Пример #1
0
        public override void Read(EndianStream stream)
        {
            base.Read(stream);

            ParsedForm.Read(stream);
            Name = ParsedForm.Name;

            m_platforms = stream.ReadEnum32Array((t) => (GPUPlatform)t);
            uint[] offsets             = stream.ReadUInt32Array();
            uint[] compressedLengths   = stream.ReadUInt32Array();
            uint[] decompressedLengths = stream.ReadUInt32Array();
            byte[] compressedBlob      = stream.ReadByteArray();
            stream.AlignStream(AlignType.Align4);

            m_subProgramBlobs = new ShaderSubProgramBlob[m_platforms.Length];
            using (MemoryStream memStream = new MemoryStream(compressedBlob))
            {
                for (int i = 0; i < m_platforms.Length; i++)
                {
                    uint offset             = offsets[i];
                    uint compressedLength   = compressedLengths[i];
                    uint decompressedLength = decompressedLengths[i];

                    memStream.Position = offset;
                    byte[] decompressedBuffer = new byte[decompressedLength];
                    using (Lz4Stream lz4Stream = new Lz4Stream(memStream, (int)compressedLength))
                    {
                        int read = lz4Stream.Read(decompressedBuffer, 0, decompressedBuffer.Length);
                        if (read != decompressedLength)
                        {
                            throw new Exception($"Can't properly decode shader blob. Read {read} but expected {decompressedLength}");
                        }
                    }

                    using (MemoryStream blobMem = new MemoryStream(decompressedBuffer))
                    {
                        using (EndianStream blobStream = new EndianStream(blobMem))
                        {
                            ShaderSubProgramBlob blob = new ShaderSubProgramBlob(AssetsFile);
                            blob.Read(blobStream);
                            m_subProgramBlobs[i] = blob;
                        }
                    }
                }
            }

            m_dependencies = stream.ReadArray(() => new PPtr <SShader>(AssetsFile));
            ShaderIsBaked  = stream.ReadBoolean();
            stream.AlignStream(AlignType.Align4);
        }
Пример #2
0
        public override void Read(EndianStream stream)
        {
            base.Read(stream);

            if (IsSerialized)
            {
                throw new NotSupportedException("Use SShader for serialized shaders");
            }

            if (IsEncoded)
            {
                uint decompressedSize = stream.ReadUInt32();
                int  comressedSize    = stream.ReadInt32();

                byte[] subProgramBlob = new byte[comressedSize];
                stream.Read(subProgramBlob, 0, comressedSize);
                stream.AlignStream(AlignType.Align4);

                if (comressedSize > 0 && decompressedSize > 0)
                {
                    byte[] decompressedBuffer = new byte[decompressedSize];
                    using (MemoryStream memStream = new MemoryStream(subProgramBlob))
                    {
                        using (Lz4Stream lz4Stream = new Lz4Stream(memStream))
                        {
                            int read = lz4Stream.Read(decompressedBuffer, 0, (int)decompressedSize);
                            if (read != decompressedSize)
                            {
                                throw new Exception($"Can't properly decode sub porgram prob. Read {read} but expected decompressedSize");
                            }
                        }
                    }

                    using (MemoryStream memStream = new MemoryStream(decompressedBuffer))
                    {
                        using (EndianStream blobStream = new EndianStream(memStream))
                        {
                            SubProgramBlob.Read(blobStream);
                        }
                    }
                }
            }

            m_dependencies = stream.ReadArray(() => new PPtr <Shader>(AssetsFile));
            ShaderIsBaked  = stream.ReadBoolean();
            stream.AlignStream(AlignType.Align4);
        }
