void Read(ProxySink.DataInfo info = null) { Clear(); var rootHeader = new Header(null, _r, Format); if ((Format == GameFormat.TES3 && rootHeader.Type != "TES3") || (Format != GameFormat.TES3 && rootHeader.Type != "TES4")) { throw new FormatException($"{FilePath} record header {rootHeader.Type} is not valid for this {Format}"); } var rootRecord = rootHeader.CreateRecord(rootHeader.Position, RecordLevel); rootRecord.Read(_r, FilePath, Format); // morrowind hack if (Format == GameFormat.TES3) { var header = new Header { Type = "ALL_", Label = string.Empty, DataSize = (uint)(_r.BaseStream.Length - _r.Position), Position = _r.Position }; ReadTES3(header, true, info); return; } // read groups var endPosition = _r.BaseStream.Length; while (_r.Position < endPosition) { var header = new Header(this, _r, Format); if (header.Type != "GRUP") { throw new InvalidOperationException($"{header.Type} not GRUP"); } ReadGRUP(header, false, info); } }
public List <Record> Load(bool loadAll = false, ProxySink.DataInfo info = null) { if (_headerSkip == Headers.Count) { return(Records); } if (_r == null && Headers.Count == 1) { var bytes = Task.Run(async() => await LoadDataLabelAsync(FilePath ?? ToPath(null))).Result(); _r = new BinaryFileReader(new MemoryStream(bytes)); Headers.First.Value.DataSize = (uint)bytes.Length; } lock (_r ?? throw new InvalidOperationException("Should not reach here")) { if (_headerSkip == Headers.Count) { return(Records); } foreach (var header in Headers.Skip(_headerSkip)) { ReadGroup(header, loadAll, info); } _headerSkip = Headers.Count; return(Records); } }
protected RecordGroup ReadGRUP(Header header, bool loadAll, ProxySink.DataInfo info) { var headerBytes = _r.ReadAbsoluteBytes(header.HeaderPosition, (int)(header.Position - header.HeaderPosition)); var nextPosition = _r.Position + header.DataSize; var label = header.Label; info?.AddGroup(label, headerBytes); if (GroupByLabel == null) { GroupByLabel = new Dictionary <string, RecordGroup>(); } if (!GroupByLabel.TryGetValue(label, out var group)) { GroupByLabel.Add(label, group = new RecordGroup(_proxySink, _r, FilePath, Format, RecordLevel, Depth + 1)); } else { group = new RecordGroup(_proxySink, _r, FilePath, Format, RecordLevel, Depth + 1) { Next = group } }; group.AddHeader(header, info); _r.Position = nextPosition; if (loadAll || info != null) { group.Load(loadAll, info); } //Log($"Grup: {string.Join("/", GetHeaderPath(new List<string>(), parentHeader).ToArray())} {parentHeader.GroupType}"); return(group); }
void ReadGroup(Header parentHeader, bool loadAll, ProxySink.DataInfo info) { _r.Position = parentHeader.Position; var endPosition = parentHeader.Position + parentHeader.DataSize; while (_r.Position < endPosition) { var header = new Header(this, _r, Format); // STREAMING READ if (info != null && (info.Data != null || Format != GameFormat.TES3)) { if (header.Type == "GRUP" && Depth < MaxDepthStreamed) { if (info.Data != null) { goto next; } info.EnterGroup(); ReadGRUP(header, loadAll, info); info.LeaveGroup(); continue; } else { info.Data?.Invoke(_r.ReadAbsoluteBytes(header.HeaderPosition, (int)(header.Position - header.HeaderPosition) + (int)header.DataSize)); } goto next; } // LOCAL READ if (header.Type == "GRUP") { ReadGRUP(header, loadAll, null); continue; } // HACK to limit cells loading if (header.Type == "CELL" && _cellsLoaded > int.MaxValue) { goto next; } var record = header.CreateRecord(_r.Position, RecordLevel); if (record == null) { goto next; } ReadRecord(record, header.Compressed); Records.Add(record); if (header.Type == "CELL") { _cellsLoaded++; } continue; // NEXT next: _r.Position += header.DataSize; } }
void ReadTES3Transform(RecordGroup group, ProxySink.DataInfo info) => GroupByLabel = group.Records.GroupBy(x => x.Header.Type) .ToDictionary(x => x.Key, x => { var s = new RecordGroup(_proxySink, _r, FilePath, Format, RecordLevel, Depth + 1) { Records = x.ToList() }; s.AddHeader(new Header { Label = x.Key }, info); return(s); });
public void AddHeader(Header header, ProxySink.DataInfo info) { //Log($"Read: {header.Label}"); Headers.AddLast(header); if (info == null && header.GroupType == Header.HeaderGroupType.Top) { switch (header.Label) { //case "DIAL": case "CELL": case "WRLD": Load(); break; } } }
public Task <byte[]> LoadDataLabelAsync(string filePath) => _proxySink.LoadDataLabelAsync(filePath, () => { var labels = FromPath(filePath); var group = Format != GameFormat.TES3 ? labels.Aggregate(this, (a, b) => a.GroupByLabel[b]) : this; var ms = new MemoryStream(); var info = new ProxySink.DataInfo { Data = data => ms.Write(data, 0, data.Length) }; foreach (var header in group.Headers) { ReadGroup(header, false, info); } ms.Position = 0; return(Task.FromResult(ms.ToArray())); });
protected RecordGroup ReadTES3(Header header, bool loadAll, ProxySink.DataInfo info) { using (var ms = new MemoryStream()) using (var w = new BinaryFileWriter(ms)) { header.Write(w, Format); ms.Position = 0; var headerBytes = ms.ToArray(); info?.AddGroup(header.Label, headerBytes); } //var group = new RecordGroup(_proxySink, _r, FilePath, Format, RecordLevel, Depth + 1); AddHeader(header, info); if (loadAll || info != null) { Load(loadAll, info); } ReadTES3Transform(this, info); return(this); }
public void SinkDataContains(string path) { var bytes = _proxySink.GetDataContains(() => { var info = new ProxySink.DataInfo(); Read(info); return(info.ToArray()); }); if (_proxySink is ProxySinkServer) { return; } // write data if (path != null) { File.WriteAllBytes(Path.Combine(path, ".set"), bytes); } ReadGRUP(new ProxySink.DataInfo(bytes), path); }
protected RecordGroup ReadGRUP(ProxySink.DataInfo info, string path) { var stack = new Stack <RecordGroup>(); if (GroupByLabel == null) { GroupByLabel = new Dictionary <string, RecordGroup>(); } var groupByLabel = GroupByLabel; var r = new BinaryFileReader(new MemoryStream()); var depth = 0; RecordGroup group = this; info.Decoder( group: (label, headerData) => { var filePath = ToPath(stack.Reverse().Select(x => x.Label).Concat(new[] { label }).ToArray()); // write data if (path != null) { var bytes = LoadDataLabelAsync(filePath).Result(); File.WriteAllBytes(Path.Combine(path, filePath), bytes); return; } if (Format != GameFormat.TES3) { if (!groupByLabel.TryGetValue(label, out group)) { groupByLabel.Add(label, group = new RecordGroup(_proxySink, null, filePath, Format, RecordLevel, depth)); } else { group = new RecordGroup(_proxySink, null, filePath, Format, RecordLevel, depth) { Next = group } } } ; r.Position = 0; r.BaseStream.Write(headerData, 0, headerData.Length); r.Position = 0; var header = new Header(group, r, Format) { DataSize = 0, Position = 0 }; group.AddHeader(header, null); }, enterGroup: () => { stack.Push(group); if (path == null) { groupByLabel = group.GroupByLabel = new Dictionary <string, RecordGroup>(); } depth++; }, leaveGroup: () => { group = stack.Pop(); if (path == null) { groupByLabel = group.GroupByLabel; } depth--; } ); if (Format == GameFormat.TES3) { group.Load(true, info); ReadTES3Transform(group, info); } return(this); }