private ChunkDescriptor ReadChunkDescriptor()
        {
            UInt32 manifestSize = this.ReadUInt32BE();
            long   baseOffset   = this.BaseStream.Position;

            byte[] manifestContent = this.ReadBytes((int)manifestSize);

            ChunkDescriptor descriptor = new ChunkDescriptor();

            using (BinaryReader memoryReader = new BinaryReader(new MemoryStream(manifestContent)))
            {
                descriptor.Magic  = memoryReader.ReadBytes(4);
                descriptor.Offset = baseOffset - 4;
                if (!descriptor.Magic.SequenceEqual(new byte[] { 0x9D, 0x79, 0x8E, 0xD5 }))
                {
                    throw new InvalidDataException();
                }
                descriptor.TotalFiles                = memoryReader.ReadUInt32BE();
                descriptor.TotalFilesWithName        = memoryReader.ReadUInt32BE();
                descriptor.TotalFilesWithId          = memoryReader.ReadUInt32BE();
                descriptor.TotalFilesWithMetaEntries = memoryReader.ReadUInt32BE();
                descriptor.OffsetFileNamesBlock      = memoryReader.ReadUInt32BE();
                descriptor.OffsetMetaEntriesBlock    = memoryReader.ReadUInt32BE();
                descriptor.MetaEntriesSize           = memoryReader.ReadUInt32BE();

                for (int i = 0; i < descriptor.TotalFiles; i++)
                {
                    ChunkDescriptorPair pair = new ChunkDescriptorPair();
                    pair.Hash = memoryReader.ReadBytes(20);
                    descriptor.Pairs.Add(pair);
                }

                List <byte[]> chunkIds = new List <byte[]>();

                if (descriptor.TotalFilesWithMetaEntries == 0 && descriptor.TotalFilesWithId != 0)
                {
                    for (int i = 0; i < descriptor.TotalFilesWithName; i++)
                    {
                        descriptor.EbxDescriptors.Add(ReadIntermediateDescriptor(baseOffset, memoryReader));
                    }

                    for (int i = 0; i < descriptor.TotalFilesWithId; i++)
                    {
                        descriptor.DataDescriptors.Add(ReadIntermediateDescriptor(baseOffset, memoryReader));
                    }

                    for (int i = 0; i < descriptor.TotalFilesWithId; i++)
                    {
                        var resourceId = memoryReader.ReadUInt32BE();
                    }

                    for (int i = 0; i < descriptor.TotalFilesWithId; i++)
                    {
                        var unknown1 = memoryReader.ReadUInt64BE();
                        var unknown2 = memoryReader.ReadUInt64BE();
                    }

                    for (int i = 0; i < descriptor.TotalFilesWithId; i++)
                    {
                        chunkIds.Add(memoryReader.ReadBytes(8));
                    }
                }

                memoryReader.BaseStream.Seek(descriptor.OffsetFileNamesBlock, SeekOrigin.Begin);

                int nameStartOffset = 0;
                for (int i = 0; i < descriptor.TotalFilesWithName; i++)
                {
                    descriptor.Pairs[i].Name = memoryReader.ReadNullTerminatedString().Replace('/', '\\');

                    var compositeDescriptor = new CompositeResourceDescriptor();
                    compositeDescriptor.Name     = descriptor.Pairs[i].Name;
                    compositeDescriptor.Ebx      = ConvertIntermediateResourceToFinalResource(descriptor.EbxDescriptors.FirstOrDefault(ebx => ebx.NameOffset == nameStartOffset), compositeDescriptor);
                    compositeDescriptor.Resource = ConvertIntermediateResourceToFinalResource(descriptor.DataDescriptors.FirstOrDefault(ebx => ebx.NameOffset == nameStartOffset), compositeDescriptor);
                    descriptor.ResourceDescriptors.Add(compositeDescriptor);

                    nameStartOffset += compositeDescriptor.Name.Length + 1;
                }

                if (descriptor.TotalFilesWithMetaEntries == 0 && descriptor.TotalFilesWithId != 0)
                {
                    for (int i = 0; i < descriptor.TotalFilesWithId; i++)
                    {
                        descriptor.Pairs[(int)descriptor.TotalFilesWithName + i].Name = BitConverter.ToString(chunkIds[i]).Replace("-", "");
                    }
                }
            }

            return(descriptor);
        }
        private ResourceDescriptor ConvertIntermediateResourceToFinalResource(IntermediateResourceDescriptor intermediateResourceDescriptor, CompositeResourceDescriptor compositeDescriptor)
        {
            if (intermediateResourceDescriptor == null)
            {
                return(null);
            }

            intermediateResourceDescriptor.FinalResourceDescriptor = compositeDescriptor;

            return(new ResourceDescriptor()
            {
                Offset = intermediateResourceDescriptor.FileOffset,
                Size = intermediateResourceDescriptor.Size
            });
        }