Пример #3
0
        private void Read530Blocks(EndianStream stream, bool isClosable, BlockInfo[] blockInfos, BundleMetadata metadata)
        {
            // Special case. If bundle has no compressed blocks then pass it as is
            if (blockInfos.All(t => t.Flags.GetCompression() == BundleCompressType.None))
            {
                Metadatas = new BundleMetadata[] { metadata };
                return;
            }

            long   dataPosisition   = stream.BaseStream.Position;
            long   decompressedSize = blockInfos.Sum(t => t.DecompressedSize);
            Stream bufferStream;

            if (decompressedSize > int.MaxValue)
            {
                string tempFile = Path.GetTempFileName();
                bufferStream = new FileStream(tempFile, FileMode.Open, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose);
            }
            else
            {
                bufferStream = new MemoryStream((int)decompressedSize);
            }

            foreach (BlockInfo blockInfo in blockInfos)
            {
                BundleCompressType compressType = blockInfo.Flags.GetCompression();
                switch (compressType)
                {
                case BundleCompressType.None:
                    stream.BaseStream.CopyStream(bufferStream, blockInfo.DecompressedSize);
                    break;

                case BundleCompressType.LZMA:
                    SevenZipHelper.DecompressLZMAStream(stream.BaseStream, blockInfo.CompressedSize, bufferStream, blockInfo.DecompressedSize);
                    break;

                case BundleCompressType.LZ4:
                case BundleCompressType.LZ4HZ:
                    using (Lz4Stream lzStream = new Lz4Stream(stream.BaseStream, blockInfo.CompressedSize))
                    {
                        long read = lzStream.Read(bufferStream, blockInfo.DecompressedSize);
                        if (read != blockInfo.DecompressedSize)
                        {
                            throw new Exception($"Read {read} but expected {blockInfo.CompressedSize}");
                        }
                    }
                    break;

                default:
                    throw new NotImplementedException($"Bundle compression '{compressType}' isn't supported");
                }
            }

            if (isClosable)
            {
                stream.Dispose();
            }

            BundleFileEntry[] entries = new BundleFileEntry[metadata.Entries.Count];
            for (int i = 0; i < metadata.Entries.Count; i++)
            {
                BundleFileEntry bundleEntry = metadata.Entries[i];
                string          name        = bundleEntry.Name;
                long            offset      = bundleEntry.Offset - dataPosisition;
                long            size        = bundleEntry.Size;
                BundleFileEntry streamEntry = new BundleFileEntry(bufferStream, m_filePath, name, offset, size, true);
                entries[i] = streamEntry;
            }
            BundleMetadata streamMetadata = new BundleMetadata(bufferStream, m_filePath, false, entries);

            Metadatas = new BundleMetadata[] { streamMetadata };
        }
Пример #4
0
        private void Read530Metadata(EndianStream stream, bool isClosable, long basePosition)
        {
            long dataPosition = stream.BaseStream.Position;

            if (Header.Flags.IsMetadataAtTheEnd())
            {
                stream.BaseStream.Position = basePosition + Header.BundleSize - Header.MetadataCompressedSize;
            }
            else
            {
                dataPosition += Header.MetadataCompressedSize;
            }

            BlockInfo[]        blockInfos;
            BundleMetadata     metadata;
            BundleCompressType metaCompress = Header.Flags.GetCompression();

            switch (metaCompress)
            {
            case BundleCompressType.None:
            {
                long metaPosition = stream.BaseStream.Position;

                // unknown 0x10
                stream.BaseStream.Position += 0x10;
                blockInfos = stream.ReadArray <BlockInfo>();
                metadata   = new BundleMetadata(stream.BaseStream, m_filePath, isClosable);
                metadata.Read530(stream, dataPosition);

                if (stream.BaseStream.Position != metaPosition + Header.MetadataDecompressedSize)
                {
                    throw new Exception($"Read {stream.BaseStream.Position - metaPosition} but expected {Header.MetadataDecompressedSize}");
                }
                break;
            }

            case BundleCompressType.LZMA:
            {
                using (MemoryStream memStream = new MemoryStream(Header.MetadataDecompressedSize))
                {
                    SevenZipHelper.DecompressLZMASizeStream(stream.BaseStream, Header.MetadataCompressedSize, memStream);
                    memStream.Position = 0;

                    using (EndianStream metadataStream = new EndianStream(memStream, EndianType.BigEndian))
                    {
                        // unknown 0x10
                        metadataStream.BaseStream.Position += 0x10;
                        blockInfos = metadataStream.ReadArray <BlockInfo>();
                        metadata   = new BundleMetadata(stream.BaseStream, m_filePath, isClosable);
                        metadata.Read530(metadataStream, dataPosition);

                        if (memStream.Position != memStream.Length)
                        {
                            throw new Exception($"Read {memStream.Position} but expected {memStream.Length}");
                        }
                    }
                }
                break;
            }

            case BundleCompressType.LZ4:
            case BundleCompressType.LZ4HZ:
            {
                using (MemoryStream memStream = new MemoryStream(Header.MetadataDecompressedSize))
                {
                    using (Lz4Stream lzStream = new Lz4Stream(stream.BaseStream, Header.MetadataCompressedSize))
                    {
                        long read = lzStream.Read(memStream, Header.MetadataDecompressedSize);
                        memStream.Position = 0;

                        if (read != Header.MetadataDecompressedSize)
                        {
                            throw new Exception($"Read {read} but expected {Header.MetadataDecompressedSize}");
                        }
                    }

                    using (EndianStream metadataStream = new EndianStream(memStream, EndianType.BigEndian))
                    {
                        // unknown 0x10
                        metadataStream.BaseStream.Position += 0x10;
                        blockInfos = metadataStream.ReadArray <BlockInfo>();
                        metadata   = new BundleMetadata(stream.BaseStream, m_filePath, isClosable);
                        metadata.Read530(metadataStream, dataPosition);

                        if (memStream.Position != memStream.Length)
                        {
                            throw new Exception($"Read {memStream.Position} but expected {memStream.Length}");
                        }
                    }
                }
                break;
            }

            default:
                throw new NotSupportedException($"Bundle compression '{metaCompress}' isn't supported");
            }

            stream.BaseStream.Position = dataPosition;
            Read530Blocks(stream, isClosable, blockInfos, metadata);
        }
