Esempio n. 1
0
        private void ParseHET()
        {
            Reader.Seek((long)HetTablePos64, SeekOrigin.Begin);

            if (Reader.Read <Media.FourCC>() != new Media.FourCC("HET\x1A"))
            {
                throw new Exception("WTF");
            }

            if (Reader.ReadUInt32() != 1)
            {
                throw new Exception("WTF");
            }

            HetDataSize        = Reader.ReadUInt32();
            HetTableSize       = Reader.ReadUInt32();
            HetMaxFileCount    = Reader.ReadUInt16();
            HetHashTableSize   = Reader.ReadUInt16();
            HetHashEntrySize   = Reader.ReadUInt32();
            HetTotalIndexSize  = Reader.ReadUInt32();
            HetIndexSizeExtra  = Reader.ReadUInt32();
            HetIndexSize       = Reader.ReadUInt32();
            HetBlockTableSize  = Reader.ReadUInt32();
            HetHashTableOffset = Reader.Position;
        }
Esempio n. 2
0
        private void ReadData(Ibasa.IO.BinaryReader reader)
        {
            LowResImage = new SharpIL.Resource(
                new Size3i(LowResImageWidth, LowResImageHeight, 1), 1, 1, EncodingFromFormat(LowResImageFormat));
            HighResImage = new SharpIL.Resource(
                new Size3i(Width, Height, Depth), MipmapCount, Frames * Faces, EncodingFromFormat(ImageFormat));

            if (VersionMinor < 3)
            {
                reader.Read(LowResImage[0, 0], 0, LowResImage[0, 0].Length);

                for (int mip = MipmapCount - 1; mip >= 0; --mip)
                {
                    Size3f size = HighResImage.ComputeMipSliceSize(mip);

                    for (int frame = 0; frame < Frames; ++frame)
                    {
                        for (int face = 0; face < Faces; ++face)
                        {
                            int array = face + (Faces * frame);
                            reader.Read(
                                HighResImage[mip, array], 0,
                                HighResImage[mip, array].Length);
                        }
                    }
                }
            }
            else
            {
                //low res
                int lowResOffset = Resources.Find((resource) => resource.Type == ResourceType.LowResImage).Data;
                reader.Seek((uint)lowResOffset, SeekOrigin.Begin);
                reader.Read(LowResImage[0, 0], 0, LowResImage[0, 0].Length);

                //high res
                int highResOffset = Resources.Find((resource) => resource.Type == ResourceType.Image).Data;
                reader.Seek((uint)highResOffset, SeekOrigin.Begin);

                for (int mip = MipmapCount - 1; mip >= 0; --mip)
                {
                    Size3f size = HighResImage.ComputeMipSliceSize(mip);

                    for (int frame = 0; frame < Frames; ++frame)
                    {
                        for (int face = 0; face < Faces; ++face)
                        {
                            byte[] data = HighResImage[mip, face + (Faces * frame)];
                            reader.Read(data, 0, data.Length);
                        }
                    }
                }
            }
        }
Esempio n. 3
0
        private void ReadData(Ibasa.IO.BinaryReader reader)
        {
            int depth       = (HeaderFlags.HasFlag(HeaderFlagsEnum.Depth) ? Depth : 1);
            int mipmapCount = (HeaderFlags.HasFlag(HeaderFlagsEnum.MipmapCount) ? MipmapCount : 1);

            if (IsDX10Mode)
            {
                int arraySize = (CubemapFlags.HasFlag(CubemapFlagsEnum.Cubemap) ? 6 : 1) * ArraySize;

                Image = new Resource(new Size3i(Width, Height, depth), mipmapCount, arraySize, SelectLoadFormat());

                for (int arraySlice = 0; arraySlice < Image.ArraySize; ++arraySlice)
                {
                    for (int mipSlice = 0; mipSlice < Image.MipLevels; ++mipSlice)
                    {
                        byte[] subresource = Image[mipSlice, arraySlice];
                        reader.Read(subresource, 0, subresource.Length);
                    }
                }
            }
            else if (PixelFlags.HasFlag(PixelFlagsEnum.FourCC))
            {
                int arraySize = (CubemapFlags.HasFlag(CubemapFlagsEnum.Cubemap) ? 6 : 1);

                Image = new Resource(new Size3i(Width, Height, depth), mipmapCount, arraySize, SelectLoadFormat());

                for (int arraySlice = 0; arraySlice < Image.ArraySize; ++arraySlice)
                {
                    for (int mipSlice = 0; mipSlice < Image.MipLevels; ++mipSlice)
                    {
                        byte[] subresource = Image[mipSlice, arraySlice];
                        reader.Read(subresource, 0, subresource.Length);
                    }
                }
            }
        }
