Exemplo n.º 1
0
 private void Init(ReadOnlyMemorySlice <byte> data, StringsFileFormat type)
 {
     try
     {
         _type = type;
         var count     = BinaryPrimitives.ReadUInt32LittleEndian(data);
         var dataSize  = checked ((int)BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(4)));
         var indexData = data.Slice(8, checked ((int)(count * 2 * 4)));
         int loc       = 0;
         for (int i = 0; i < count; i++)
         {
             _locations.Add(
                 BinaryPrimitives.ReadUInt32LittleEndian(indexData.Slice(loc)),
                 checked ((int)BinaryPrimitives.ReadUInt32LittleEndian(indexData.Slice(loc + 4))));
             loc += 8;
         }
         _stringData = data.Slice(8 + indexData.Length, dataSize);
     }
     catch (ArgumentException)
     {
         throw new ArgumentException("Strings file had duplicate entries.");
     }
     catch (OverflowException)
     {
         throw new ArgumentException("Strings file was too big for current systems");
     }
 }
Exemplo n.º 2
0
 public BsaFileNameBlock(BsaReader bsa, long position)
 {
     Names = new Lazy <ReadOnlyMemorySlice <byte>[]>(
         mode: System.Threading.LazyThreadSafetyMode.ExecutionAndPublication,
         valueFactory: () =>
     {
         using var stream                   = bsa.GetStream();
         stream.BaseStream.Position         = position;
         ReadOnlyMemorySlice <byte> data    = stream.ReadBytes(checked ((int)bsa.TotalFileNameLength));
         ReadOnlyMemorySlice <byte>[] names = new ReadOnlyMemorySlice <byte> [bsa.FileCount];
         for (int i = 0; i < bsa.FileCount; i++)
         {
             var index = data.Span.IndexOf(default(byte));
             if (index == -1)
             {
                 throw new InvalidDataException("Did not end all of its strings in null bytes");
             }
             names[i] = data.Slice(0, index + 1);
             var str  = names[i].ReadStringTerm(bsa.HeaderType);
             data     = data.Slice(index + 1);
         }
         // Data doesn't seem to need to be fully consumed.
         // Official BSAs have overflow of zeros
         return(names);
     });
 }
Exemplo n.º 3
0
        public static IReadOnlyList <string> FactoryByCountLength <T>(
            ReadOnlyMemorySlice <byte> mem,
            BinaryOverlayFactoryPackage package,
            byte countLength,
            BinaryOverlay.SpanFactory <string> getter)
        {
            var count = countLength switch
            {
                4 => BinaryPrimitives.ReadUInt32LittleEndian(mem),
                _ => throw new NotImplementedException(),
            };

            int[] locs = new int[count];
            int   loc  = 0;

            for (int i = 0; i < count - 1; i++)
            {
                locs[i] = loc;
                var len = BinaryPrimitives.ReadUInt16LittleEndian(mem.Slice(loc));
                loc += len + 2;
            }
            return(FactoryByArray(
                       mem.Slice(countLength),
                       package,
                       getter,
                       locs));
        }
Exemplo n.º 4
0
        private T ConstructWrapper(int pos)
        {
            ReadOnlyMemorySlice <byte> slice = this._data.Slice(pos);
            var majorMeta = _package.MetaData.Constants.MajorRecord(slice);

            if (majorMeta.IsCompressed)
            {
                uint   uncompressedLength = BinaryPrimitives.ReadUInt32LittleEndian(slice.Slice(majorMeta.HeaderLength));
                byte[] buf = new byte[majorMeta.HeaderLength + checked ((int)uncompressedLength)];
                // Copy major meta bytes over
                slice.Span.Slice(0, majorMeta.HeaderLength).CopyTo(buf.AsSpan());
                // Set length bytes
                BinaryPrimitives.WriteUInt32LittleEndian(buf.AsSpan().Slice(Constants.HeaderLength), uncompressedLength);
                // Remove compression flag
                BinaryPrimitives.WriteInt32LittleEndian(buf.AsSpan().Slice(_package.MetaData.Constants.MajorConstants.FlagLocationOffset), majorMeta.MajorRecordFlags & ~Constants.CompressedFlag);
                // Copy uncompressed data over
                using (var stream = new ZlibStream(new ByteMemorySliceStream(slice.Slice(majorMeta.HeaderLength + 4)), CompressionMode.Decompress))
                {
                    stream.Read(buf, majorMeta.HeaderLength, checked ((int)uncompressedLength));
                }
                slice = new MemorySlice <byte>(buf);
            }
            return(LoquiBinaryOverlayTranslation <T> .Create(
                       stream : new OverlayStream(slice, _package),
                       package : _package,
                       recordTypeConverter : null));
        }
