Esempio n. 1
0
        static AssetObject LoadObject(EndianStream es, int format, TypeMeta types)
        {
            var obj = new AssetObject();

            obj.PathId  = es.ReadUInt64();
            obj.DataOfs = es.ReadUInt32();
            obj.Size    = es.ReadUInt32();
            if (format < 17)
            {
                obj.TypeId  = es.ReadInt32();
                obj.ClassId = es.ReadInt16();
            }
            else
            {
                obj.TypeId  = es.ReadInt32();
                obj.ClassId = types.ClassIds[obj.TypeId];
            }
            if (format <= 16)
            {
                es.ReadInt16();
            }
            if (format == 15 || format == 16)
            {
                es.ReadByte();
            }
            return(obj);
        }
Esempio n. 2
0
        private void ParseBundleFormat(EndianStream stream)
        {
            int bundleSize = stream.ReadInt32();

            short unused16       = stream.ReadInt16();
            int   offset         = stream.ReadInt16();
            int   unused32       = stream.ReadInt32();
            int   lzmaChunkCount = stream.ReadInt32();

            if (lzmaChunkCount != 1)
            {
                // see original project, it support only 1 chunk
                throw new Exception($"Found lzma with {lzmaChunkCount} chunks");
            }

            MemoryStream memStream = IsBundlePacked ? new MemoryStream() : null;

            for (int i = 0; i < lzmaChunkCount; i++)
            {
                int lzmaSize         = stream.ReadInt32();
                int decompressedSize = stream.ReadInt32();

                stream.BaseStream.Position = offset;
                switch (Signature)
                {
                case BundleSignature.UnityRaw:
                    ParseBundleFiles(stream);
                    break;

                case BundleSignature.UnityWeb:
                case BundleSignature.HexFA:
                    memStream.Position = 0;

                    SevenZipHelper.DecompressLZMASizeStream(stream.BaseStream, lzmaSize, memStream);
                    using (EndianStream decompressStream = new EndianStream(memStream, EndianType.BigEndian))
                    {
                        ParseBundleFiles(decompressStream);
                    }
                    break;

                default:
                    throw new Exception($"Unsupported bundle signature '{Signature}'");
                }

                offset += lzmaSize;
            }
        }
Esempio n. 3
0
            public void Load(EndianStream es, int format)
            {
                ClassIds  = new List <int>();
                Hashes    = new Dictionary <int, byte[]>();
                TypeTrees = new Dictionary <int, TreeNode>();

                version = es.ReadStringToNull();
                target  = (BuildTarget)es.ReadInt32();
                Debug.WriteLine(version + " target " + target);
                if (format >= 13)
                {
                    var hasTypeTrees = es.ReadByte() != 0;
                    var num          = es.ReadInt32();
                    for (int i = 0; i < num; i++)
                    {
                        int classId = es.ReadInt32();
                        if (format >= 17)
                        {
                            var unk0     = es.ReadByte();
                            var scriptId = es.ReadInt16();
                            if (classId == 114)
                            {
                                if (scriptId >= 0)
                                {
                                    classId = -2 - scriptId;
                                }
                                else
                                {
                                    classId = -1;
                                }
                            }
                        }
                        ClassIds.Add(classId);
                        Hashes.Add(classId, es.ReadBytes(classId < 0 ? 32 : 16));
                        if (hasTypeTrees)
                        {
                            TypeTrees.Add(classId, LoadTree(es, format));
                        }
                    }
                }
            }