Esempio n. 4
0
        private void ReadHeader(Ibasa.IO.BinaryReader reader)
        {
            Header.ImageId      = new byte[reader.ReadByte()];
            Header.ColorMapType = reader.ReadByte();
            Header.ImageType    = reader.ReadByte();

            Header.ColourMapOrigin = reader.ReadUInt16();
            Header.ColorMapLength  = reader.ReadUInt16();
            Header.ColorMapDepth   = reader.ReadByte();

            Header.XOrigin = reader.ReadUInt16();
            Header.YOrigin = reader.ReadUInt16();
            Header.Width   = reader.ReadUInt16();
            Header.Height  = reader.ReadUInt16();

            Header.PixelDepth      = reader.ReadByte();
            Header.ImageDescriptor = reader.ReadByte();

            reader.Read(Header.ImageId, 0, Header.ImageId.Length);
        }
Esempio n. 5
0
File: Mpq.cs Progetto: Frassle/Ibasa
        public Mpq(Stream stream)
        {
            Reader = new Ibasa.IO.BinaryReader(stream, Encoding.ASCII);

            long offset = 0;
            bool founda, foundb;
            {
                Ibasa.Media.FourCC mpqa = new Media.FourCC("MPQ\x1A");
                Ibasa.Media.FourCC mpqb = new Media.FourCC("MPQ\x1B");

                //find offset
                var fourcc = Reader.Read<Ibasa.Media.FourCC>();
                founda = fourcc == mpqa;
                foundb = fourcc == mpqb;

                while (!founda && !foundb)
                {
                    offset += 512;
                    fourcc = Reader.Read<Ibasa.Media.FourCC>();
                    founda = fourcc == mpqa;
                    foundb = fourcc == mpqb;
                }
            }

            if (foundb)
            {
                var userdatasize = Reader.ReadUInt32();
                offset += Reader.ReadUInt32();
                var userdataheader = Reader.ReadUInt32();
            }

            Reader.Seek(offset, SeekOrigin.Begin);

            if (Reader.Read<Media.FourCC>() != new Media.FourCC("MPQ\x1A"))
                throw new Exception("WTF");

            HeaderSize = Reader.ReadUInt32();
            ArchiveSize = Reader.ReadUInt32();
            FormatVersion = Reader.ReadUInt16();
            BlockSize = Reader.ReadUInt16();
            HashTablePos = Reader.ReadUInt32();
            BlockTablePos = Reader.ReadUInt32();
            HashTableSize = Reader.ReadUInt32();
            BlockTableSize = Reader.ReadUInt32();

            if (FormatVersion >= 2)
            {
                HiBlockTablePos64 = Reader.ReadUInt64();
                HashTablePosHi = Reader.ReadUInt16();
                BlockTablePosHi = Reader.ReadUInt16();
            }
            if (FormatVersion >= 3)
            {
                ArchiveSize64 = Reader.ReadUInt64();
                BetTablePos64 = Reader.ReadUInt64();
                HetTablePos64 = Reader.ReadUInt64();
            }
            if (FormatVersion >= 4)
            {
                hashtablesize64 = Reader.ReadUInt64();
                blocktablesize64 = Reader.ReadUInt64();
                hiblocktablesize64 = Reader.ReadUInt64();
                hettablesize64 = Reader.ReadUInt64();
                bettablesize64 = Reader.ReadUInt64();
                dawchunksize = Reader.ReadUInt32();
                md5_blocktable = Reader.ReadBytes(16);
                md5_hashtable = Reader.ReadBytes(16);
                md5_hiblocktable = Reader.ReadBytes(16);
                md5_bettable = Reader.ReadBytes(16);
                md5_hettable = Reader.ReadBytes(16);
                md5_mpqheader = Reader.ReadBytes(16);
            }

            if (HetTablePos64 != 0)
            {
                ParseHET();
            }
            if (BetTablePos64 != 0)
            {
                ParseBET();
            }
        }