Пример #5
0
        public override void Read(AssetReader reader)
        {
            if (IsSerialized(reader.Version))
            {
                ReadBase(reader);

                ParsedForm.Read(reader);

                m_platforms = reader.ReadEnum32Array((t) => (GPUPlatform)t);
                uint[] offsets             = reader.ReadUInt32Array();
                uint[] compressedLengths   = reader.ReadUInt32Array();
                uint[] decompressedLengths = reader.ReadUInt32Array();
                byte[] compressedBlob      = reader.ReadByteArray();
                reader.AlignStream(AlignType.Align4);

                m_subProgramBlobs = new ShaderSubProgramBlob[m_platforms.Length];
                using (MemoryStream memStream = new MemoryStream(compressedBlob))
                {
                    for (int i = 0; i < m_platforms.Length; i++)
                    {
                        uint offset             = offsets[i];
                        uint compressedLength   = compressedLengths[i];
                        uint decompressedLength = decompressedLengths[i];

                        memStream.Position = offset;
                        byte[] decompressedBuffer = new byte[decompressedLength];
                        using (Lz4Stream lz4Stream = new Lz4Stream(memStream, (int)compressedLength))
                        {
                            int read = lz4Stream.Read(decompressedBuffer, 0, decompressedBuffer.Length);
                            if (read != decompressedLength)
                            {
                                throw new Exception($"Can't properly decode shader blob. Read {read} but expected {decompressedLength}");
                            }
                        }

                        using (MemoryStream blobMem = new MemoryStream(decompressedBuffer))
                        {
                            using (AssetReader blobReader = new AssetReader(blobMem, reader.Version, reader.Platform, reader.Flags))
                            {
                                ShaderSubProgramBlob blob = new ShaderSubProgramBlob();
                                blob.Read(blobReader);
                                m_subProgramBlobs[i] = blob;
                            }
                        }
                    }
                }
            }
            else
            {
                base.Read(reader);

                if (IsEncoded(reader.Version))
                {
                    uint decompressedSize = reader.ReadUInt32();
                    int  comressedSize    = reader.ReadInt32();

                    byte[] subProgramBlob = new byte[comressedSize];
                    reader.Read(subProgramBlob, 0, comressedSize);
                    reader.AlignStream(AlignType.Align4);

                    if (comressedSize > 0 && decompressedSize > 0)
                    {
                        byte[] decompressedBuffer = new byte[decompressedSize];
                        using (MemoryStream memStream = new MemoryStream(subProgramBlob))
                        {
                            using (Lz4Stream lz4Stream = new Lz4Stream(memStream))
                            {
                                int read = lz4Stream.Read(decompressedBuffer, 0, decompressedBuffer.Length);
                                if (read != decompressedSize)
                                {
                                    throw new Exception($"Can't properly decode sub porgram blob. Read {read} but expected {decompressedSize}");
                                }
                            }
                        }

                        using (MemoryStream memStream = new MemoryStream(decompressedBuffer))
                        {
                            using (AssetReader blobReader = new AssetReader(memStream, reader.Version, reader.Platform, reader.Flags))
                            {
                                SubProgramBlob.Read(blobReader);
                            }
                        }
                    }
                }

                if (IsReadFallback(reader.Version))
                {
                    Fallback.Read(reader);
                }
                if (IsReadDefaultProperties(reader.Version))
                {
                    DefaultProperties.Read(reader);
                }
                if (IsReadStaticProperties(reader.Version))
                {
                    StaticProperties.Read(reader);
                }
            }

            if (IsReadDependencies(reader.Version))
            {
                m_dependencies = reader.ReadArray <PPtr <Shader> >();
            }
            if (IsReadNonModifiableTextures(reader.Version))
            {
                m_nonModifiableTextures = reader.ReadArray <PPtr <Texture> >();
            }
            if (IsReadShaderIsBaked(reader.Version))
            {
                ShaderIsBaked = reader.ReadBoolean();
                reader.AlignStream(AlignType.Align4);
            }
        }