Esempio n. 4
0
        /// <summary>
        /// Load the usermap's Header
        /// </summary>
        public void LoadHeader()
        {
            _forgeHeader = new Header();

            _forgeStream.SeekTo(0x42);
            _forgeHeader.CreationDate = _forgeStream.ReadInt32();
            _forgeStream.SeekTo(0x48);
            _forgeHeader.CreationVarientName = _forgeStream.ReadUTF16(0x1F);
            _forgeStream.SeekTo(0x68);
            _forgeHeader.CreationVarientDescription = _forgeStream.ReadAscii(0x80);
            _forgeStream.SeekTo(0xE8);
            _forgeHeader.CreationVarientAuthor = _forgeStream.ReadAscii(0x13);

            _forgeStream.SeekTo(0x114);
            _forgeHeader.ModificationDate = _forgeStream.ReadInt32();
            _forgeStream.SeekTo(0x150);
            _forgeHeader.VarientName = _forgeStream.ReadUTF16(0x1F);
            _forgeStream.SeekTo(0x170);
            _forgeHeader.VarientDescription = _forgeStream.ReadAscii(0x80);
            _forgeStream.SeekTo(0x1F0);
            _forgeHeader.VarientAuthor = _forgeStream.ReadAscii(0x13);

            _forgeStream.SeekTo(0x228);
            _forgeHeader.MapID = _forgeStream.ReadInt32();

            _forgeStream.SeekTo(0x246);
            _forgeHeader.SpawnedObjectCount = _forgeStream.ReadInt16();

            _forgeStream.SeekTo(0x24C);
            _forgeHeader.WorldBoundsXMin = _forgeStream.ReadFloat();
            _forgeHeader.WorldBoundsXMax = _forgeStream.ReadFloat();
            _forgeHeader.WorldBoundsYMin = _forgeStream.ReadFloat();
            _forgeHeader.WorldBoundsYMax = _forgeStream.ReadFloat();
            _forgeHeader.WorldBoundsZMin = _forgeStream.ReadFloat();
            _forgeHeader.WorldBoundsZMax = _forgeStream.ReadFloat();

            _forgeStream.SeekTo(0x268);
            _forgeHeader.MaximiumBudget = _forgeStream.ReadFloat();
            _forgeHeader.CurrentBudget  = _forgeStream.ReadFloat();
        }
Esempio n. 5
0
 public ItemPlacementChunk(EndianStream stream)
 {
     Offset    = stream.Position;
     ChunkType = (ItemChunkType)stream.ReadInt16();
     stream.SeekTo(stream.Position + 0x0A);
     TagIndex    = stream.ReadInt32();
     SpawnCoords = new ItemSpawnCoords()
     {
         X     = stream.ReadFloat(),
         Y     = stream.ReadFloat(),
         Z     = stream.ReadFloat(),
         Yaw   = stream.ReadFloat(),
         Pitch = stream.ReadFloat(),
         Roll  = stream.ReadFloat()
     };
     stream.SeekTo(stream.Position + 0x16);
     stream.ReadByte();
     Team        = stream.ReadByte();
     SpareClips  = stream.ReadByte();
     RespawnTime = stream.ReadByte();
     stream.SeekTo(stream.Position + 0x12);
 }
Esempio n. 6
0
        private void ReadBase5(EndianStream stream)
        {
            int classID = stream.ReadInt32();

            if (IsReadSubClass)
            {
                // same class ID with different subclasses coored several times but we need unique class ID
                // so create unique class ID and store corresponding class ID

                stream.BaseStream.Position++;

                int uniqueClassID;
                int subClassID = stream.ReadInt16();
                if (subClassID == -1)
                {
                    // no subclass. that meen that class ID is unique by itself
                    uniqueClassID = classID;
                }
                else if (subClassID >= 0)
                {
                    // ordinal class ID should be >= 0, so we can use whole negative int range
                    uniqueClassID = -1 - subClassID;
                }
                else
                {
                    throw new Exception($"Invalid type value {subClassID} for asset file {Name}");
                }

                ClassIDMap id = new ClassIDMap(uniqueClassID, classID);
                m_classIDs.Add(id);

                if (classID == (int)ClassIDType.MonoBehaviour)
                {
                    stream.BaseStream.Position += 16;
                }
                classID = uniqueClassID;
            }
            else if (classID < 0)
            {
                stream.BaseStream.Position += 16;
            }
            stream.BaseStream.Position += 16;

            if (BaseDefinitions)
            {
                ClassStruct classStruct = new ClassStruct();
                classStruct.ClassID = classID;

                int memberCount = stream.ReadInt32();
                if (memberCount < 0)
                {
                    throw new Exception($"Invalid member count {memberCount}");
                }
                int stringSize = stream.ReadInt32();
                if (stringSize < 0)
                {
                    throw new Exception($"Invalid string size {stringSize}");
                }

                long stringPosition = stream.BaseStream.Position + memberCount * ClassMember.ClassSize;

                List <ClassMember> members = new List <ClassMember>();
                for (int i = 0; i < memberCount; i++)
                {
                    ReadClassMember5(stream, classStruct, members, stringPosition);
                }
                stream.BaseStream.Position += stringSize;
                classStruct.Members         = members.ToArray();

                AddClassStruct(classStruct);
            }
        }
