示例#1
0
        private static void Decompress_WithState(ReadOnlySpan <byte> input, Span <byte> output)
        {
            BrotliDecoder decoder = default;

            while (!input.IsEmpty && !output.IsEmpty)
            {
                decoder.Decompress(input, output, out int bytesConsumed, out int written);
                input  = input.Slice(bytesConsumed);
                output = output.Slice(written);
            }
        }
示例#2
0
        public void ReadFully(string testFile)
        {
            byte[] correctUncompressedBytes = File.ReadAllBytes(testFile);
            byte[] compressedBytes          = File.ReadAllBytes(CompressedTestFile(testFile));
            byte[] actualUncompressedBytes  = new byte[correctUncompressedBytes.Length + 10000];
            ReadOnlySpan <byte> source      = new ReadOnlySpan <byte>(compressedBytes);
            Span <byte>         destination = new Span <byte>(actualUncompressedBytes);

            Assert.True(BrotliDecoder.TryDecompress(source, destination, out int bytesWritten), "TryDecompress did not complete successfully");
            Assert.Equal(correctUncompressedBytes.Length, bytesWritten);
            Assert.Equal <byte>(correctUncompressedBytes, actualUncompressedBytes.AsSpan(0, correctUncompressedBytes.Length).ToArray());
        }
示例#3
0
        public void WriteFully(string testFile)
        {
            byte[] correctUncompressedBytes = File.ReadAllBytes(testFile);
            byte[] compressedBytes          = new byte[BrotliEncoder.GetMaxCompressedLength(correctUncompressedBytes.Length)];
            byte[] actualUncompressedBytes  = new byte[BrotliEncoder.GetMaxCompressedLength(correctUncompressedBytes.Length)];

            Span <byte> destination = new Span <byte>(compressedBytes);

            Assert.True(BrotliEncoder.TryCompress(correctUncompressedBytes, destination, out int bytesWritten));
            Assert.True(BrotliDecoder.TryDecompress(destination, actualUncompressedBytes, out bytesWritten));
            Assert.Equal(correctUncompressedBytes.Length, bytesWritten);

            Assert.Equal <byte>(correctUncompressedBytes, actualUncompressedBytes.AsSpan(0, correctUncompressedBytes.Length).ToArray());
        }
示例#4
0
        public void Decompress_WithEmptySource()
        {
            string testFile = UncompressedTestFile();

            byte[] sourceBytes              = new byte[0];
            byte[] destinationBytes         = new byte[100000];
            ReadOnlySpan <byte> source      = new ReadOnlySpan <byte>(sourceBytes);
            Span <byte>         destination = new Span <byte>(destinationBytes);

            Assert.False(BrotliDecoder.TryDecompress(source, destination, out int bytesWritten), "TryDecompress completed successfully but should have failed due to too short of a source array");
            Assert.Equal(0, bytesWritten);

            BrotliDecoder decoder;
            var           result = decoder.Decompress(source, destination, out int bytesConsumed, out bytesWritten);

            Assert.Equal(0, bytesWritten);
            Assert.Equal(0, bytesConsumed);
            Assert.Equal(OperationStatus.NeedMoreData, result);
        }
示例#5
0
        public void Decompress_WithEmptyDestination()
        {
            string testFile = UncompressedTestFile();

            byte[] sourceBytes              = File.ReadAllBytes(CompressedTestFile(testFile));
            byte[] destinationBytes         = new byte[0];
            ReadOnlySpan <byte> source      = new ReadOnlySpan <byte>(sourceBytes);
            Span <byte>         destination = new Span <byte>(destinationBytes);

            Assert.False(BrotliDecoder.TryDecompress(source, destination, out int bytesWritten), "TryDecompress completed successfully but should have failed due to too short of a destination array");
            Assert.Equal(0, bytesWritten);

            BrotliDecoder decoder = default;
            var           result  = decoder.Decompress(source, destination, out int bytesConsumed, out bytesWritten);

            Assert.Equal(0, bytesWritten);
            Assert.Equal(0, bytesConsumed);
            Assert.Equal(OperationStatus.DestinationTooSmall, result);
        }
        public static bool WriteBlockAndPreamble(TrackingPipeWriter writer, NettraceBlock block)
        {
            if (block.Type.Name != KnownTypeNames.EventBlockCompressed && block.Type.Name != KnownTypeNames.StackBlockCompressed)
            {
                return(false);
            }

            var padding      = BlockHelpers.GetPadding(writer, block);
            var prefixLength = padding + sizeof(int);

            using var decoder = new BrotliDecoder();

            var source = ArrayPool <byte> .Shared.Rent((int)block.BlockBody.Length);

            block.BlockBody.CopyTo(source);
            var           written = 0;
            Memory <byte> memory;

            try
            {
                var length = prefixLength + (int)block.BlockBody.Length;
                memory = writer.GetMemory(length);
                while (!BrotliDecoder.TryDecompress(source.AsSpan(0, (int)block.BlockBody.Length), memory.Slice(prefixLength).Span, out written))
                {
                    length = memory.Length * 2;
                    memory = writer.GetMemory(length);
                }
            }
            finally
            {
                ArrayPool <byte> .Shared.Return(source);
            }

            // Write size
            BitConverter.TryWriteBytes(memory.Span, written);
            // clear padding bits
            memory.Slice(sizeof(int), padding).Span.Clear();
            writer.Advance(written + prefixLength);

            return(true);
        }
