Пример #1
0
        private void Init()
        {
            if (LocateMpqHeader() == false)
            {
                throw new MpqParserException("Unable to find MPQ header");
            }

            if (_mpqHeader.HashTableOffsetHigh != 0 || _mpqHeader.ExtendedBlockTableOffset != 0 || _mpqHeader.BlockTableOffsetHigh != 0)
            {
                throw new MpqParserException("MPQ format version 1 features are not supported");
            }

            var reader = new BinaryReader(BaseStream);

            _blockSize = 0x200 << _mpqHeader.BlockSize;

            // Load hash table
            BaseStream.Seek(_mpqHeader.HashTablePos, SeekOrigin.Begin);
            _hashTable = new HashTable(reader, _mpqHeader.HashTableSize);

            // Load entry table
            BaseStream.Seek(_mpqHeader.BlockTablePos, SeekOrigin.Begin);
            _blockTable = new BlockTable(reader, _mpqHeader.BlockTableSize, (uint)_headerOffset);
        }
Пример #2
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);
            }
        }