Esempio n. 7
0
        public override void Read(EndianStream stream)
        {
            base.Read(stream);

            Enabled = stream.ReadBoolean();
            if (IsReadAlign)
            {
                stream.AlignStream(AlignType.Align4);
            }

            CastShadows    = stream.ReadByte();
            ReceiveShadows = stream.ReadByte();
            if (IsReadAlign)
            {
                stream.AlignStream(AlignType.Align4);
            }

            if (IsReadMotionVector)
            {
                MotionVectors        = stream.ReadByte();
                LightProbeUsage      = stream.ReadByte();
                ReflectionProbeUsage = stream.ReadByte();
                stream.AlignStream(AlignType.Align4);
            }

            if (IsSmallLightIndex)
            {
                LightmapIndex = stream.ReadByte();
            }
            else
            {
                LightmapIndex = stream.ReadUInt16();
            }

            if (IsReadLightDynamic)
            {
                LightmapIndexDynamic = stream.ReadUInt16();
            }

            if (IsReadTileOffset)
            {
                LightmapTilingOffset.Read(stream);
            }
            if (IsReadTileDynamic)
            {
                LightmapTilingOffsetDynamic.Read(stream);
            }

            m_materials = stream.ReadArray(() => new PPtr <Material>(AssetsFile));

            if (IsReadSubsetIndices)
            {
                m_subsetIndices = stream.ReadUInt32Array();
            }
            else
            {
                StaticBatchInfo.Read(stream);
            }

            StaticBatchRoot.Read(stream);

            if (IsReadUseLight)
            {
                UseLightProbes = stream.ReadBoolean();
                stream.AlignStream(AlignType.Align4);
                if (IsReadReflectUsage)
                {
                    ReflectionProbeUsage = stream.ReadInt32();
                }
            }

            ProbeAnchor.Read(stream);
            if (IsReadLightOverride)
            {
                LightProbeVolumeOverride.Read(stream);
            }
            stream.AlignStream(AlignType.Align4);

            SortingLayerID = stream.ReadInt32();

            if (IsReadLayer)
            {
                SortingLayer = stream.ReadInt16();
            }

            SortingOrder = stream.ReadInt16();
            stream.AlignStream(AlignType.Align4);
        }