Esempio n. 6
0
        public Mpq(Stream stream)
        {
            Reader = new Ibasa.IO.BinaryReader(stream, Encoding.ASCII);

            long offset = 0;
            bool founda, foundb;

            {
                Ibasa.Media.FourCC mpqa = new Media.FourCC("MPQ\x1A");
                Ibasa.Media.FourCC mpqb = new Media.FourCC("MPQ\x1B");

                //find offset
                var fourcc = Reader.Read <Ibasa.Media.FourCC>();
                founda = fourcc == mpqa;
                foundb = fourcc == mpqb;

                while (!founda && !foundb)
                {
                    offset += 512;
                    fourcc  = Reader.Read <Ibasa.Media.FourCC>();
                    founda  = fourcc == mpqa;
                    foundb  = fourcc == mpqb;
                }
            }

            if (foundb)
            {
                var userdatasize = Reader.ReadUInt32();
                offset += Reader.ReadUInt32();
                var userdataheader = Reader.ReadUInt32();
            }

            Reader.Seek(offset, SeekOrigin.Begin);

            if (Reader.Read <Media.FourCC>() != new Media.FourCC("MPQ\x1A"))
            {
                throw new Exception("WTF");
            }

            HeaderSize     = Reader.ReadUInt32();
            ArchiveSize    = Reader.ReadUInt32();
            FormatVersion  = Reader.ReadUInt16();
            BlockSize      = Reader.ReadUInt16();
            HashTablePos   = Reader.ReadUInt32();
            BlockTablePos  = Reader.ReadUInt32();
            HashTableSize  = Reader.ReadUInt32();
            BlockTableSize = Reader.ReadUInt32();

            if (FormatVersion >= 2)
            {
                HiBlockTablePos64 = Reader.ReadUInt64();
                HashTablePosHi    = Reader.ReadUInt16();
                BlockTablePosHi   = Reader.ReadUInt16();
            }
            if (FormatVersion >= 3)
            {
                ArchiveSize64 = Reader.ReadUInt64();
                BetTablePos64 = Reader.ReadUInt64();
                HetTablePos64 = Reader.ReadUInt64();
            }
            if (FormatVersion >= 4)
            {
                hashtablesize64    = Reader.ReadUInt64();
                blocktablesize64   = Reader.ReadUInt64();
                hiblocktablesize64 = Reader.ReadUInt64();
                hettablesize64     = Reader.ReadUInt64();
                bettablesize64     = Reader.ReadUInt64();
                dawchunksize       = Reader.ReadUInt32();
                md5_blocktable     = Reader.ReadBytes(16);
                md5_hashtable      = Reader.ReadBytes(16);
                md5_hiblocktable   = Reader.ReadBytes(16);
                md5_bettable       = Reader.ReadBytes(16);
                md5_hettable       = Reader.ReadBytes(16);
                md5_mpqheader      = Reader.ReadBytes(16);
            }

            if (HetTablePos64 != 0)
            {
                ParseHET();
            }
            if (BetTablePos64 != 0)
            {
                ParseBET();
            }
        }
