Ejemplo n.º 1
0
        public static MpqHeader FromReader(BinaryReader br)
        {
            uint num = br.ReadUInt32();

            if (num != MpqId)
            {
                return(null);
            }
            MpqHeader header2 = new MpqHeader {
                ID             = num,
                DataOffset     = br.ReadUInt32(),
                ArchiveSize    = br.ReadUInt32(),
                MpqVersion     = br.ReadUInt16(),
                BlockSize      = br.ReadUInt16(),
                HashTablePos   = br.ReadUInt32(),
                BlockTablePos  = br.ReadUInt32(),
                HashTableSize  = br.ReadUInt32(),
                BlockTableSize = br.ReadUInt32()
            };
            MpqHeader header = header2;

            if (header.MpqVersion == 1)
            {
                header.ExtendedBlockTableOffset = br.ReadInt64();
                header.HashTableOffsetHigh      = br.ReadInt16();
                header.BlockTableOffsetHigh     = br.ReadInt16();
            }
            return(header);
        }
Ejemplo n.º 2
0
        public static MpqHeader FromReader(BinaryReader br)
        {
            uint id = br.ReadUInt32();

            if (id != MpqId)
            {
                return(null);
            }
            MpqHeader header = new MpqHeader
            {
                ID             = id,
                DataOffset     = br.ReadUInt32(),
                ArchiveSize    = br.ReadUInt32(),
                MpqVersion     = br.ReadUInt16(),
                BlockSize      = br.ReadUInt16(),
                HashTablePos   = br.ReadUInt32(),
                BlockTablePos  = br.ReadUInt32(),
                HashTableSize  = br.ReadUInt32(),
                BlockTableSize = br.ReadUInt32(),
            };

#if DEBUG
            if (header.MpqVersion == 0)
            {
                // Check validity
                if (Size != header.DataOffset)
                {
                    throw new MpqParserException(string.Format("Invalid MPQ header field: DataOffset. Expected {0}, was {1}", Size, header.DataOffset));
                }

                if (header.ArchiveSize != header.BlockTablePos + MpqEntry.Size * header.BlockTableSize)
                {
                    throw new MpqParserException(string.Format("Invalid MPQ header field: ArchiveSize. Was {0}, expected {1}", header.ArchiveSize, header.BlockTablePos + MpqEntry.Size * header.BlockTableSize));
                }
                if (header.HashTablePos != header.ArchiveSize - MpqHash.Size * header.HashTableSize - MpqEntry.Size * header.BlockTableSize)
                {
                    throw new MpqParserException(string.Format("Invalid MPQ header field: HashTablePos. Was {0}, expected {1}", header.HashTablePos, header.ArchiveSize - MpqHash.Size * header.HashTableSize - MpqEntry.Size * header.BlockTableSize));
                }
                if (header.BlockTablePos != header.HashTablePos + MpqHash.Size * header.HashTableSize)
                {
                    throw new MpqParserException(string.Format("Invalid MPQ header field: BlockTablePos. Was {0}, expected {1}", header.BlockTablePos, header.HashTablePos + MpqHash.Size * header.HashTableSize));
                }
            }
#endif

            if (header.MpqVersion == 1)
            {
                header.ExtendedBlockTableOffset = br.ReadInt64();
                header.HashTableOffsetHigh      = br.ReadInt16();
                header.BlockTableOffsetHigh     = br.ReadInt16();
            }

            return(header);
        }
Ejemplo n.º 3
0
        private bool LocateMpqHeader()
        {
            BinaryReader br = new BinaryReader(this.BaseStream);

            for (long i = 0L; i < (this.BaseStream.Length - MpqHeader.Size); i += 0x200L)
            {
                this.BaseStream.Seek(i, SeekOrigin.Begin);
                this._mpqHeader = MpqHeader.FromReader(br);
                if (this._mpqHeader != null)
                {
                    this._headerOffset = i;
                    this._mpqHeader.SetHeaderOffset(this._headerOffset);
                    return(true);
                }
            }
            return(false);
        }
Ejemplo n.º 4
0
        private bool LocateMpqHeader()
        {
            BinaryReader br = new BinaryReader(BaseStream);

            // In .mpq files the header will be at the start of the file
            // In .exe files, it will be at a multiple of 0x200
            for (long i = 0; i < BaseStream.Length - MpqHeader.Size; i += 0x200)
            {
                BaseStream.Seek(i, SeekOrigin.Begin);
                _mpqHeader = MpqHeader.FromReader(br);
                if (_mpqHeader != null)
                {
                    _headerOffset = i;
                    _mpqHeader.SetHeaderOffset(_headerOffset);
                    return(true);
                }
            }
            return(false);
        }
Ejemplo n.º 5
0
        private void Build(ICollection <MpqFile> mpqFiles, ushort?hashTableSize, ushort blockSize)
        {
            _blockSize = 0x200 << blockSize;

            var fileCount = (uint)mpqFiles.Count;

            _hashTable  = new HashTable(Math.Max(hashTableSize ?? fileCount * 8, fileCount));
            _blockTable = new BlockTable(fileCount);

            using (var writer = new BinaryWriter(BaseStream, new UTF8Encoding(false, true), true))
            {
                // Skip the MPQ header, since its contents will be calculated afterwards.
                writer.Seek((int)MpqHeader.Size, SeekOrigin.Current);

                const bool archiveBeforeTables = true;
                uint       hashTableEntries    = 0;

                // Write Archive
                var fileIndex  = (uint)0;
                var fileOffset = archiveBeforeTables ? MpqHeader.Size : throw new NotImplementedException();
                var filePos    = fileOffset;
                // TODO: add support for encryption of the archive files
                foreach (var mpqFile in mpqFiles)
                {
                    uint locale = 0;
                    mpqFile.AddToArchive((uint)_headerOffset, fileIndex, filePos, locale, _hashTable.Mask);

                    if (archiveBeforeTables)
                    {
                        mpqFile.WriteToStream(writer);
                    }

                    hashTableEntries += _hashTable.Add(mpqFile.MpqHash, mpqFile.HashIndex, mpqFile.HashCollisions);
                    _blockTable.Add(mpqFile.MpqEntry);

                    filePos += mpqFile.MpqEntry.CompressedSize;
                    fileIndex++;
                }

                // Match size of blocktable with amount of occupied entries in hashtable

                /*
                 * for ( var i = blockTable.Size; i < hashTableEntries; i++ )
                 * {
                 *  var entry = MpqEntry.Dummy;
                 *  entry.SetPos( filePos );
                 *  blockTable.Add( entry );
                 * }
                 * blockTable.UpdateSize();
                 */

                _hashTable.WriteToStream(writer);
                _blockTable.WriteToStream(writer);

                if (!archiveBeforeTables)
                {
                    foreach (var mpqFile in mpqFiles)
                    {
                        mpqFile.WriteToStream(writer);
                    }
                }

                writer.Seek((int)_headerOffset, SeekOrigin.Begin);

                _mpqHeader = new MpqHeader(filePos - fileOffset, _hashTable.Size, _blockTable.Size, blockSize, archiveBeforeTables);
                _mpqHeader.WriteToStream(writer);
            }
        }