Esempio n. 8
0
        /// <summary>
        /// Load the gpd's Campaign Skulls
        /// </summary>
        public void LoadCampaignSkulls()
        {
            _gpdCampaignSkulls = new List <Skull>();

            // Load Gold Skulls
            _gpdStream.SeekTo(0x356E);

            BitArray goldSkullsBitmask = new BitArray(BitConverter.GetBytes(_gpdStream.ReadInt16()));

            for (int skullBitmaskIndex = 0; skullBitmaskIndex < 9; skullBitmaskIndex++)
            {
                Skull skull = new Skull();
                skull.Enabled   = goldSkullsBitmask[skullBitmaskIndex];
                skull.SkullType = SkullType.Gold;
                skull.Name      = (SkullName)skullBitmaskIndex;

                #region Skill Description
                switch (skullBitmaskIndex)
                {
                case 0:
                    skull.Description = "Death carries a heavy price...";
                    break;

                case 1:
                    skull.Description = "Bash your way to better health.";
                    break;

                case 2:
                    skull.Description = "Your foes always make every saving throw.";
                    break;

                case 3:
                    skull.Description = "Pull pin. Count to three. Throw.";
                    break;

                case 4:
                    skull.Description = "You'll miss those eyes in the back of your head.";
                    break;

                case 5:
                    skull.Description = "Trust us. Bring a magazine.";
                    break;

                case 6:
                    skull.Description = "Field promotions for everyone!";
                    break;

                case 7:
                    skull.Description = "What was once resistance is now immunity.";
                    break;

                case 8:
                    skull.Description = "Coverage under the covenant Health Plan.";
                    break;
                }
                #endregion

                _gpdCampaignSkulls.Add(skull);
            }

            _gpdStream.SeekTo(0x3573);
            goldSkullsBitmask = new BitArray(BitConverter.GetBytes((int)(_gpdStream.ReadByte() >> 1)));
            if (goldSkullsBitmask.Length != 0)
            {
                for (int skullBitmaskIndex = 0; skullBitmaskIndex < 4; skullBitmaskIndex++)
                {
                    Skull skull = new Skull();
                    skull.Enabled   = goldSkullsBitmask[skullBitmaskIndex];
                    skull.SkullType = SkullType.Silver;
                    skull.Name      = (SkullName)(skullBitmaskIndex + 9);

                    #region Skill Description
                    switch (skullBitmaskIndex)
                    {
                    case 0:
                        skull.Description = "Shoot from the hip.";
                        break;

                    case 1:
                        skull.Description = "More bang for your buck.";
                        break;

                    case 2:
                        skull.Description = "Light a match...";
                        break;

                    case 3:
                        skull.Description = "But a dog beat me over the fence.";
                        break;
                    }
                    #endregion

                    _gpdCampaignSkulls.Add(skull);
                }
            }
        }
Esempio n. 9
0
        // returns list of materials
        public static void ReadBundleStream(EndianStream b_Stream, out List <string> materials, out List <string> gameObjects)
        {
            materials   = null;
            gameObjects = null;
            var header = b_Stream.ReadStringToNull();

            if (header == "UnityFS")
            {
                var ver1 = b_Stream.ReadInt32();
                var ver2 = b_Stream.ReadStringToNull();
                var ver3 = b_Stream.ReadStringToNull();

                long bundleSize = ver1 < 6 ? b_Stream.ReadInt32() : b_Stream.ReadInt64();

                var  cHdrSize    = b_Stream.ReadInt32();
                var  uHdrSize    = b_Stream.ReadInt32();
                var  hdrFlags    = b_Stream.ReadInt32();
                var  compression = hdrFlags & 0x3f;
                var  eofMetadata = (hdrFlags & 0x80) != 0;
                long pos         = 0;
                if (eofMetadata)
                {
                    pos = b_Stream.Position;
                    b_Stream.BaseStream.Seek(-cHdrSize, SeekOrigin.End);
                }
                var data = decompress(b_Stream.ReadBytes(cHdrSize), uHdrSize, compression);
                if (eofMetadata)
                {
                    b_Stream.Position = pos;
                }
                var hdr       = new EndianStream(new MemoryStream(data), EndianType.BigEndian);
                var guid      = hdr.ReadBytes(16);
                var numBlocks = hdr.ReadInt32();
                var blocks    = new BlockInfo[numBlocks];
                for (int i = 0; i < numBlocks; i++)
                {
                    var uSize = hdr.ReadInt32();
                    var cSize = hdr.ReadInt32();
                    var flags = hdr.ReadInt16();
                    blocks[i] = new BlockInfo()
                    {
                        uSize = uSize, cSize = cSize, flags = flags
                    };
                }
                var storage = new Storage(blocks, b_Stream);

                var numParts = hdr.ReadInt32();
                for (int i = 0; i < numParts; i++)
                {
                    var ofs    = hdr.ReadInt64();
                    var size   = hdr.ReadInt64();
                    var status = hdr.ReadInt32();
                    var name   = hdr.ReadStringToNull();
                    var part   = new BundlePart()
                    {
                        stream = new StreamPart(storage, ofs, size), name = name
                    };
                    if (i == 0) //(status & 4) != 0)
                    {
                        LoadAssetFile(new StreamPart(storage, ofs, size), out materials, out gameObjects);
                    }
                }
            }
            else
            {
                throw new Exception("Unknown header: " +
                                    (header[0] > 'A' && header[0] < 'Z' ?
                                     header.Substring(0, 8) :
                                     string.Join(" ", header.Substring(0, 8).ToCharArray().Select(c => ((int)c).ToString("X2")))));
            }
        }