Esempio n. 7
0
File: Gcf.cs Progetto: Frassle/Ibasa
        public Gcf(Stream stream)
        {
            Reader = new Ibasa.IO.BinaryReader(stream, Encoding.ASCII);

            {
                long seek = Reader.Position;
                uint checksum = Reader.ReadBytes(10 * 4).Aggregate(0U, (sum, value) => sum + value);
                Reader.Position = seek;

                if (Reader.ReadUInt32() != 0x00000001) // HeaderVersion Always 0x00000001
                {
                    throw new InvalidDataException("Header version mismatch.");
                }
                if (Reader.ReadUInt32() != 0x00000001) // MajorVersion Always 0x00000001
                {
                    throw new InvalidDataException("Major version mismatch.");
                }
                var minor = Reader.ReadInt32();
                if (minor != 3 && minor != 5 && minor != 6)
                {
                    throw new InvalidDataException(string.Format("Minor version mismatch, read {0} expected 3, 5 or 6.", minor));
                }

                GCFVersion = new Version(1, minor);
                CacheID = Reader.ReadInt32();
                LastVersionPlayed = Reader.ReadInt32();

                var dummy0 = Reader.ReadUInt32();
                var dummy1 = Reader.ReadUInt32();

                FileSize = Reader.ReadUInt32(); // Total size of GCF file in bytes.
                SectorSize = Reader.ReadUInt32(); // Size of each data block in bytes.
                SectorCount = Reader.ReadUInt32(); // Number of data blocks.
                
                if (checksum != Reader.ReadUInt32())// Header checksum.
                    throw new InvalidDataException("Checksum mismatch.");
            }

            {
                long seek = Reader.Position;
                uint checksum = Reader.Read<uint>(7).Aggregate(0U, (sum, value) => sum + value);
                Reader.Position = seek;

                BlockCount = Reader.ReadUInt32(); // Number of data blocks.
                if (BlockCount != SectorCount)
                {
                    throw new InvalidDataException("BlockCount does not match SectorCount.");
                }

                BlocksUsed = Reader.ReadUInt32(); // Number of data blocks that point to data.

                var dummy0 = Reader.ReadUInt32();
                var dummy1 = Reader.ReadUInt32();
                var dummy2 = Reader.ReadUInt32();
                var dummy3 = Reader.ReadUInt32();
                var dummy4 = Reader.ReadUInt32();

                if (checksum != Reader.ReadUInt32()) // Header checksum.
                    throw new InvalidDataException("Checksum mismatch.");
            }

            BlockEntryOffset = Reader.Position;
            //Seek past block entries
            Reader.Seek(BlockCount * BlockEntry.Size, SeekOrigin.Current);

            { //FragmentationMapHeader
                long seek = Reader.Position;
                uint checksum = Reader.Read<uint>(3).Aggregate(0U, (sum, value) => sum + value);
                Reader.Position = seek;

                uint sectorCount = Reader.ReadUInt32();
                if (SectorCount != sectorCount)
                    throw new InvalidDataException();

                FirstUnusedEntry = Reader.ReadUInt32();
                Terminator = Reader.ReadUInt32() == 0 ? 0x0000ffff : 0xffffffff; 

                if (checksum != Reader.ReadUInt32()) // Header checksum.
                    throw new InvalidDataException("Checksum mismatch.");
            }

            FragmentationMapEntryOffset = Reader.BaseStream.Position;
            //Seek past block entries
            Reader.Seek(BlockCount * 4, SeekOrigin.Current);

            { //BlockMapHeader
                if (GCFVersion.Minor <= 5)
                {
                    uint blockCount = Reader.ReadUInt32();
                    uint firstBlockEntryIndex = Reader.ReadUInt32();
                    uint lastBlockEntryIndex = Reader.ReadUInt32();
                    uint dummy0 = Reader.ReadUInt32();
                    uint checksum = Reader.ReadUInt32();

                    //struct BlockMapEntry
                    //{
                    //    public uint PreviousBlockEntryIndex;	// The previous block entry.  (N/A if == BlockCount.)
                    //    public uint NextBlockEntryIndex;	// The next block entry.  (N/A if == BlockCount.)
                    //}

                    Reader.Seek(blockCount * 8, SeekOrigin.Current);
                }
            }

            { //DirectoryHeader

                if (Reader.ReadUInt32() != 0x00000004) // HeaderVersion Always 0x00000004
                    throw new InvalidDataException("Header version mismatch.");
                if (Reader.ReadUInt32() != CacheID) // CacheID
                    throw new InvalidDataException("CacheID mismatch.");
                if (Reader.ReadUInt32() != LastVersionPlayed) // LastVersionPlayed
                    throw new InvalidDataException("LastVersionPlayed mismatch.");

                ItemCount = Reader.ReadUInt32(); //public uint ItemCount;	// Number of items in the directory.	
                FileCount = Reader.ReadUInt32(); //public uint FileCount;	// Number of files in the directory.
                var dummy0 = Reader.ReadUInt32(); 
                DirectorySize = Reader.ReadUInt32(); //public uint DirectorySize;	// Size of lpGCFDirectoryEntries & lpGCFDirectoryNames & lpGCFDirectoryInfo1Entries & lpGCFDirectoryInfo2Entries & lpGCFDirectoryCopyEntries & lpGCFDirectoryLocalEntries in bytes.
                NameSize = Reader.ReadUInt32(); //public uint NameSize;		// Size of the directory names in bytes.
                HashTableKeyCount = Reader.ReadUInt32(); //public uint HashTableKeyCount;	// Number of Info1 entires.
                CopyCount = Reader.ReadUInt32(); //public uint CopyCount;	// Number of files to copy.
                LocalCount = Reader.ReadUInt32(); //public uint LocalCount;	// Number of files to keep local.
                var dummy1 = Reader.ReadUInt32(); 
                var dummy2 = Reader.ReadUInt32();

                var checksum = Reader.ReadUInt32(); // Header checksum never computes
            }

            DirectoryEntryOffset = Reader.BaseStream.Position;
            Reader.Seek(ItemCount * DirectoryEntry.Size, SeekOrigin.Current);

            DirectoryNameOffset = Reader.BaseStream.Position;
            Reader.Seek(NameSize, SeekOrigin.Current);

            DirectoryInfo1EntryOffset = Reader.BaseStream.Position;
            Reader.Seek(HashTableKeyCount * DirectoryInfo1Entry.Size, SeekOrigin.Current);

            DirectoryInfo2EntryOffset = Reader.BaseStream.Position;
            Reader.Seek(ItemCount * DirectoryInfo2Entry.Size, SeekOrigin.Current);

            DirectoryCopyEntryOffset = Reader.BaseStream.Position;
            Reader.Seek(CopyCount * DirectoryCopyEntry.Size, SeekOrigin.Current);

            DirectoryLocalEntryOffset = Reader.BaseStream.Position;
            Reader.Seek(LocalCount * DirectoryLocalEntry.Size, SeekOrigin.Current);

            { //DirectoryMapHeader
                //public uint Dummy0;
                //public uint Dummy1;
                Reader.Seek(8, SeekOrigin.Current);
            }

            DirectoryMapEntryOffset = Reader.BaseStream.Position;
            Reader.Seek(ItemCount * 4, SeekOrigin.Current);

            { //ChecksumHeader ChecksumMapHeader
                if (Reader.ReadUInt32() != 0x00000001) // HeaderVersion Always 0x00000001
                    throw new InvalidDataException();

                ChecksumSize = Reader.ReadUInt32();	// Size of LPGCFCHECKSUMHEADER & LPGCFCHECKSUMMAPHEADER & in bytes.

                if (Reader.ReadUInt32() != 0x14893721) // FormatCode  Always 0x14893721
                    throw new InvalidDataException();
                if (Reader.ReadUInt32() != 0x00000001) // Dummy0  Always 0x00000001
                    throw new InvalidDataException();

                ChecksumItemCount = Reader.ReadUInt32(); // Number of file ID entries.
                ChecksumCount = Reader.ReadUInt32(); // Number of checksums.
            }

            ChecksumMapEntryOffset = Reader.BaseStream.Position;
            Reader.Seek(ChecksumItemCount * ChecksumMapEntry.Size, SeekOrigin.Current);

            ChecksumEntryOffset = Reader.BaseStream.Position;
            Reader.Seek(ChecksumCount * 4, SeekOrigin.Current);

            //Skip past signature
            Reader.Seek(0x80, SeekOrigin.Current);

            if (Reader.ReadUInt32() != LastVersionPlayed) // LastVersionPlayed
                throw new InvalidDataException("LastVersionPlayed mismatch.");

            { //DataHeader
                uint checksum = 0;
                uint sectorCount, sectorSize;

                checksum += (sectorCount = Reader.ReadUInt32());	// Number of data blocks.
                if (SectorCount != sectorCount)
                    throw new InvalidDataException();

                checksum += (sectorSize = Reader.ReadUInt32()); // Size of each data block in bytes.
                if (SectorSize != sectorSize)
                    throw new InvalidDataException();

                checksum += (FirstSectorOffset = Reader.ReadUInt32()); // Offset to first data block.
                checksum += (SectorsUsed = Reader.ReadUInt32()); // Number of data blocks that contain data.

                if (checksum != Reader.ReadUInt32()) //public uint Checksum;		// Header checksum.
                    throw new InvalidDataException();
            }

            for (uint index = 0; index < ItemCount; ++index)
            {
                DirectoryEntry entry = GetDirectoryEntry(index);

                if (entry.ParentIndex == 0xFFFFFFFF)
                {
                    RootDirectory = new GcfDirectoryInfo(this, index);
                    break;
                }
            }
        }