Exemplo n.º 5
0
        private FolderRecord[] LoadFolderRecords()
        {
            using var rdr           = GetStream();
            rdr.BaseStream.Position = _folderRecordOffset;
            var folderHeaderLength = FolderRecord.HeaderLength(HeaderType);
            ReadOnlyMemorySlice <byte> folderHeaderData = rdr.ReadBytes(checked ((int)(folderHeaderLength * _folderCount)));

            var ret = new FolderRecord[_folderCount];

            for (var idx = 0; idx < _folderCount; idx += 1)
            {
                ret[idx] = new FolderRecord(this, folderHeaderData.Slice(idx * folderHeaderLength, folderHeaderLength), idx);
            }

            // Slice off appropriate file header data per folder
            int fileCountTally = 0;

            foreach (var folder in ret)
            {
                folder.ProcessFileRecordHeadersBlock(rdr, fileCountTally);
                fileCountTally = checked ((int)(fileCountTally + folder.FileCount));
            }

            if (HasFileNames)
            {
                var filenameBlock = new FileNameBlock(this, rdr.BaseStream.Position);
                foreach (var folder in ret)
                {
                    folder.FileNameBlock = filenameBlock;
                }
            }

            return(ret);
        }
Exemplo n.º 6
0
        public static IReadOnlyList <T> FactoryByCountLength(
            ReadOnlyMemorySlice <byte> mem,
            BinaryOverlayFactoryPackage package,
            int itemLength,
            byte countLength,
            BinaryOverlay.SpanFactory <T> getter)
        {
            uint count;

            switch (countLength)
            {
            case 4:
                count = BinaryPrimitives.ReadUInt32LittleEndian(mem);
                break;

            default:
                throw new NotImplementedException();
            }
            if (((mem.Length - countLength) / itemLength) < count)
            {
                throw new ArgumentException("Item count and expected size did not match.");
            }
            return(new BinaryOverlayListByStartIndex(
                       mem.Slice(countLength, checked ((int)(count * itemLength))),
                       package,
                       getter,
                       itemLength));
        }
Exemplo n.º 7
0
        public static ReadOnlyMemorySlice <byte> ExtractGroupMemory(ReadOnlyMemorySlice <byte> span, GameConstants meta)
        {
            var groupMeta = meta.Group(span);
            var len       = groupMeta.ContentLength;

            len += (byte)meta.GroupConstants.LengthAfterLength;
            return(span.Slice(meta.GroupConstants.TypeAndLengthLength, checked ((int)len)));
        }
Exemplo n.º 8
0
        public static ReadOnlyMemorySlice <byte> ExtractRecordMemory(ReadOnlyMemorySlice <byte> span, GameConstants meta)
        {
            var majorMeta = meta.MajorRecord(span);
            var len       = majorMeta.ContentLength;

            len += (byte)meta.MajorConstants.LengthAfterLength;
            return(span.Slice(meta.MajorConstants.TypeAndLengthLength, checked ((int)len)));
        }
Exemplo n.º 9
0
 public static IReadOnlyList <T> FactoryByLazyParse <T>(
     ReadOnlyMemorySlice <byte> mem,
     BinaryOverlayFactoryPackage package,
     byte countLength,
     BinaryOverlay.Factory <T> getter)
 {
     return(FactoryByLazyParse(mem.Slice(countLength), package, getter));
 }
Exemplo n.º 10
0
 public static string ReadStringLenTerm(this ReadOnlyMemorySlice <byte> bytes, VersionType version)
 {
     if (bytes.Length <= 1)
     {
         return(string.Empty);
     }
     return(GetEncoding(version).GetString(bytes.Slice(1, bytes[0])));
 }
Exemplo n.º 11
0
 public static PathGridPointBinaryOverlay Factory(
     ReadOnlyMemorySlice <byte> stream,
     BinaryOverlayFactoryPackage package)
 {
     return(new PathGridPointBinaryOverlay(
                bytes: stream.Slice(0, 16),
                package: package));
 }
Exemplo n.º 12
0
 public T this[int index]
 {
     get
     {
         var startIndex = index * _itemLength;
         return(_getter(_mem.Slice(startIndex, _itemLength), _package));
     }
 }
Exemplo n.º 13
0
 public T this[int index]
 {
     get
     {
         var startIndex = index * this._totalItemLength;
         var subMeta    = _package.MetaData.Constants.Subrecord(_mem.Slice(startIndex));
         if (!this._recordTypes.Contains(subMeta.RecordType))
         {
             throw new ArgumentException($"Unexpected record type: {subMeta.RecordType}");
         }
         if (subMeta.ContentLength != this._itemLength)
         {
             throw new ArgumentException($"Unexpected record length: {subMeta.ContentLength} != {this._itemLength}");
         }
         return(_getter(_mem.Slice(startIndex + _package.MetaData.Constants.SubConstants.HeaderLength, _itemLength), _package));
     }
 }