Пример #6
0
        private void Read530Blocks(EndianStream stream, bool isClosable, BlockInfo[] blockInfos, BundleMetadata metadata)
        {
            // Special case. If bundle has no compressed blocks then pass it as a stream
            if (blockInfos.All(t => t.Flags.GetCompression() == BundleCompressType.None))
            {
                Metadatas = new BundleMetadata[] { metadata };
            }

            long dataPosisition   = stream.BaseStream.Position;
            long decompressedSize = blockInfos.Sum(t => t.DecompressedSize);

            if (decompressedSize > int.MaxValue)
            {
                throw new Exception("How to read such big data? Save to file and then read?");
            }

            MemoryStream memStream = new MemoryStream((int)decompressedSize);

            foreach (BlockInfo blockInfo in blockInfos)
            {
                BundleCompressType compressType = blockInfo.Flags.GetCompression();
                switch (compressType)
                {
                case BundleCompressType.None:
                    stream.BaseStream.CopyStream(memStream, blockInfo.DecompressedSize);
                    break;

                case BundleCompressType.LZMA:
                    SevenZipHelper.DecompressLZMAStream(stream.BaseStream, blockInfo.CompressedSize, memStream, blockInfo.DecompressedSize);
                    break;

                case BundleCompressType.LZ4:
                case BundleCompressType.LZ4HZ:
                    using (Lz4Stream lzStream = new Lz4Stream(stream.BaseStream, blockInfo.CompressedSize))
                    {
                        long read = lzStream.Read(memStream, blockInfo.DecompressedSize);
                        if (read != blockInfo.DecompressedSize)
                        {
                            throw new Exception($"Read {read} but expected {blockInfo.CompressedSize}");
                        }
                    }
                    break;

                default:
                    throw new NotImplementedException($"Bundle compression '{compressType}' isn't supported");
                }
            }

            if (isClosable)
            {
                stream.Dispose();
            }

            BundleFileEntry[] entries = new BundleFileEntry[metadata.Entries.Count];
            for (int i = 0; i < metadata.Entries.Count; i++)
            {
                BundleFileEntry bundleEntry = metadata.Entries[i];
                string          name        = bundleEntry.Name;
                long            offset      = bundleEntry.Offset - dataPosisition;
                long            size        = bundleEntry.Size;
                BundleFileEntry streamEntry = new BundleFileEntry(memStream, m_filePath, name, offset, size);
                entries[i] = streamEntry;
            }
            BundleMetadata streamMetadata = new BundleMetadata(memStream, m_filePath, true, entries);

            Metadatas = new BundleMetadata[] { streamMetadata };
        }