Esempio n. 10
0
        static object ReadValue(EndianStream es, TreeNode type)
        {
            object v;
            var    t = type.type;

            switch (t)
            {
            case "bool":
                v = es.ReadByte() != 0;
                break;

            case "SInt8":
                v = es.ReadSByte();
                break;

            case "UInt8":
                v = es.ReadByte();
                break;

            case "SInt16":
                v = es.ReadInt16();
                break;

            case "UInt16":
                v = es.ReadUInt16();
                break;

            case "SInt32":
            case "int":
                v = es.ReadInt32();
                break;

            case "UInt32":
            case "unsigned int":
                v = es.ReadUInt32();
                break;

            case "SInt64":
                v = es.ReadInt64();
                break;

            case "UInt64":
                v = es.ReadUInt64();
                break;

            case "float":
                es.AlignStream(4);
                v = es.ReadSingle();
                break;

            case "double":
                es.AlignStream(4);
                v = es.ReadDouble();
                break;

            case "string":
                var ssize = es.ReadInt32();
                v = UTF8Encoding.UTF8.GetString(es.ReadBytes(ssize));
                if (type.children[0].postAlign)
                {
                    es.AlignStream(4);
                }
                break;

            default:
                var firstChild = type.children.Any() ? type.children[0] : null;
                if (type.isArray)
                {
                    firstChild = type;
                }
                if (t.StartsWith("PPtr<"))
                {
                    v = new FilePtr()
                    {
                        FileID = es.ReadInt32(), PathID = es.ReadInt64()
                    };
                }
                else if (firstChild != null && firstChild.isArray)
                {
                    var size      = es.ReadInt32();
                    var arrayType = firstChild.children[1];
                    if (arrayType.type == "char" || arrayType.type == "UInt8")
                    {
                        v = es.ReadBytes(size);
                    }
                    else
                    {
                        var a = new object[size];
                        for (int i = 0; i < size; i++)
                        {
                            a[i] = ReadValue(es, arrayType);
                        }
                        v = a;
                    }
                    if (firstChild.postAlign)
                    {
                        es.AlignStream(4);
                    }
                }
                else if (t == "pair")
                {
                    v = Tuple.Create <object, object>(ReadValue(es, type.children[0]), ReadValue(es, type.children[1]));
                }
                else
                {
                    var o = new Dictionary <string, object>();
                    foreach (var child in type.children)
                    {
                        o.Add(child.name, ReadValue(es, child));
                    }
                    v = o;
                }
                break;
            }
            if (type.postAlign)
            {
                es.AlignStream(4);
            }
            return(v);
        }
