Exemple #1
0
        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);
            }
        }
Exemple #2
0
 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);
     }
 }
Exemple #3
0
        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);
        }
Exemple #4
0
        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;
            }
        }
Exemple #5
0
 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);
 });
Exemple #6
0
 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;
         }
     }
 }
Exemple #7
0
 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()));
 });
Exemple #8
0
 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);
 }
Exemple #9
0
        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);
        }
Exemple #10
0
        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);
        }