Пример #7
0
        private void Read530Blocks(SmartStream bundleStream, BlockInfo[] blockInfos)
        {
            int  cachedBlock = -1;
            long dataOffset  = bundleStream.Position;

            BundleFileEntry[] newEntries = new BundleFileEntry[Metadata.Entries.Count];
            using (SmartStream blockStream = SmartStream.CreateNull())
            {
                for (int ei = 0; ei < Metadata.Entries.Count; ei++)
                {
                    BundleFileEntry entry = Metadata.Entries[ei];

                    // find block corresponding to current entry
                    int  blockIndex         = 0;
                    long compressedOffset   = 0;
                    long decompressedOffset = 0;
                    while (true)
                    {
                        BlockInfo block = blockInfos[blockIndex];
                        if (decompressedOffset + block.DecompressedSize > entry.Offset)
                        {
                            break;
                        }
                        blockIndex++;
                        compressedOffset   += block.CompressedSize;
                        decompressedOffset += block.DecompressedSize;
                    }

                    // check does this entry use any compressed blocks
                    long entrySize    = 0;
                    bool isCompressed = false;
                    for (int bi = blockIndex; entrySize < entry.Size; bi++)
                    {
                        BlockInfo block = blockInfos[bi];
                        entrySize += block.DecompressedSize;
                        if (block.Flags.GetCompression() != BundleCompressType.None)
                        {
                            isCompressed = true;
                            break;
                        }
                    }

                    if (isCompressed)
                    {
                        // well, at leat one block is compressed so we should copy data of current entry to separate stream
                        using (SmartStream entryStream = CreateStream(entry.Size))
                        {
                            long left        = entry.Size;
                            long entryOffset = entry.Offset - decompressedOffset;
                            bundleStream.Position = dataOffset + compressedOffset;

                            // copy data of all blocks used by current entry to created stream
                            for (int bi = blockIndex; left > 0; bi++)
                            {
                                long      blockOffset = 0;
                                BlockInfo block       = blockInfos[bi];
                                if (cachedBlock == bi)
                                {
                                    // some data of previous entry is in the same block as this one
                                    // so we don't need to unpack it once again but can use cached stream
                                    bundleStream.Position += block.CompressedSize;
                                }
                                else
                                {
                                    BundleCompressType compressType = block.Flags.GetCompression();
                                    switch (compressType)
                                    {
                                    case BundleCompressType.None:
                                        blockOffset = dataOffset + compressedOffset;
                                        blockStream.Assign(bundleStream);
                                        break;

                                    case BundleCompressType.LZMA:
                                        blockStream.Move(CreateStream(block.DecompressedSize));
                                        SevenZipHelper.DecompressLZMAStream(bundleStream, block.CompressedSize, blockStream, block.DecompressedSize);
                                        break;

                                    case BundleCompressType.LZ4:
                                    case BundleCompressType.LZ4HZ:
                                        blockStream.Move(CreateStream(block.DecompressedSize));
                                        using (Lz4Stream lzStream = new Lz4Stream(bundleStream, block.CompressedSize))
                                        {
                                            long read = lzStream.Read(blockStream, block.DecompressedSize);
                                            if (read != block.DecompressedSize)
                                            {
                                                throw new Exception($"Read {read} but expected {block.CompressedSize}");
                                            }
                                        }
                                        break;

                                    default:
                                        throw new NotImplementedException($"Bundle compression '{compressType}' isn't supported");
                                    }
                                    cachedBlock = bi;
                                }

                                // consider next offsets:
                                // 1) block - if it is new stream then offset is 0, otherwise offset of this block in bundle file
                                // 2) entry - if this is first block for current entry then it is offset of this entry related to this block
                                //			  otherwise 0
                                long fragmentSize = block.DecompressedSize - entryOffset;
                                blockStream.Position = blockOffset + entryOffset;
                                entryOffset          = 0;

                                long size = Math.Min(fragmentSize, left);
                                blockStream.CopyStream(entryStream, size);

                                compressedOffset += block.CompressedSize;
                                left             -= size;
                            }
                            if (left < 0)
                            {
                                throw new Exception($"Read more than expected");
                            }

                            newEntries[ei] = new BundleFileEntry(entryStream, entry.FilePath, entry.Name, 0, entry.Size);
                        }
                    }
                    else
                    {
                        // no compressed blocks was found so we can use original bundle stream
                        newEntries[ei] = new BundleFileEntry(entry, dataOffset + entry.Offset);
                    }
                }
            }
            Metadata.Dispose();
            Metadata = new BundleMetadata(m_filePath, newEntries);
        }