Esempio n. 8
0
 int GetDataBlock(uint blockIndex, uint blockOffset, byte[] buffer, int index, int count)
 {
     Reader.Seek(FirstSectorOffset + blockIndex * SectorSize + blockOffset, SeekOrigin.Begin);
     return(Reader.Read(buffer, index, Math.Min(count, (int)(SectorSize - blockOffset))));
 }
Esempio n. 9
0
        public Gcf(Stream stream)
        {
            Reader = new Ibasa.IO.BinaryReader(stream, Encoding.ASCII);

            {
                long seek     = Reader.Position;
                uint checksum = Reader.ReadBytes(10 * 4).Aggregate(0U, (sum, value) => sum + value);
                Reader.Position = seek;

                if (Reader.ReadUInt32() != 0x00000001) // HeaderVersion Always 0x00000001
                {
                    throw new InvalidDataException("Header version mismatch.");
                }
                if (Reader.ReadUInt32() != 0x00000001) // MajorVersion Always 0x00000001
                {
                    throw new InvalidDataException("Major version mismatch.");
                }
                var minor = Reader.ReadInt32();
                if (minor != 3 && minor != 5 && minor != 6)
                {
                    throw new InvalidDataException(string.Format("Minor version mismatch, read {0} expected 3, 5 or 6.", minor));
                }

                GCFVersion        = new Version(1, minor);
                CacheID           = Reader.ReadInt32();
                LastVersionPlayed = Reader.ReadInt32();

                var dummy0 = Reader.ReadUInt32();
                var dummy1 = Reader.ReadUInt32();

                FileSize    = Reader.ReadUInt32();   // Total size of GCF file in bytes.
                SectorSize  = Reader.ReadUInt32();   // Size of each data block in bytes.
                SectorCount = Reader.ReadUInt32();   // Number of data blocks.

                if (checksum != Reader.ReadUInt32()) // Header checksum.
                {
                    throw new InvalidDataException("Checksum mismatch.");
                }
            }

            {
                long seek     = Reader.Position;
                uint checksum = Reader.Read <uint>(7).Aggregate(0U, (sum, value) => sum + value);
                Reader.Position = seek;

                BlockCount = Reader.ReadUInt32(); // Number of data blocks.
                if (BlockCount != SectorCount)
                {
                    throw new InvalidDataException("BlockCount does not match SectorCount.");
                }

                BlocksUsed = Reader.ReadUInt32(); // Number of data blocks that point to data.

                var dummy0 = Reader.ReadUInt32();
                var dummy1 = Reader.ReadUInt32();
                var dummy2 = Reader.ReadUInt32();
                var dummy3 = Reader.ReadUInt32();
                var dummy4 = Reader.ReadUInt32();

                if (checksum != Reader.ReadUInt32()) // Header checksum.
                {
                    throw new InvalidDataException("Checksum mismatch.");
                }
            }

            BlockEntryOffset = Reader.Position;
            //Seek past block entries
            Reader.Seek(BlockCount * BlockEntry.Size, SeekOrigin.Current);

            { //FragmentationMapHeader
                long seek     = Reader.Position;
                uint checksum = Reader.Read <uint>(3).Aggregate(0U, (sum, value) => sum + value);
                Reader.Position = seek;

                uint sectorCount = Reader.ReadUInt32();
                if (SectorCount != sectorCount)
                {
                    throw new InvalidDataException();
                }

                FirstUnusedEntry = Reader.ReadUInt32();
                Terminator       = Reader.ReadUInt32() == 0 ? 0x0000ffff : 0xffffffff;

                if (checksum != Reader.ReadUInt32()) // Header checksum.
                {
                    throw new InvalidDataException("Checksum mismatch.");
                }
            }

            FragmentationMapEntryOffset = Reader.BaseStream.Position;
            //Seek past block entries
            Reader.Seek(BlockCount * 4, SeekOrigin.Current);

            { //BlockMapHeader
                if (GCFVersion.Minor <= 5)
                {
                    uint blockCount           = Reader.ReadUInt32();
                    uint firstBlockEntryIndex = Reader.ReadUInt32();
                    uint lastBlockEntryIndex  = Reader.ReadUInt32();
                    uint dummy0   = Reader.ReadUInt32();
                    uint checksum = Reader.ReadUInt32();

                    //struct BlockMapEntry
                    //{
                    //    public uint PreviousBlockEntryIndex;	// The previous block entry.  (N/A if == BlockCount.)
                    //    public uint NextBlockEntryIndex;	// The next block entry.  (N/A if == BlockCount.)
                    //}

                    Reader.Seek(blockCount * 8, SeekOrigin.Current);
                }
            }

            {                                          //DirectoryHeader
                if (Reader.ReadUInt32() != 0x00000004) // HeaderVersion Always 0x00000004
                {
                    throw new InvalidDataException("Header version mismatch.");
                }
                if (Reader.ReadUInt32() != CacheID) // CacheID
                {
                    throw new InvalidDataException("CacheID mismatch.");
                }
                if (Reader.ReadUInt32() != LastVersionPlayed) // LastVersionPlayed
                {
                    throw new InvalidDataException("LastVersionPlayed mismatch.");
                }

                ItemCount = Reader.ReadUInt32();         //public uint ItemCount;	// Number of items in the directory.
                FileCount = Reader.ReadUInt32();         //public uint FileCount;	// Number of files in the directory.
                var dummy0 = Reader.ReadUInt32();
                DirectorySize     = Reader.ReadUInt32(); //public uint DirectorySize;	// Size of lpGCFDirectoryEntries & lpGCFDirectoryNames & lpGCFDirectoryInfo1Entries & lpGCFDirectoryInfo2Entries & lpGCFDirectoryCopyEntries & lpGCFDirectoryLocalEntries in bytes.
                NameSize          = Reader.ReadUInt32(); //public uint NameSize;		// Size of the directory names in bytes.
                HashTableKeyCount = Reader.ReadUInt32(); //public uint HashTableKeyCount;	// Number of Info1 entires.
                CopyCount         = Reader.ReadUInt32(); //public uint CopyCount;	// Number of files to copy.
                LocalCount        = Reader.ReadUInt32(); //public uint LocalCount;	// Number of files to keep local.
                var dummy1 = Reader.ReadUInt32();
                var dummy2 = Reader.ReadUInt32();

                var checksum = Reader.ReadUInt32(); // Header checksum never computes
            }

            DirectoryEntryOffset = Reader.BaseStream.Position;
            Reader.Seek(ItemCount * DirectoryEntry.Size, SeekOrigin.Current);

            DirectoryNameOffset = Reader.BaseStream.Position;
            Reader.Seek(NameSize, SeekOrigin.Current);

            DirectoryInfo1EntryOffset = Reader.BaseStream.Position;
            Reader.Seek(HashTableKeyCount * DirectoryInfo1Entry.Size, SeekOrigin.Current);

            DirectoryInfo2EntryOffset = Reader.BaseStream.Position;
            Reader.Seek(ItemCount * DirectoryInfo2Entry.Size, SeekOrigin.Current);

            DirectoryCopyEntryOffset = Reader.BaseStream.Position;
            Reader.Seek(CopyCount * DirectoryCopyEntry.Size, SeekOrigin.Current);

            DirectoryLocalEntryOffset = Reader.BaseStream.Position;
            Reader.Seek(LocalCount * DirectoryLocalEntry.Size, SeekOrigin.Current);

            { //DirectoryMapHeader
                //public uint Dummy0;
                //public uint Dummy1;
                Reader.Seek(8, SeekOrigin.Current);
            }

            DirectoryMapEntryOffset = Reader.BaseStream.Position;
            Reader.Seek(ItemCount * 4, SeekOrigin.Current);

            {                                          //ChecksumHeader ChecksumMapHeader
                if (Reader.ReadUInt32() != 0x00000001) // HeaderVersion Always 0x00000001
                {
                    throw new InvalidDataException();
                }

                ChecksumSize = Reader.ReadUInt32();    // Size of LPGCFCHECKSUMHEADER & LPGCFCHECKSUMMAPHEADER & in bytes.

                if (Reader.ReadUInt32() != 0x14893721) // FormatCode  Always 0x14893721
                {
                    throw new InvalidDataException();
                }
                if (Reader.ReadUInt32() != 0x00000001) // Dummy0  Always 0x00000001
                {
                    throw new InvalidDataException();
                }

                ChecksumItemCount = Reader.ReadUInt32(); // Number of file ID entries.
                ChecksumCount     = Reader.ReadUInt32(); // Number of checksums.
            }

            ChecksumMapEntryOffset = Reader.BaseStream.Position;
            Reader.Seek(ChecksumItemCount * ChecksumMapEntry.Size, SeekOrigin.Current);

            ChecksumEntryOffset = Reader.BaseStream.Position;
            Reader.Seek(ChecksumCount * 4, SeekOrigin.Current);

            //Skip past signature
            Reader.Seek(0x80, SeekOrigin.Current);

            if (Reader.ReadUInt32() != LastVersionPlayed) // LastVersionPlayed
            {
                throw new InvalidDataException("LastVersionPlayed mismatch.");
            }

            { //DataHeader
                uint checksum = 0;
                uint sectorCount, sectorSize;

                checksum += (sectorCount = Reader.ReadUInt32());        // Number of data blocks.
                if (SectorCount != sectorCount)
                {
                    throw new InvalidDataException();
                }

                checksum += (sectorSize = Reader.ReadUInt32()); // Size of each data block in bytes.
                if (SectorSize != sectorSize)
                {
                    throw new InvalidDataException();
                }

                checksum += (FirstSectorOffset = Reader.ReadUInt32()); // Offset to first data block.
                checksum += (SectorsUsed = Reader.ReadUInt32());       // Number of data blocks that contain data.

                if (checksum != Reader.ReadUInt32())                   //public uint Checksum;		// Header checksum.
                {
                    throw new InvalidDataException();
                }
            }

            for (uint index = 0; index < ItemCount; ++index)
            {
                DirectoryEntry entry = GetDirectoryEntry(index);

                if (entry.ParentIndex == 0xFFFFFFFF)
                {
                    RootDirectory = new GcfDirectoryInfo(this, index);
                    break;
                }
            }
        }