Esempio n. 11
0
        /// <summary>
        /// Load the STFS Container's MetaData
        /// </summary>
        public void LoadMetaData()
        {
            _stfsMetaData = new xMetaData();

            _stfsStream.SeekTo(0x22C);

            // Read License Entries
            _stfsMetaData.LicensingEntries              = new xMetaData.LicensingEntry();
            _stfsMetaData.LicensingEntries.LicenseID    = _stfsStream.ReadInt64();
            _stfsMetaData.LicensingEntries.LicenseBits  = _stfsStream.ReadInt32();
            _stfsMetaData.LicensingEntries.LicenseFlags = _stfsStream.ReadInt32();

            _stfsStream.SeekTo(0x32C);
            _stfsMetaData.ContentID       = _stfsStream.ReadBlock(0x14);
            _stfsMetaData.HeaderSize      = _stfsStream.ReadUInt32();
            _stfsMetaData.ContentType     = (ContentTypes)_stfsStream.ReadInt32();
            _stfsMetaData.MetadataVersion = _stfsStream.ReadInt32();
            _stfsMetaData.ContentSize     = _stfsStream.ReadInt64();
            _stfsMetaData.MediaID         = _stfsStream.ReadUInt32();
            _stfsMetaData.Version         = _stfsStream.ReadInt32();
            _stfsMetaData.BaseVersion     = _stfsStream.ReadInt32();
            _stfsMetaData.TitleID         = _stfsStream.ReadUInt32();
            _stfsMetaData.Platform        = (PackagePlatform)_stfsStream.ReadByte();
            _stfsMetaData.ExecutableType  = _stfsStream.ReadByte();
            _stfsMetaData.DiskNumber      = _stfsStream.ReadByte();
            _stfsMetaData.DiskInSet       = _stfsStream.ReadByte();
            _stfsMetaData.SaveGameID      = _stfsStream.ReadUInt32();
            _stfsMetaData.ConsoleID       = _stfsStream.ReadBlock(0x5);
            _stfsMetaData.ProfileID       = _stfsStream.ReadBlock(0x8);

            _stfsMetaData.VolumeDescriptor = new xMetaData.xVolumeDescription();
            _stfsMetaData.VolumeDescriptor.VolumeDescriptorSize = _stfsStream.ReadByte();
            _stfsStream.ReadByte();
            _stfsStream.ReadByte();
            _stfsMetaData.VolumeDescriptor.FileTableBlockCount        = _stfsStream.ReadInt16();
            _stfsMetaData.VolumeDescriptor.FileTableBlockNumber       = _stfsStream.ReadInt24();
            _stfsMetaData.VolumeDescriptor.TopHashTableHash           = _stfsStream.ReadBlock(0x14);
            _stfsMetaData.VolumeDescriptor.TotalAllocatedBlockCount   = _stfsStream.ReadInt32();
            _stfsMetaData.VolumeDescriptor.TotalUnallocatedBlockCount = _stfsStream.ReadInt32();

            _stfsStream.SeekTo(0x39D);
            _stfsMetaData.DataFileCount        = _stfsStream.ReadInt32();
            _stfsMetaData.DataFileCombinedSize = _stfsStream.ReadInt64();

            _stfsStream.SeekTo(0x3FD);
            _stfsMetaData.DeviceID    = _stfsStream.ReadBlock(0x14);
            _stfsMetaData.DisplayName = _stfsStream.ReadUTF16();

            _stfsStream.SeekTo(0xD11);
            _stfsMetaData.DisplayDescription = _stfsStream.ReadUTF16();

            _stfsStream.SeekTo(0x1611);
            _stfsMetaData.PublisherName = _stfsStream.ReadUTF16();

            _stfsStream.SeekTo(0x1691);
            _stfsMetaData.TitleName = _stfsStream.ReadUTF16();

            _stfsStream.SeekTo(0x1711);
            _stfsMetaData.TransferFlags = (TransferFlags)_stfsStream.ReadByte();

            _stfsMetaData.ThumbnailImage      = new xMetaData.xMetaImage();
            _stfsMetaData.TitleThumbnailImage = new xMetaData.xMetaImage();

            _stfsMetaData.ThumbnailImage.ImageSize      = _stfsStream.ReadInt32();
            _stfsMetaData.TitleThumbnailImage.ImageSize = _stfsStream.ReadInt32();

            _stfsMetaData.ThumbnailImage.Image = _stfsStream.ReadBlock(_stfsMetaData.ThumbnailImage.ImageSize);
            _stfsStream.SeekTo(0x571A);
            _stfsMetaData.TitleThumbnailImage.Image = _stfsStream.ReadBlock(_stfsMetaData.TitleThumbnailImage.ImageSize);
        }
Esempio n. 12
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);
        }