Exemplo n.º 14
0
        internal static IEnumerable <SubrecordPinFrame> EnumerateSubrecords(ReadOnlyMemorySlice <byte> span, GameConstants meta, int loc)
        {
            while (loc < span.Length)
            {
                var subHeader = new SubrecordPinFrame(meta, span.Slice(loc), loc);
                yield return(subHeader);

                loc += subHeader.TotalLength;
            }
        }
Exemplo n.º 15
0
        internal static IEnumerable <SubrecordPinFrame> EnumerateSubrecords(ReadOnlyMemorySlice <byte> span, GameConstants meta, int loc, ICollection <RecordType> lengthOverflowTypes)
        {
            while (loc < span.Length)
            {
                var subFrame = new SubrecordPinFrame(meta, span.Slice(loc), loc);
                if (lengthOverflowTypes.Contains(subFrame.RecordType))
                { // Length overflow record
                    var nextLen = subFrame.AsUInt32();
                    loc += subFrame.TotalLength;
                    var nextSpan  = span.Slice(loc, checked ((int)(nextLen + meta.SubConstants.HeaderLength)));
                    var subHeader = new SubrecordHeader(meta, nextSpan);
                    yield return(SubrecordPinFrame.FactoryNoTrim(subHeader, nextSpan, loc));

                    loc += checked ((int)(subHeader.HeaderLength + nextLen));
                    continue;
                }
                yield return(subFrame);

                loc += subFrame.TotalLength;
            }
        }
Exemplo n.º 16
0
 public INavmeshTriangleGetter this[int index]
 {
     get
     {
         var triangleLoc = _trianglesStartPos + (index * 16);
         var triangle    = NavmeshTriangleBinaryOverlay.NavmeshTriangleFactory(
             _data.Slice(triangleLoc),
             _package);
         triangle.IsCover = _isCover[index];
         return(triangle);
     }
 }
Exemplo n.º 17
0
 public static ReadOnlyMemorySlice <T> EnumSliceFromFixedSize <T>(
     ReadOnlyMemorySlice <byte> mem,
     int amount,
     byte enumLength)
     where T : struct, Enum
 {
     T[] ret = new T[amount];
     for (int i = 0; i < amount; i++)
     {
         ret[i] = EnumExt.Parse <T>(BinaryPrimitives.ReadInt32LittleEndian(mem.Slice(i * enumLength)), default(T));
     }
     return(ret);
 }
Exemplo n.º 18
0
        /// <summary>
        /// Parses span data and enumerates pairs of record type -> locations
        ///
        /// It is assumed the span contains only subrecords
        /// </summary>
        /// <param name="span">Bytes containing subrecords</param>
        /// <param name="meta">Metadata to use in subrecord parsing</param>
        /// <returns>Enumerable of KeyValue pairs of encountered RecordTypes and their locations relative to the input span</returns>
        public static IEnumerable <KeyValuePair <RecordType, int> > EnumerateSubrecords(ReadOnlyMemorySlice <byte> span, GameConstants meta)
        {
            int loc = 0;

            while (span.Length > loc)
            {
                var subMeta = meta.Subrecord(span.Slice(loc));
                var len     = subMeta.TotalLength;
                yield return(new KeyValuePair <RecordType, int>(subMeta.RecordType, loc));

                loc += len;
            }
        }
Exemplo n.º 19
0
        public static ReadOnlyMemorySlice <byte> DecompressSpan(ReadOnlyMemorySlice <byte> slice, GameConstants meta)
        {
            var majorMeta = meta.MajorRecord(slice);

            if (majorMeta.IsCompressed)
            {
                uint   uncompressedLength = BinaryPrimitives.ReadUInt32LittleEndian(slice.Slice(majorMeta.HeaderLength));
                byte[] buf = new byte[majorMeta.HeaderLength + checked ((int)uncompressedLength)];
                // Copy major meta bytes over
                slice.Span.Slice(0, majorMeta.HeaderLength).CopyTo(buf.AsSpan());
                // Set length bytes
                BinaryPrimitives.WriteUInt32LittleEndian(buf.AsSpan().Slice(Constants.HeaderLength), uncompressedLength);
                // Remove compression flag
                BinaryPrimitives.WriteInt32LittleEndian(buf.AsSpan().Slice(meta.MajorConstants.FlagLocationOffset), majorMeta.MajorRecordFlags & ~Constants.CompressedFlag);
                // Copy uncompressed data over
                using (var stream = new ZlibStream(new ByteMemorySliceStream(slice.Slice(majorMeta.HeaderLength + 4)), CompressionMode.Decompress))
                {
                    stream.Read(buf, majorMeta.HeaderLength, checked ((int)uncompressedLength));
                }
                slice = new MemorySlice <byte>(buf);
            }
            return(slice);
        }