Пример #8
0
        private void Read530Metadata(EndianReader reader, long basePosition)
        {
            SmartStream bundleStream = (SmartStream)reader.BaseStream;
            long        dataPosition = bundleStream.Position;

            if (Header.Flags.IsMetadataAtTheEnd())
            {
                bundleStream.Position = basePosition + Header.BundleSize - Header.MetadataCompressedSize;
            }
            else
            {
                dataPosition += Header.MetadataCompressedSize;
            }

            BlockInfo[]        blockInfos;
            BundleCompressType metaCompression = Header.Flags.GetCompression();

            switch (metaCompression)
            {
            case BundleCompressType.None:
            {
                long metaPosition = bundleStream.Position;

                // unknown 0x10
                bundleStream.Position += 0x10;
                blockInfos             = reader.ReadArray <BlockInfo>();
                Metadata = new BundleMetadata(m_filePath);
                Metadata.Read530(reader, bundleStream);

                if (bundleStream.Position != metaPosition + Header.MetadataDecompressedSize)
                {
                    throw new Exception($"Read {bundleStream.Position - metaPosition} but expected {Header.MetadataDecompressedSize}");
                }
                break;
            }

            case BundleCompressType.LZMA:
            {
                using (MemoryStream metaStream = new MemoryStream(new byte[Header.MetadataDecompressedSize]))
                {
                    SevenZipHelper.DecompressLZMASizeStream(bundleStream, Header.MetadataCompressedSize, metaStream);
                    using (EndianReader metaReader = new EndianReader(metaStream, EndianType.BigEndian))
                    {
                        // unknown 0x10
                        metaReader.BaseStream.Position += 0x10;
                        blockInfos = metaReader.ReadArray <BlockInfo>();
                        Metadata   = new BundleMetadata(m_filePath);
                        Metadata.Read530(metaReader, bundleStream);
                    }

                    if (metaStream.Position != metaStream.Length)
                    {
                        throw new Exception($"Read {metaStream.Position} but expected {metaStream.Length}");
                    }
                }
                break;
            }

            case BundleCompressType.LZ4:
            case BundleCompressType.LZ4HZ:
            {
                using (MemoryStream metaStream = new MemoryStream(new byte[Header.MetadataDecompressedSize]))
                {
                    using (Lz4Stream lzStream = new Lz4Stream(bundleStream, Header.MetadataCompressedSize))
                    {
                        long read = lzStream.Read(metaStream, Header.MetadataDecompressedSize);
                        metaStream.Position = 0;

                        if (read != Header.MetadataDecompressedSize)
                        {
                            throw new Exception($"Read {read} but expected {Header.MetadataDecompressedSize}");
                        }
                    }

                    using (EndianReader metaReader = new EndianReader(metaStream, EndianType.BigEndian))
                    {
                        // unknown 0x10
                        metaReader.BaseStream.Position += 0x10;
                        blockInfos = metaReader.ReadArray <BlockInfo>();
                        Metadata   = new BundleMetadata(m_filePath);
                        Metadata.Read530(metaReader, bundleStream);
                    }

                    if (metaStream.Position != metaStream.Length)
                    {
                        throw new Exception($"Read {metaStream.Position} but expected {metaStream.Length}");
                    }
                }
                break;
            }

            default:
                throw new NotSupportedException($"Bundle compression '{metaCompression}' isn't supported");
            }

            bundleStream.Position = dataPosition;
            Read530Blocks(bundleStream, blockInfos);
        }
Пример #9
0
        /// <summary>
        /// Read block infos and create uncompressed stream with corresponding data
        /// </summary>
        /// <param name="blockStream">Stream with block infos</param>
        /// <param name="blockPosition">BlockInfos position within block stream</param>
        /// <param name="dataStream">Stream with compressed data</param>
        /// <param name="dataPosition">CompressedData position within data stream</param>
        /// <returns>Uncompressed data stream</returns>
        private EndianStream ParseBundle6BlockInfo(EndianStream blockStream, ref long blockPosition, EndianStream dataStream, ref long dataPosition)
        {
            // dataStream and blockStream could be same stream. so we should handle this situation properly

            MemoryStream memStream    = null;
            EndianStream resultStream = null;
            long         read         = 0;

            blockStream.BaseStream.Position  = blockPosition;
            blockStream.BaseStream.Position += 0x10;
            int blockCount = blockStream.ReadInt32();

            blockPosition = blockStream.BaseStream.Position;
            for (int i = 0; i < blockCount; i++)
            {
                // prepare block position
                blockStream.BaseStream.Position = blockPosition;

                int decompressSize = blockStream.ReadInt32();
                int compressSize   = blockStream.ReadInt32();
                int flag           = blockStream.ReadInt16();
                blockPosition = blockStream.BaseStream.Position;

                dataStream.BaseStream.Position = dataPosition;
                BundleCompressType compressType = (BundleCompressType)(flag & 0x3F);
                if (i == 0)
                {
                    if (compressType == BundleCompressType.None)
                    {
                        resultStream      = dataStream;
                        m_isNewDataStream = false;
                    }
                    else
                    {
                        memStream         = new MemoryStream();
                        resultStream      = new EndianStream(memStream, EndianType.BigEndian);
                        m_isNewDataStream = true;
                    }
                }
                else
                {
                    if (compressType != BundleCompressType.None && !m_isNewDataStream)
                    {
                        // TODO: if first block is none compressed then we should create stream and copy all previous blocks into it
                        // but for now just throw exception
                        throw new NotImplementedException("None compression");
                    }
                }

                switch (compressType)
                {
                case BundleCompressType.None:
                    if (m_isNewDataStream)
                    {
                        if (decompressSize != compressSize)
                        {
                            throw new Exception($"Compressed {compressSize} and decompressed {decompressSize} sizes differ");
                        }

                        dataStream.BaseStream.CopyStream(memStream, compressSize);
                    }
                    break;

                case BundleCompressType.LZMA:
                    SevenZipHelper.DecompressLZMAStream(dataStream.BaseStream, compressSize, memStream, decompressSize);
                    break;

                case BundleCompressType.LZ4:
                case BundleCompressType.LZ4HZ:
                    using (Lz4Stream lzStream = new Lz4Stream(dataStream.BaseStream, compressSize))
                    {
                        lzStream.Read(memStream, decompressSize);
                    }
                    break;

                default:
                    throw new NotImplementedException($"Bundle compression '{compressType}' isn't supported");
                }

                dataPosition += compressSize;
                read         += compressSize;

                if (m_isNewDataStream)
                {
                    if (dataPosition != dataStream.BaseStream.Position)
                    {
                        throw new Exception($"Read data length is differ from compressed size for {i}th block");
                    }
                }
            }

            // update position acording to result stream
            if (m_isNewDataStream)
            {
                dataPosition = 0;
            }
            else
            {
                dataPosition -= read;
            }

            return(resultStream);
        }
