private Folder ReadFolder(HeaderBuffer headerBytes)
        {
            Folder folder = new Folder(this);
            folder.Coders = headerBytes.CreateArray<CodersInfo>();

            int numInStreams = 0;
            int numOutStreams = 0;

            foreach (var coder in folder.Coders)
            {
                byte mainByte = headerBytes.ReadByte();
                int size = (byte)(mainByte & 0xF);
                coder.Method = headerBytes.ReadBytes(size);
                if ((mainByte & 0x10) != 0)
                {
                    coder.NumberOfInStreams = headerBytes.ReadEncodedInt64();
                    coder.NumberOfOutStreams = headerBytes.ReadEncodedInt64();
                }
                else
                {
                    coder.NumberOfInStreams = 1;
                    coder.NumberOfOutStreams = 1;
                }
                if ((mainByte & 0x20) != 0)
                {
                    ulong propertiesSize = headerBytes.ReadEncodedInt64();
                    coder.Properties = headerBytes.ReadBytes((int)propertiesSize);
                }
                while ((mainByte & 0x80) != 0)
                {
                    mainByte = headerBytes.ReadByte();
                    headerBytes.ReadBytes(mainByte & 0xF);
                    if ((mainByte & 0x10) != 0)
                    {
                        headerBytes.ReadEncodedInt64();
                        headerBytes.ReadEncodedInt64();
                    }
                    if ((mainByte & 0x20) != 0)
                    {
                        ulong propertiesSize = headerBytes.ReadEncodedInt64();
                        headerBytes.ReadBytes((int)propertiesSize);
                    }
                }
                numInStreams += (int)coder.NumberOfInStreams;
                numOutStreams += (int)coder.NumberOfOutStreams;
            }

            int numBindPairs = numOutStreams - 1;
            folder.BindPairs = new BindPair[numBindPairs];

            for (int i = 0; i < numBindPairs; i++)
            {
                BindPair bindpair = new BindPair();
                folder.BindPairs[i] = bindpair;
                bindpair.InIndex = headerBytes.ReadEncodedInt64();
                bindpair.OutIndex = headerBytes.ReadEncodedInt64();
            }

            int numPackedStreams = numInStreams - numBindPairs;

            folder.PackedStreamIndices = new ulong[numPackedStreams];

            if (numPackedStreams == 1)
            {
                uint pi = 0;
                for (uint j = 0; j < numInStreams; j++)
                {
                    if (!folder.BindPairs.Where(x => x.InIndex == j).Any())
                    {
                        folder.PackedStreamIndices[pi++] = j;
                        break;
                    }
                }
            }
            else
            {
                for (uint i = 0; i < numPackedStreams; i++)
                {
                    folder.PackedStreamIndices[i] = headerBytes.ReadEncodedInt64();
                }
            }
            return folder;
        }
        public ulong GetFolderStreamPos(int folderIndex, int indexInFolder)
        {
            Folder folder = FilesInfo.Folders[folderIndex];

            return((ulong)BaseOffset + folder.PackedStreams[indexInFolder].StartPosition);
        }
        public long GetFolderFullPackSize(int folderIndex)
        {
            Folder folder = FilesInfo.Folders[folderIndex];

            return(folder.PackedStreams.Select(x => x.PackedSize).Sum(x => (long)x));
        }
        private Folder ReadFolder(HeaderBuffer headerBytes)
        {
            Folder folder = new Folder(this);

            folder.Coders = headerBytes.CreateArray <CodersInfo>();

            int numInStreams  = 0;
            int numOutStreams = 0;

            foreach (var coder in folder.Coders)
            {
                byte mainByte = headerBytes.ReadByte();
                int  size     = (byte)(mainByte & 0xF);
                coder.Method = headerBytes.ReadBytes(size);
                if ((mainByte & 0x10) != 0)
                {
                    coder.NumberOfInStreams  = headerBytes.ReadEncodedInt64();
                    coder.NumberOfOutStreams = headerBytes.ReadEncodedInt64();
                }
                else
                {
                    coder.NumberOfInStreams  = 1;
                    coder.NumberOfOutStreams = 1;
                }
                if ((mainByte & 0x20) != 0)
                {
                    ulong propertiesSize = headerBytes.ReadEncodedInt64();
                    coder.Properties = headerBytes.ReadBytes((int)propertiesSize);
                }
                while ((mainByte & 0x80) != 0)
                {
                    mainByte = headerBytes.ReadByte();
                    headerBytes.ReadBytes(mainByte & 0xF);
                    if ((mainByte & 0x10) != 0)
                    {
                        headerBytes.ReadEncodedInt64();
                        headerBytes.ReadEncodedInt64();
                    }
                    if ((mainByte & 0x20) != 0)
                    {
                        ulong propertiesSize = headerBytes.ReadEncodedInt64();
                        headerBytes.ReadBytes((int)propertiesSize);
                    }
                }
                numInStreams  += (int)coder.NumberOfInStreams;
                numOutStreams += (int)coder.NumberOfOutStreams;
            }

            int numBindPairs = numOutStreams - 1;

            folder.BindPairs = new BindPair[numBindPairs];

            for (int i = 0; i < numBindPairs; i++)
            {
                BindPair bindpair = new BindPair();
                folder.BindPairs[i] = bindpair;
                bindpair.InIndex    = headerBytes.ReadEncodedInt64();
                bindpair.OutIndex   = headerBytes.ReadEncodedInt64();
            }


            int numPackedStreams = numInStreams - numBindPairs;

            folder.PackedStreamIndices = new ulong[numPackedStreams];

            if (numPackedStreams == 1)
            {
                uint pi = 0;
                for (uint j = 0; j < numInStreams; j++)
                {
                    if (!folder.BindPairs.Where(x => x.InIndex == j).Any())
                    {
                        folder.PackedStreamIndices[pi++] = j;
                        break;
                    }
                }
            }
            else
            {
                for (uint i = 0; i < numPackedStreams; i++)
                {
                    folder.PackedStreamIndices[i] = headerBytes.ReadEncodedInt64();
                }
            }
            return(folder);
        }
        private static void ReadSubStreamsInfo(StreamsInfo info, HeaderBuffer headerBytes)
        {
            info.UnpackedStreams = new List <UnpackedStreamInfo>();
            foreach (var folder in info.Folders)
            {
                folder.UnpackedStreams    = new UnpackedStreamInfo[1];
                folder.UnpackedStreams[0] = new UnpackedStreamInfo();
                info.UnpackedStreams.Add(folder.UnpackedStreams[0]);
            }

            bool loop = true;
            var  prop = HeaderProperty.kEnd;

            while (loop)
            {
                prop = headerBytes.ReadProperty();
                switch (prop)
                {
                case HeaderProperty.kNumUnPackStream:
                {
                    info.UnpackedStreams.Clear();
                    foreach (var folder in info.Folders)
                    {
                        var numStreams = (int)headerBytes.ReadEncodedInt64();
                        folder.UnpackedStreams = new UnpackedStreamInfo[numStreams];
                        folder.UnpackedStreams.Initialize(() => new UnpackedStreamInfo());
                        info.UnpackedStreams.AddRange(folder.UnpackedStreams);
                    }
                }
                break;

                case HeaderProperty.kCRC:
                case HeaderProperty.kSize:
                case HeaderProperty.kEnd:
                {
                    loop = false;
                }
                break;

                default:
                    throw new InvalidFormatException(prop.ToString());
                }
            }

            int si = 0;

            for (int i = 0; i < info.Folders.Length; i++)
            {
                var   folder = info.Folders[i];
                ulong sum    = 0;
                if (folder.UnpackedStreams.Length == 0)
                {
                    continue;
                }
                if (prop == HeaderProperty.kSize)
                {
                    for (int j = 1; j < folder.UnpackedStreams.Length; j++)
                    {
                        ulong size = headerBytes.ReadEncodedInt64();
                        info.UnpackedStreams[si].UnpackedSize = size;
                        sum += size;
                        si++;
                    }
                }
                info.UnpackedStreams[si].UnpackedSize = folder.GetUnpackSize() - sum;
                si++;
            }
            if (prop == HeaderProperty.kSize)
            {
                prop = headerBytes.ReadProperty();
            }

            int numDigests = 0;

            foreach (var folder in info.Folders)
            {
                if (folder.UnpackedStreams.Length != 1 || !folder.UnpackCRC.HasValue)
                {
                    numDigests += folder.UnpackedStreams.Length;
                }
            }

            si = 0;
            while (true)
            {
                if (prop == HeaderProperty.kCRC)
                {
                    int     digestIndex = 0;
                    uint?[] digests2;
                    UnPackDigests(headerBytes, numDigests, out digests2);
                    for (uint i = 0; i < info.Folders.Length; i++)
                    {
                        Folder folder = info.Folders[i];
                        if (folder.UnpackedStreams.Length == 1 && folder.UnpackCRC.HasValue)
                        {
                            info.UnpackedStreams[si].Digest = folder.UnpackCRC;
                            si++;
                        }
                        else
                        {
                            for (uint j = 0; j < folder.UnpackedStreams.Length; j++, digestIndex++)
                            {
                                info.UnpackedStreams[si].Digest = digests2[digestIndex];
                                si++;
                            }
                        }
                    }
                }
                else if (prop == HeaderProperty.kEnd)
                {
                    return;
                }
                prop = headerBytes.ReadProperty();
            }
        }