Exemplo n.º 20
0
 public static ReadOnlyMemorySlice <T> LoquiSliceFromFixedSize <T>(
     ReadOnlyMemorySlice <byte> mem,
     int amount,
     int length,
     BinaryOverlayFactoryPackage package,
     RecordTypeConverter?recordTypeConverter,
     BinaryOverlay.ConverterFactory <T> getter)
 {
     T[] ret = new T[amount];
     for (int i = 0; i < amount; i++)
     {
         ret[i] = getter(new OverlayStream(mem.Slice(i * length), package), package, recordTypeConverter);
     }
     return(ret);
 }
Exemplo n.º 21
0
        public static IReadOnlyList <T> FactoryByCountLength <T>(
            ReadOnlyMemorySlice <byte> mem,
            BinaryOverlayFactoryPackage package,
            int itemLength,
            byte countLength,
            PluginBinaryOverlay.SpanFactory <T> getter)
        {
            var count = countLength switch
            {
                4 => BinaryPrimitives.ReadUInt32LittleEndian(mem),
                _ => throw new NotImplementedException(),
            };

            if (((mem.Length - countLength) / itemLength) < count)
            {
                throw new ArgumentException("Item count and expected size did not match.");
            }
            return(new BinaryOverlayListByStartIndex <T>(
                       mem.Slice(countLength, checked ((int)(count * itemLength))),
                       package,
                       getter,
                       itemLength));
        }
Exemplo n.º 22
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="meta">Game metadata to use as reference for alignment</param>
 /// <param name="span">Span to overlay on, aligned to the start of the Sub Record's header</param>
 public SubrecordHeader(GameConstants meta, ReadOnlyMemorySlice <byte> span)
 {
     this.Meta       = meta;
     this.HeaderData = span.Slice(0, meta.SubConstants.HeaderLength);
 }
Exemplo n.º 23
0
 /// <summary>
 /// Factory
 /// </summary>
 /// <param name="header">Existing SubrecordHeader struct</param>
 /// <param name="span">Span to overlay on, aligned to the start of the header</param>
 public static SubrecordFrame Factory(SubrecordHeader header, ReadOnlyMemorySlice <byte> span)
 {
     return(new SubrecordFrame(header, span.Slice(0, header.TotalLength)));
 }
Exemplo n.º 24
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="meta">Game metadata to use as reference for alignment</param>
 /// <param name="span">Span to overlay on, aligned to the start of the header</param>
 public SubrecordFrame(GameConstants meta, ReadOnlyMemorySlice <byte> span)
 {
     Header = meta.Subrecord(span);
     HeaderAndContentData = span.Slice(0, Header.TotalLength);
 }
Exemplo n.º 25
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="meta">Game metadata to use as reference for alignment</param>
 /// <param name="span">Span to overlay on, aligned to the start of the Group's header</param>
 public GroupHeader(GameConstants meta, ReadOnlyMemorySlice <byte> span)
 {
     this.Meta       = meta;
     this.HeaderData = span.Slice(0, meta.GroupConstants.HeaderLength);
 }
Exemplo n.º 26
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="header">Existing GroupHeader struct</param>
 /// <param name="span">Span to overlay on, aligned to the start of the Group's header</param>
 public GroupFrame(GroupHeader header, ReadOnlyMemorySlice <byte> span)
 {
     this._header = header;
     this.HeaderAndContentData = span.Slice(0, checked ((int)this._header.TotalLength));
 }
Exemplo n.º 27
0
 public T this[int index] => _getter(_mem.Slice(_locations[index]), _package, _recordTypeConverter);
Exemplo n.º 28
0
 public T this[int index] => _getter(_mem.Slice(_locations[index]), _package);
Exemplo n.º 29
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="constants">Record constants to use as reference for alignment</param>
 /// <param name="span">Span to overlay on, aligned to the start of the header</param>
 public VariableHeader(RecordHeaderConstants constants, ReadOnlyMemorySlice <byte> span)
 {
     Constants = constants;
     Span      = span.Slice(0, constants.HeaderLength);
 }
Exemplo n.º 30
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="meta">Game metadata to use as reference for alignment</param>
 /// <param name="span">Span to overlay on, aligned to the start of the header</param>
 public GroupFrame(GameConstants meta, ReadOnlyMemorySlice <byte> span)
 {
     this._header = meta.Group(span);
     this.HeaderAndContentData = span.Slice(0, checked ((int)this._header.TotalLength));
 }