示例#7
0
 public bool TryDecompress(byte[] source, int sourceOffset, int sourceLength, byte[] destination, int destinationOffset, int destinationLength, out int written)
 {
     return(BrotliDecoder.TryDecompress(new ReadOnlySpan <byte>(source, sourceOffset, sourceLength),
                                        new Span <byte>(destination, destinationOffset, destinationLength), out written));
 }
示例#8
0
 private static void Decompress_WithoutState(ReadOnlySpan <byte> input, Span <byte> output)
 {
     BrotliDecoder.TryDecompress(input, output, out int bytesWritten);
 }
示例#9
0
        internal Usmap(IGenericReader fileReader, UsmapOptions options)
        {
            var magic = fileReader.Read <ushort>();

            if (magic != MAGIC)
            {
                throw new FileLoadException("Invalid .usmap magic constant");
            }

            var version = fileReader.Read <EUsmapVersion>();

            if (version != EUsmapVersion.LATEST)
            {
                throw new FileLoadException($"Invalid .usmap version: {(int)version}");
            }

            var compMethod = fileReader.Read <EUsmapCompressionMethod>();
            var compSize   = fileReader.Read <uint>();
            var decompSize = fileReader.Read <uint>();

            if (fileReader.Size - fileReader.Position < compSize)
            {
                throw new FileLoadException("There is not enough data in the .usmap file");
            }

            options ??= new UsmapOptions();
            IGenericReader reader;

            switch (compMethod)
            {
            case EUsmapCompressionMethod.None:
            {
                if (compSize != decompSize)
                {
                    throw new FileLoadException("No .usmap compression: Compression size must be equal to decompression size");
                }

                reader = fileReader;
                break;
            }

            case EUsmapCompressionMethod.Oodle:
            {
                if (options.OodlePath == null)
                {
                    throw new FileLoadException("Undefined oodle library path");
                }

                if (!File.Exists(options.OodlePath))
                {
                    throw new FileLoadException($"Could not find oodle library at \"{options.OodlePath}\"");
                }

                var compData = fileReader.ReadBytes((int)compSize);
                fileReader.Dispose();
                var data = new byte[decompSize];
                using var decompressor = new OodleCompressor(options.OodlePath);

                unsafe
                {
                    var result = decompressor.Decompress(compData, compSize, data, decompSize, OodleLZ_FuzzSafe.No, OodleLZ_CheckCRC.No, OodleLZ_Verbosity.None, 0L, 0L, 0L, 0L, 0L, 0L, OodleLZ_Decode_ThreadPhase.Unthreaded);

                    if (result != decompSize)
                    {
                        throw new FileLoadException($"Invalid oodle .usmap decompress result: {result} / {decompSize}");
                    }
                }

                reader = new GenericBufferReader(data);
                break;
            }

            case EUsmapCompressionMethod.Brotli:
            {
                var compData = fileReader.ReadBytes((int)compSize);
                fileReader.Dispose();
                var data = new byte[decompSize];
                using var decoder = new BrotliDecoder();
                var result = decoder.Decompress(compData, data, out var bytesConsumed, out var bytesWritten);

                if (result != OperationStatus.Done)
                {
                    throw new FileLoadException($"Invalid brotli .usmap decompress result: {result} | {bytesWritten} / {decompSize} | {bytesConsumed} / {compSize}");
                }

                reader = new GenericBufferReader(data);
                break;
            }

            default:
                throw new FileLoadException($"Unknown .usmap compression method: {(int)compMethod}");
            }

            string[] names;

            {
                var size = reader.Read <uint>();
                names = new string[size];

                for (var i = 0; i < size; ++i)
                {
                    var nameSize = reader.ReadByte();
                    var name     = reader.ReadString(nameSize, Encoding.UTF8);
                    names[i] = name;
                }
            }

            {
                var size = reader.Read <uint>();
                Enums = new UsmapEnum[size];

                for (var i = 0; i < size; ++i)
                {
                    var idx           = reader.Read <uint>();
                    var enumNamesSize = reader.ReadByte();
                    var enumNames     = new string[enumNamesSize];

                    for (var j = 0; j < enumNamesSize; ++j)
                    {
                        var nameIdx = reader.Read <uint>();
                        enumNames[j] = names[nameIdx];
                    }

                    Enums[i] = new UsmapEnum(names[idx], enumNames);
                }
            }

            {
                var size = reader.Read <uint>();
                Schemas = new UsmapSchema[size];

                for (var i = 0; i < size; ++i)
                {
                    var idx       = reader.Read <uint>();
                    var superIdx  = reader.Read <uint>();
                    var propCount = reader.Read <ushort>();

                    var serializablePropCount = reader.Read <ushort>();
                    var props = new UsmapProperty[serializablePropCount];

                    for (var j = 0; j < serializablePropCount; ++j)
                    {
                        var schemaIdx = reader.Read <ushort>();
                        var arraySize = reader.Read <byte>();
                        var nameIdx   = reader.Read <uint>();
                        var data      = UsmapPropertyData.Deserialize(reader, names);
                        props[j] = new UsmapProperty(names[nameIdx], schemaIdx, arraySize, data);
                    }

                    Schemas[i] = new UsmapSchema(names[idx], superIdx == uint.MaxValue ? null : names[superIdx], propCount, props);
                }
            }

            Names = options.SaveNames ? names : null;

            reader.Dispose();
        }