Пример #10
0
        private void ParseBundleFormat6(EndianStream stream, bool isPadding)
        {
            long bundleSize     = stream.ReadInt64();
            int  compressSize   = stream.ReadInt32();
            int  decompressSize = stream.ReadInt32();
            int  flag           = stream.ReadInt32();

            if (isPadding)
            {
                stream.BaseStream.Position++;
            }

            long blockPosition;
            long dataPosition;
            int  isDataFirst = flag & 0x80;

            if (isDataFirst != 0)
            {
                blockPosition = stream.BaseStream.Length - compressSize;
                dataPosition  = stream.BaseStream.Position;
            }
            else
            {
                blockPosition = stream.BaseStream.Position;
                dataPosition  = stream.BaseStream.Position + compressSize;
            }

            stream.BaseStream.Position = blockPosition;
            BundleCompressType compressType = (BundleCompressType)(flag & 0x3F);

            switch (compressType)
            {
            case BundleCompressType.None:
                ParseBundle6BlockInfo(stream, ref blockPosition, stream, ref dataPosition);
                ParseBundle6Files(stream, ref blockPosition, stream, ref dataPosition);
                break;

            case BundleCompressType.LZMA:
                using (MemoryStream memStream = SevenZipHelper.DecompressLZMASSizeStream(stream.BaseStream, compressSize))
                {
                    using (EndianStream decBlockStream = new EndianStream(memStream, EndianType.BigEndian))
                    {
                        // update position acerding to newly created stream
                        blockPosition = 0;
                        using (EndianStream decDataStream = ParseBundle6BlockInfo(decBlockStream, ref blockPosition, stream, ref dataPosition))
                        {
                            ParseBundle6Files(decBlockStream, ref blockPosition, decDataStream, ref dataPosition);
                        }
                    }
                }
                break;

            case BundleCompressType.LZ4:
            case BundleCompressType.LZ4HZ:
                using (MemoryStream memStream = new MemoryStream(decompressSize))
                {
                    using (Lz4Stream lzStream = new Lz4Stream(stream.BaseStream, compressSize))
                    {
                        lzStream.Read(memStream, decompressSize);
                    }
                    using (EndianStream decBlockStream = new EndianStream(memStream, EndianType.BigEndian))
                    {
                        // update position acerding to newly created stream
                        blockPosition = 0;
                        using (EndianStream decDataStream = ParseBundle6BlockInfo(decBlockStream, ref blockPosition, stream, ref dataPosition))
                        {
                            ParseBundle6Files(decBlockStream, ref blockPosition, decDataStream, ref dataPosition);
                        }
                    }
                }
                break;

            default:
                throw new NotImplementedException($"Bundle compression '{compressType}' isn't supported");
            }
        }