stormlib 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/stormlib/StormLib/CMakeFiles/3.22.1/CMakeCCompiler.cmake +72 -0
- data/ext/stormlib/StormLib/CMakeFiles/3.22.1/CMakeCXXCompiler.cmake +83 -0
- data/ext/stormlib/StormLib/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_C.bin +0 -0
- data/ext/stormlib/StormLib/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_CXX.bin +0 -0
- data/ext/stormlib/StormLib/CMakeFiles/3.22.1/CMakeSystem.cmake +15 -0
- data/ext/stormlib/StormLib/CMakeFiles/3.22.1/CompilerIdC/CMakeCCompilerId.c +803 -0
- data/ext/stormlib/StormLib/CMakeFiles/3.22.1/CompilerIdC/a.out +0 -0
- data/ext/stormlib/StormLib/CMakeFiles/3.22.1/CompilerIdCXX/CMakeCXXCompilerId.cpp +791 -0
- data/ext/stormlib/StormLib/CMakeFiles/3.22.1/CompilerIdCXX/a.out +0 -0
- data/ext/stormlib/StormLib/CMakeFiles/CMakeDirectoryInformation.cmake +16 -0
- data/ext/stormlib/StormLib/CMakeFiles/CMakeOutput.log +478 -0
- data/ext/stormlib/StormLib/CMakeFiles/Export/share/StormLib/StormLibConfig-noconfig.cmake +19 -0
- data/ext/stormlib/StormLib/CMakeFiles/Export/share/StormLib/StormLibConfig.cmake +99 -0
- data/ext/stormlib/StormLib/CMakeFiles/Makefile.cmake +61 -0
- data/ext/stormlib/StormLib/CMakeFiles/Makefile2 +112 -0
- data/ext/stormlib/StormLib/CMakeFiles/TargetDirectories.txt +9 -0
- data/ext/stormlib/StormLib/CMakeFiles/cmake.check_cache +1 -0
- data/ext/stormlib/StormLib/CMakeFiles/progress.marks +1 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/DependInfo.cmake +243 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/build.make +3695 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/cmake_clean.cmake +459 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/cmake_clean_target.cmake +3 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/compiler_depend.make +2 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/compiler_depend.ts +2 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/depend.make +2 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/flags.make +17 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/link.txt +2 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/progress.make +227 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/FileStream.cpp.o.d +160 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SBaseCommon.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SBaseDumpData.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SBaseFileTable.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SBaseSubTypes.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SCompression.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SFileAddFile.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SFileAttributes.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SFileCompactArchive.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SFileCreateArchive.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SFileExtractFile.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SFileFindFile.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SFileGetFileInfo.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SFileListFile.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SFileOpenArchive.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SFileOpenFileEx.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SFilePatchArchives.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SFileReadFile.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/SFileVerify.cpp.o.d +159 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/adpcm/adpcm.cpp.o.d +12 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/huffman/huff.cpp.o.d +16 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/jenkins/lookup3.c.o.d +88 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/hashes/hash_memory.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/hashes/md5.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/hashes/sha1.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/hashes/sha256.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/math/ltm_desc.c.o.d +105 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/math/multi.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/math/rand_prime.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/misc/base64_decode.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/misc/crypt_argchk.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/misc/crypt_find_hash.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/misc/crypt_find_prng.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/misc/crypt_hash_descriptor.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/misc/crypt_hash_is_valid.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/misc/crypt_libc.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/misc/crypt_ltc_mp_descriptor.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/misc/crypt_prng_descriptor.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/misc/crypt_prng_is_valid.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/misc/crypt_register_hash.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/misc/crypt_register_prng.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/misc/zeromem.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_decode_bit_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_decode_boolean.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_decode_choice.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_decode_ia5_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_decode_integer.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_decode_object_identifier.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_decode_octet_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_decode_printable_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_decode_sequence_ex.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_decode_sequence_flexi.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_decode_sequence_multi.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_decode_short_integer.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_decode_utctime.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_decode_utf8_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_encode_bit_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_encode_boolean.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_encode_ia5_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_encode_integer.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_encode_object_identifier.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_encode_octet_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_encode_printable_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_encode_sequence_ex.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_encode_sequence_multi.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_encode_set.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_encode_setof.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_encode_short_integer.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_encode_utctime.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_encode_utf8_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_length_bit_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_length_boolean.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_length_ia5_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_length_integer.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_length_object_identifier.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_length_octet_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_length_printable_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_length_sequence.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_length_short_integer.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_length_utctime.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_length_utf8_string.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/asn1/der_sequence_free.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/ecc/ltc_ecc_map.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/ecc/ltc_ecc_mul2add.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/ecc/ltc_ecc_points.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/ecc/ltc_ecc_projective_add_point.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/ecc/ltc_ecc_projective_dbl_point.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/pkcs1/pkcs_1_mgf1.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_decode.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_decode.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_encode.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_decode.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_encode.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/rsa/rsa_exptmod.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/rsa/rsa_free.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/rsa/rsa_import.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/rsa/rsa_make_key.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/rsa/rsa_sign_hash.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/rsa/rsa_verify_hash.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtomcrypt/src/pk/rsa/rsa_verify_simple.c.o.d +102 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_fast_mp_invmod.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_fast_mp_montgomery_reduce.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_fast_s_mp_mul_digs.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_fast_s_mp_mul_high_digs.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_fast_s_mp_sqr.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_2expt.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_abs.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_add.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_add_d.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_addmod.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_and.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_clamp.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_clear.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_clear_multi.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_cmp.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_cmp_d.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_cmp_mag.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_cnt_lsb.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_copy.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_count_bits.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_div.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_div_2.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_div_2d.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_div_3.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_div_d.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_dr_is_modulus.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_dr_reduce.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_dr_setup.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_exch.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_expt_d.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_exptmod.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_exptmod_fast.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_exteuclid.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_fread.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_fwrite.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_gcd.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_get_int.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_grow.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_init.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_init_copy.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_init_multi.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_init_set.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_init_set_int.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_init_size.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_invmod.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_invmod_slow.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_is_square.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_jacobi.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_karatsuba_mul.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_karatsuba_sqr.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_lcm.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_lshd.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_mod.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_mod_2d.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_mod_d.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_montgomery_calc_normalization.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_montgomery_reduce.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_montgomery_setup.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_mul.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_mul_2.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_mul_2d.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_mul_d.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_mulmod.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_n_root.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_neg.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_or.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_prime_fermat.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_prime_is_divisible.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_prime_is_prime.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_prime_miller_rabin.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_prime_next_prime.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_prime_rabin_miller_trials.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_prime_random_ex.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_radix_size.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_radix_smap.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_rand.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_read_radix.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_read_signed_bin.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_read_unsigned_bin.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_reduce.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_reduce_2k.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_reduce_2k_l.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_reduce_2k_setup.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_reduce_2k_setup_l.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_reduce_is_2k.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_reduce_is_2k_l.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_reduce_setup.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_rshd.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_set.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_set_int.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_shrink.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_signed_bin_size.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_sqr.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_sqrmod.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_sqrt.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_sub.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_sub_d.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_submod.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_to_signed_bin.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_to_signed_bin_n.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_to_unsigned_bin.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_to_unsigned_bin_n.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_toom_mul.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_toom_sqr.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_toradix.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_toradix_n.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_unsigned_bin_size.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_xor.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_mp_zero.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_prime_tab.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_reverse.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_s_mp_add.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_s_mp_exptmod.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_s_mp_mul_digs.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_s_mp_mul_high_digs.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_s_mp_sqr.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bn_s_mp_sub.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/libtommath/bncore.c.o.d +65 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/lzma/C/LzFind.c.o.d +18 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/lzma/C/LzmaDec.c.o.d +17 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/lzma/C/LzmaEnc.c.o.d +18 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/pklib/explode.c.o.d +16 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/pklib/implode.c.o.d +23 -0
- data/ext/stormlib/StormLib/CMakeFiles/storm.dir/src/sparse/sparse.cpp.o.d +16 -0
- data/ext/stormlib/StormLib/CMakeLists.txt +418 -0
- data/ext/stormlib/StormLib/Info.plist +22 -0
- data/ext/stormlib/StormLib/LICENSE +21 -0
- data/ext/stormlib/StormLib/Premake5.lua +132 -0
- data/ext/stormlib/StormLib/README.md +39 -0
- data/ext/stormlib/StormLib/StormLib.sln +162 -0
- data/ext/stormlib/StormLib/StormLib.vcxproj +1024 -0
- data/ext/stormlib/StormLib/StormLib.vcxproj.filters +221 -0
- data/ext/stormlib/StormLib/StormLib.xcodeproj/project.pbxproj +2104 -0
- data/ext/stormlib/StormLib/StormLib_dll.vcxproj +348 -0
- data/ext/stormlib/StormLib/StormLib_dll.vcxproj.filters +229 -0
- data/ext/stormlib/StormLib/StormLib_test.vcxproj +360 -0
- data/ext/stormlib/StormLib/StormLib_test.vcxproj.filters +230 -0
- data/ext/stormlib/StormLib/StormLib_vs08.sln +139 -0
- data/ext/stormlib/StormLib/StormLib_vs08.vcproj +4205 -0
- data/ext/stormlib/StormLib/StormLib_vs08_dll.vcproj +1851 -0
- data/ext/stormlib/StormLib/StormLib_vs08_test.vcproj +1289 -0
- data/ext/stormlib/StormLib/doc/History.txt +78 -0
- data/ext/stormlib/StormLib/doc/The MoPaQ File Format 0.9.txt +318 -0
- data/ext/stormlib/StormLib/doc/The MoPaQ File Format 1.0.txt +433 -0
- data/ext/stormlib/StormLib/doc/d3-authenticationcode/d3-authenticationcode-deDE.txt +1 -0
- data/ext/stormlib/StormLib/doc/d3-authenticationcode/d3-authenticationcode-enGB.txt +1 -0
- data/ext/stormlib/StormLib/doc/d3-authenticationcode/d3-authenticationcode-enSG.txt +1 -0
- data/ext/stormlib/StormLib/doc/d3-authenticationcode/d3-authenticationcode-enUS.txt +1 -0
- data/ext/stormlib/StormLib/doc/d3-authenticationcode/d3-authenticationcode-esES.txt +1 -0
- data/ext/stormlib/StormLib/doc/d3-authenticationcode/d3-authenticationcode-esMX.txt +1 -0
- data/ext/stormlib/StormLib/doc/d3-authenticationcode/d3-authenticationcode-frFR.txt +1 -0
- data/ext/stormlib/StormLib/doc/d3-authenticationcode/d3-authenticationcode-itIT.txt +1 -0
- data/ext/stormlib/StormLib/doc/d3-authenticationcode/d3-authenticationcode-koKR.txt +1 -0
- data/ext/stormlib/StormLib/doc/d3-authenticationcode/d3-authenticationcode-plPL.txt +1 -0
- data/ext/stormlib/StormLib/doc/d3-authenticationcode/d3-authenticationcode-ptBR.txt +1 -0
- data/ext/stormlib/StormLib/doc/d3-authenticationcode/d3-authenticationcode-zhTW.txt +1 -0
- data/ext/stormlib/StormLib/doc/hots-authenticationcode/hots-authenticationcode-bgdl.txt +1 -0
- data/ext/stormlib/StormLib/doc/sc2-authenticationcode/sc2-authenticationcode-deDE.txt +1 -0
- data/ext/stormlib/StormLib/doc/sc2-authenticationcode/sc2-authenticationcode-enGB.txt +1 -0
- data/ext/stormlib/StormLib/doc/sc2-authenticationcode/sc2-authenticationcode-enUS.txt +1 -0
- data/ext/stormlib/StormLib/doc/sc2-authenticationcode/sc2-authenticationcode-esES.txt +1 -0
- data/ext/stormlib/StormLib/doc/sc2-authenticationcode/sc2-authenticationcode-esMX.txt +1 -0
- data/ext/stormlib/StormLib/doc/sc2-authenticationcode/sc2-authenticationcode-frFR.txt +1 -0
- data/ext/stormlib/StormLib/doc/sc2-authenticationcode/sc2-authenticationcode-itIT.txt +1 -0
- data/ext/stormlib/StormLib/doc/sc2-authenticationcode/sc2-authenticationcode-koKR.txt +1 -0
- data/ext/stormlib/StormLib/doc/sc2-authenticationcode/sc2-authenticationcode-plPL.txt +1 -0
- data/ext/stormlib/StormLib/doc/sc2-authenticationcode/sc2-authenticationcode-ptBR.txt +1 -0
- data/ext/stormlib/StormLib/doc/sc2-authenticationcode/sc2-authenticationcode-ruRU.txt +1 -0
- data/ext/stormlib/StormLib/doc/sc2-authenticationcode/sc2-authenticationcode-zhTW.txt +1 -0
- data/ext/stormlib/StormLib/make-msvc.bat +95 -0
- data/ext/stormlib/StormLib/make.bat +46 -0
- data/ext/stormlib/StormLib/sources +14 -0
- data/ext/stormlib/StormLib/src/DllMain.c +24 -0
- data/ext/stormlib/StormLib/src/DllMain.def +79 -0
- data/ext/stormlib/StormLib/src/DllMain.rc +110 -0
- data/ext/stormlib/StormLib/src/FileStream.cpp +2928 -0
- data/ext/stormlib/StormLib/src/FileStream.h +217 -0
- data/ext/stormlib/StormLib/src/LibTomCrypt.c +85 -0
- data/ext/stormlib/StormLib/src/LibTomMath.c +125 -0
- data/ext/stormlib/StormLib/src/LibTomMathDesc.c +4 -0
- data/ext/stormlib/StormLib/src/SBaseCommon.cpp +1970 -0
- data/ext/stormlib/StormLib/src/SBaseDumpData.cpp +183 -0
- data/ext/stormlib/StormLib/src/SBaseFileTable.cpp +3194 -0
- data/ext/stormlib/StormLib/src/SBaseSubTypes.cpp +688 -0
- data/ext/stormlib/StormLib/src/SCompression.cpp +1183 -0
- data/ext/stormlib/StormLib/src/SFileAddFile.cpp +1337 -0
- data/ext/stormlib/StormLib/src/SFileAttributes.cpp +573 -0
- data/ext/stormlib/StormLib/src/SFileCompactArchive.cpp +654 -0
- data/ext/stormlib/StormLib/src/SFileCreateArchive.cpp +285 -0
- data/ext/stormlib/StormLib/src/SFileExtractFile.cpp +64 -0
- data/ext/stormlib/StormLib/src/SFileFindFile.cpp +484 -0
- data/ext/stormlib/StormLib/src/SFileGetFileInfo.cpp +627 -0
- data/ext/stormlib/StormLib/src/SFileListFile.cpp +750 -0
- data/ext/stormlib/StormLib/src/SFileOpenArchive.cpp +723 -0
- data/ext/stormlib/StormLib/src/SFileOpenFileEx.cpp +423 -0
- data/ext/stormlib/StormLib/src/SFilePatchArchives.cpp +1175 -0
- data/ext/stormlib/StormLib/src/SFileReadFile.cpp +922 -0
- data/ext/stormlib/StormLib/src/SFileVerify.cpp +1059 -0
- data/ext/stormlib/StormLib/src/StormCommon.h +450 -0
- data/ext/stormlib/StormLib/src/StormLib.exp +74 -0
- data/ext/stormlib/StormLib/src/StormLib.h +1157 -0
- data/ext/stormlib/StormLib/src/StormPort.h +474 -0
- data/ext/stormlib/StormLib/src/adpcm/adpcm.cpp +539 -0
- data/ext/stormlib/StormLib/src/adpcm/adpcm.h +27 -0
- data/ext/stormlib/StormLib/src/bzip2/blocksort.c +1094 -0
- data/ext/stormlib/StormLib/src/bzip2/bzlib.c +1573 -0
- data/ext/stormlib/StormLib/src/bzip2/bzlib.h +282 -0
- data/ext/stormlib/StormLib/src/bzip2/bzlib_private.h +509 -0
- data/ext/stormlib/StormLib/src/bzip2/compress.c +672 -0
- data/ext/stormlib/StormLib/src/bzip2/crctable.c +104 -0
- data/ext/stormlib/StormLib/src/bzip2/decompress.c +626 -0
- data/ext/stormlib/StormLib/src/bzip2/huffman.c +205 -0
- data/ext/stormlib/StormLib/src/bzip2/randtable.c +84 -0
- data/ext/stormlib/StormLib/src/huffman/huff.cpp +915 -0
- data/ext/stormlib/StormLib/src/huffman/huff.h +143 -0
- data/ext/stormlib/StormLib/src/jenkins/lookup.h +24 -0
- data/ext/stormlib/StormLib/src/jenkins/lookup3.c +1003 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/hashes/hash_memory.c +69 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/hashes/md5.c +368 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/hashes/sha1.c +288 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/hashes/sha256.c +340 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/headers/tomcrypt.h +91 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/headers/tomcrypt_argchk.h +38 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/headers/tomcrypt_cfg.h +144 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/headers/tomcrypt_cipher.h +891 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/headers/tomcrypt_custom.h +424 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/headers/tomcrypt_hash.h +378 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/headers/tomcrypt_mac.h +384 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/headers/tomcrypt_macros.h +424 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/headers/tomcrypt_math.h +500 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/headers/tomcrypt_misc.h +23 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/headers/tomcrypt_pk.h +558 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/headers/tomcrypt_pkcs.h +89 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/headers/tomcrypt_prng.h +199 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/math/ltm_desc.c +483 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/math/multi.c +61 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/math/rand_prime.c +87 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/misc/base64_decode.c +104 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/misc/crypt_argchk.c +30 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/misc/crypt_find_hash.c +40 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/misc/crypt_find_prng.c +41 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/misc/crypt_hash_descriptor.c +27 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/misc/crypt_hash_is_valid.c +36 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/misc/crypt_libc.c +43 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/misc/crypt_ltc_mp_descriptor.c +13 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/misc/crypt_prng_descriptor.c +26 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/misc/crypt_prng_is_valid.c +36 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/misc/crypt_register_hash.c +54 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/misc/crypt_register_prng.c +54 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/misc/zeromem.c +34 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_bit_string.c +102 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_boolean.c +47 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_choice.c +182 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_ia5_string.c +96 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_integer.c +110 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_object_identifier.c +99 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_octet_string.c +91 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_printable_string.c +96 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_ex.c +287 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_flexi.c +386 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_multi.c +139 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_short_integer.c +68 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_utctime.c +127 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_utf8_string.c +111 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_encode_bit_string.c +89 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_encode_boolean.c +51 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_encode_ia5_string.c +85 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_encode_integer.c +130 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_encode_object_identifier.c +111 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_encode_octet_string.c +86 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_encode_printable_string.c +85 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_encode_sequence_ex.c +335 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_encode_sequence_multi.c +138 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_encode_set.c +103 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_encode_setof.c +162 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_encode_short_integer.c +97 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_encode_utctime.c +83 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_encode_utf8_string.c +105 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_length_bit_string.c +54 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_length_boolean.c +35 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_length_ia5_string.c +194 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_length_integer.c +82 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_length_object_identifier.c +89 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_length_octet_string.c +53 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_length_printable_string.c +166 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_length_sequence.c +169 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_length_short_integer.c +70 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_length_utctime.c +46 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_length_utf8_string.c +83 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/asn1/der_sequence_free.c +65 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_map.c +76 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_mul2add.c +207 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod.c +222 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_points.c +60 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_projective_add_point.c +196 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_projective_dbl_point.c +147 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_mgf1.c +108 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_decode.c +189 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_decode.c +177 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_encode.c +175 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_decode.c +110 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_encode.c +111 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/rsa/rsa_exptmod.c +113 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/rsa/rsa_free.c +34 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/rsa/rsa_import.c +143 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/rsa/rsa_make_key.c +112 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/rsa/rsa_sign_hash.c +134 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/rsa/rsa_verify_hash.c +167 -0
- data/ext/stormlib/StormLib/src/libtomcrypt/src/pk/rsa/rsa_verify_simple.c +87 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_fast_mp_invmod.c +148 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_fast_mp_montgomery_reduce.c +172 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_fast_s_mp_mul_digs.c +107 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_fast_s_mp_mul_high_digs.c +98 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_fast_s_mp_sqr.c +114 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_2expt.c +48 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_abs.c +43 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_add.c +53 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_add_d.c +112 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_addmod.c +41 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_and.c +57 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_clamp.c +44 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_clear.c +44 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_clear_multi.c +34 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_cmp.c +43 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_cmp_d.c +44 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_cmp_mag.c +55 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_cnt_lsb.c +53 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_copy.c +68 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_count_bits.c +45 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_div.c +292 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_div_2.c +68 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_div_2d.c +97 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_div_3.c +79 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_div_d.c +115 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_dr_is_modulus.c +43 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_dr_reduce.c +94 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_dr_setup.c +32 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_exch.c +34 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_expt_d.c +57 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_exptmod.c +112 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_exptmod_fast.c +321 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_exteuclid.c +82 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_fread.c +67 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_fwrite.c +52 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_gcd.c +105 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_get_int.c +45 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_grow.c +57 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_init.c +46 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_init_copy.c +32 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_init_multi.c +59 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_init_set.c +32 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_init_set_int.c +31 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_init_size.c +48 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_invmod.c +43 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_invmod_slow.c +175 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_is_square.c +109 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_jacobi.c +105 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_karatsuba_mul.c +167 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_karatsuba_sqr.c +121 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_lcm.c +60 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_lshd.c +67 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_mod.c +48 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_mod_2d.c +55 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_mod_d.c +27 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_montgomery_calc_normalization.c +59 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_montgomery_reduce.c +118 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_montgomery_setup.c +59 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_mul.c +66 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_mul_2.c +82 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_mul_2d.c +85 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_mul_d.c +79 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_mulmod.c +40 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_n_root.c +132 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_neg.c +40 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_or.c +50 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_prime_fermat.c +62 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_prime_is_divisible.c +50 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_prime_is_prime.c +83 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_prime_miller_rabin.c +103 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_prime_next_prime.c +170 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_prime_rabin_miller_trials.c +52 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_prime_random_ex.c +125 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_radix_size.c +78 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_radix_smap.c +24 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_rand.c +55 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_read_radix.c +85 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_read_signed_bin.c +41 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_read_unsigned_bin.c +55 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_reduce.c +100 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_reduce_2k.c +61 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_reduce_2k_l.c +62 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_reduce_2k_setup.c +47 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_reduce_2k_setup_l.c +44 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_reduce_is_2k.c +52 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_reduce_is_2k_l.c +44 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_reduce_setup.c +34 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_rshd.c +72 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_set.c +29 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_set_int.c +48 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_shrink.c +35 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_signed_bin_size.c +27 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_sqr.c +58 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_sqrmod.c +41 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_sqrt.c +81 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_sub.c +59 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_sub_d.c +93 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_submod.c +42 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_to_signed_bin.c +33 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_to_signed_bin_n.c +31 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_to_unsigned_bin.c +48 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_to_unsigned_bin_n.c +31 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_toom_mul.c +284 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_toom_sqr.c +226 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_toradix.c +75 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_toradix_n.c +88 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_unsigned_bin_size.c +28 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_xor.c +51 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_mp_zero.c +36 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_prime_tab.c +61 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_reverse.c +39 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_s_mp_add.c +109 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_s_mp_exptmod.c +252 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_s_mp_mul_digs.c +90 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_s_mp_mul_high_digs.c +81 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_s_mp_sqr.c +84 -0
- data/ext/stormlib/StormLib/src/libtommath/bn_s_mp_sub.c +89 -0
- data/ext/stormlib/StormLib/src/libtommath/bncore.c +36 -0
- data/ext/stormlib/StormLib/src/libtommath/tommath.h +584 -0
- data/ext/stormlib/StormLib/src/libtommath/tommath_class.h +999 -0
- data/ext/stormlib/StormLib/src/libtommath/tommath_superclass.h +76 -0
- data/ext/stormlib/StormLib/src/lzma/C/LzFind.c +761 -0
- data/ext/stormlib/StormLib/src/lzma/C/LzFind.h +115 -0
- data/ext/stormlib/StormLib/src/lzma/C/LzFindMt.c +793 -0
- data/ext/stormlib/StormLib/src/lzma/C/LzFindMt.h +105 -0
- data/ext/stormlib/StormLib/src/lzma/C/LzHash.h +54 -0
- data/ext/stormlib/StormLib/src/lzma/C/LzmaDec.c +999 -0
- data/ext/stormlib/StormLib/src/lzma/C/LzmaDec.h +231 -0
- data/ext/stormlib/StormLib/src/lzma/C/LzmaEnc.c +2268 -0
- data/ext/stormlib/StormLib/src/lzma/C/LzmaEnc.h +80 -0
- data/ext/stormlib/StormLib/src/lzma/C/Threads.c +84 -0
- data/ext/stormlib/StormLib/src/lzma/C/Threads.h +59 -0
- data/ext/stormlib/StormLib/src/lzma/C/Types.h +236 -0
- data/ext/stormlib/StormLib/src/lzma/info.txt +1 -0
- data/ext/stormlib/StormLib/src/pklib/crc32.c +66 -0
- data/ext/stormlib/StormLib/src/pklib/explode.c +521 -0
- data/ext/stormlib/StormLib/src/pklib/implode.c +674 -0
- data/ext/stormlib/StormLib/src/pklib/pklib.h +160 -0
- data/ext/stormlib/StormLib/src/resource.h +15 -0
- data/ext/stormlib/StormLib/src/sparse/sparse.cpp +287 -0
- data/ext/stormlib/StormLib/src/sparse/sparse.h +17 -0
- data/ext/stormlib/StormLib/src/wdk/sources-cpp.cpp +26 -0
- data/ext/stormlib/StormLib/src/wdk/sources-wdk-bzip2.c +13 -0
- data/ext/stormlib/StormLib/src/wdk/sources-wdk-ltc.c +4 -0
- data/ext/stormlib/StormLib/src/wdk/sources-wdk-lzma.c +8 -0
- data/ext/stormlib/StormLib/src/wdk/sources-wdk-misc.c +6 -0
- data/ext/stormlib/StormLib/src/wdk/sources-wdk-tomcrypt.c +82 -0
- data/ext/stormlib/StormLib/src/wdk/sources-wdk-tommath.c +123 -0
- data/ext/stormlib/StormLib/src/wdk/sources-wdk-zlib.c +21 -0
- data/ext/stormlib/StormLib/src/zlib/adler32.c +169 -0
- data/ext/stormlib/StormLib/src/zlib/compress.c +80 -0
- data/ext/stormlib/StormLib/src/zlib/compress_zlib.c +5 -0
- data/ext/stormlib/StormLib/src/zlib/crc32.c +442 -0
- data/ext/stormlib/StormLib/src/zlib/crc32.h +441 -0
- data/ext/stormlib/StormLib/src/zlib/deflate.c +1834 -0
- data/ext/stormlib/StormLib/src/zlib/deflate.h +342 -0
- data/ext/stormlib/StormLib/src/zlib/gzguts.h +218 -0
- data/ext/stormlib/StormLib/src/zlib/inffast.c +340 -0
- data/ext/stormlib/StormLib/src/zlib/inffast.h +11 -0
- data/ext/stormlib/StormLib/src/zlib/inffixed.h +94 -0
- data/ext/stormlib/StormLib/src/zlib/inflate.c +1480 -0
- data/ext/stormlib/StormLib/src/zlib/inflate.h +130 -0
- data/ext/stormlib/StormLib/src/zlib/inftrees.c +330 -0
- data/ext/stormlib/StormLib/src/zlib/inftrees.h +67 -0
- data/ext/stormlib/StormLib/src/zlib/trees.c +1244 -0
- data/ext/stormlib/StormLib/src/zlib/trees.h +128 -0
- data/ext/stormlib/StormLib/src/zlib/zconf.h +428 -0
- data/ext/stormlib/StormLib/src/zlib/zlib.h +1613 -0
- data/ext/stormlib/StormLib/src/zlib/zutil.c +318 -0
- data/ext/stormlib/StormLib/src/zlib/zutil.h +274 -0
- data/ext/stormlib/StormLib/storm_dll/storm.cpp +117 -0
- data/ext/stormlib/StormLib/storm_dll/storm.def +25 -0
- data/ext/stormlib/StormLib/storm_dll/storm.h +65 -0
- data/ext/stormlib/StormLib/storm_dll/storm.vcxproj +209 -0
- data/ext/stormlib/StormLib/storm_dll/storm.vcxproj.filters +28 -0
- data/ext/stormlib/StormLib/storm_dll/storm_test.cpp +182 -0
- data/ext/stormlib/StormLib/storm_dll/storm_test.vcxproj +202 -0
- data/ext/stormlib/StormLib/storm_dll/storm_test.vcxproj.filters +22 -0
- data/ext/stormlib/StormLib/test/StormTest.cpp +4393 -0
- data/ext/stormlib/StormLib/test/TLogHelper.cpp +567 -0
- data/ext/stormlib/StormLib/test/stormlib-test-001.txt +164 -0
- data/ext/stormlib/extconf.rb +0 -2
- data/lib/stormlib/version.rb +1 -1
- data/stormlib.gemspec +1 -1
- metadata +621 -2
|
@@ -0,0 +1,3194 @@
|
|
|
1
|
+
/*****************************************************************************/
|
|
2
|
+
/* SBaseFileTable.cpp Copyright (c) Ladislav Zezula 2010 */
|
|
3
|
+
/*---------------------------------------------------------------------------*/
|
|
4
|
+
/* Description: Common handler for classic and new hash&block tables */
|
|
5
|
+
/*---------------------------------------------------------------------------*/
|
|
6
|
+
/* Date Ver Who Comment */
|
|
7
|
+
/* -------- ---- --- ------- */
|
|
8
|
+
/* 06.09.10 1.00 Lad The first version of SBaseFileTable.cpp */
|
|
9
|
+
/*****************************************************************************/
|
|
10
|
+
|
|
11
|
+
#define __STORMLIB_SELF__
|
|
12
|
+
#include "StormLib.h"
|
|
13
|
+
#include "StormCommon.h"
|
|
14
|
+
|
|
15
|
+
//-----------------------------------------------------------------------------
|
|
16
|
+
// Local defines
|
|
17
|
+
|
|
18
|
+
#define INVALID_FLAG_VALUE 0xCCCCCCCC
|
|
19
|
+
#define MAX_FLAG_INDEX 512
|
|
20
|
+
|
|
21
|
+
//-----------------------------------------------------------------------------
|
|
22
|
+
// Support for calculating bit sizes
|
|
23
|
+
|
|
24
|
+
static void InitFileFlagArray(LPDWORD FlagArray)
|
|
25
|
+
{
|
|
26
|
+
memset(FlagArray, 0xCC, MAX_FLAG_INDEX * sizeof(DWORD));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static DWORD GetFileFlagIndex(LPDWORD FlagArray, DWORD dwFlags)
|
|
30
|
+
{
|
|
31
|
+
// Find free or equal entry in the flag array
|
|
32
|
+
for(DWORD dwFlagIndex = 0; dwFlagIndex < MAX_FLAG_INDEX; dwFlagIndex++)
|
|
33
|
+
{
|
|
34
|
+
if(FlagArray[dwFlagIndex] == INVALID_FLAG_VALUE || FlagArray[dwFlagIndex] == dwFlags)
|
|
35
|
+
{
|
|
36
|
+
FlagArray[dwFlagIndex] = dwFlags;
|
|
37
|
+
return dwFlagIndex;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// This should never happen
|
|
42
|
+
assert(false);
|
|
43
|
+
return 0xFFFFFFFF;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static DWORD GetNecessaryBitCount(ULONGLONG MaxValue)
|
|
47
|
+
{
|
|
48
|
+
DWORD dwBitCount = 0;
|
|
49
|
+
|
|
50
|
+
while(MaxValue > 0)
|
|
51
|
+
{
|
|
52
|
+
MaxValue >>= 1;
|
|
53
|
+
dwBitCount++;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return dwBitCount;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//-----------------------------------------------------------------------------
|
|
60
|
+
// Implementation of the TMPQBits struct
|
|
61
|
+
|
|
62
|
+
struct TMPQBits
|
|
63
|
+
{
|
|
64
|
+
static TMPQBits * Create(DWORD NumberOfBits, BYTE FillValue);
|
|
65
|
+
|
|
66
|
+
DWORD GetBits(unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, unsigned int nResultSize);
|
|
67
|
+
DWORD SetBits(unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, unsigned int nResultSize);
|
|
68
|
+
|
|
69
|
+
static const USHORT SetBitsMask[]; // Bit mask for each number of bits (0-8)
|
|
70
|
+
|
|
71
|
+
DWORD NumberOfBytes; // Total number of bytes in "Elements"
|
|
72
|
+
DWORD NumberOfBits; // Total number of bits that are available
|
|
73
|
+
BYTE Elements[1]; // Array of elements (variable length)
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const USHORT TMPQBits::SetBitsMask[] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF};
|
|
77
|
+
|
|
78
|
+
TMPQBits * TMPQBits::Create(
|
|
79
|
+
DWORD NumberOfBits,
|
|
80
|
+
BYTE FillValue)
|
|
81
|
+
{
|
|
82
|
+
TMPQBits * pBitArray;
|
|
83
|
+
size_t nSize = sizeof(TMPQBits) + (NumberOfBits + 7) / 8;
|
|
84
|
+
|
|
85
|
+
// Allocate the bit array
|
|
86
|
+
pBitArray = (TMPQBits *)STORM_ALLOC(BYTE, nSize);
|
|
87
|
+
if(pBitArray != NULL)
|
|
88
|
+
{
|
|
89
|
+
memset(pBitArray, FillValue, nSize);
|
|
90
|
+
pBitArray->NumberOfBytes = (NumberOfBits + 7) / 8;
|
|
91
|
+
pBitArray->NumberOfBits = NumberOfBits;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return pBitArray;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
DWORD TMPQBits::GetBits(
|
|
98
|
+
unsigned int nBitPosition,
|
|
99
|
+
unsigned int nBitLength,
|
|
100
|
+
void * pvBuffer,
|
|
101
|
+
unsigned int nResultByteSize)
|
|
102
|
+
{
|
|
103
|
+
unsigned char * pbBuffer = (unsigned char *)pvBuffer;
|
|
104
|
+
unsigned int nBytePosition0 = (nBitPosition / 8);
|
|
105
|
+
unsigned int nBytePosition1 = nBytePosition0 + 1;
|
|
106
|
+
unsigned int nByteLength = (nBitLength / 8);
|
|
107
|
+
unsigned int nBitOffset = (nBitPosition & 0x07);
|
|
108
|
+
unsigned char BitBuffer;
|
|
109
|
+
|
|
110
|
+
// Check for bit overflow
|
|
111
|
+
if(nBitPosition + nBitLength < nBitPosition)
|
|
112
|
+
return ERROR_BUFFER_OVERFLOW;
|
|
113
|
+
if(nBitPosition + nBitLength > NumberOfBits)
|
|
114
|
+
return ERROR_BUFFER_OVERFLOW;
|
|
115
|
+
if(nByteLength > nResultByteSize)
|
|
116
|
+
return ERROR_BUFFER_OVERFLOW;
|
|
117
|
+
|
|
118
|
+
#ifdef _DEBUG
|
|
119
|
+
// Check if the target is properly zeroed
|
|
120
|
+
for(unsigned int i = 0; i < nResultByteSize; i++)
|
|
121
|
+
assert(pbBuffer[i] == 0);
|
|
122
|
+
#endif
|
|
123
|
+
|
|
124
|
+
#ifndef STORMLIB_LITTLE_ENDIAN
|
|
125
|
+
// Adjust the buffer pointer for big endian platforms
|
|
126
|
+
pbBuffer += (nResultByteSize - 1);
|
|
127
|
+
#endif
|
|
128
|
+
|
|
129
|
+
// Copy whole bytes, if any
|
|
130
|
+
while(nByteLength > 0)
|
|
131
|
+
{
|
|
132
|
+
// Is the current position in the Elements byte-aligned?
|
|
133
|
+
if(nBitOffset != 0)
|
|
134
|
+
{
|
|
135
|
+
BitBuffer = (unsigned char)((Elements[nBytePosition0] >> nBitOffset) | (Elements[nBytePosition1] << (0x08 - nBitOffset)));
|
|
136
|
+
}
|
|
137
|
+
else
|
|
138
|
+
{
|
|
139
|
+
BitBuffer = Elements[nBytePosition0];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
#ifdef STORMLIB_LITTLE_ENDIAN
|
|
143
|
+
*pbBuffer++ = BitBuffer;
|
|
144
|
+
#else
|
|
145
|
+
*pbBuffer-- = BitBuffer;
|
|
146
|
+
#endif
|
|
147
|
+
|
|
148
|
+
// Move byte positions and lengths
|
|
149
|
+
nBytePosition1++;
|
|
150
|
+
nBytePosition0++;
|
|
151
|
+
nByteLength--;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Get the rest of the bits
|
|
155
|
+
nBitLength = (nBitLength & 0x07);
|
|
156
|
+
if(nBitLength != 0)
|
|
157
|
+
{
|
|
158
|
+
*pbBuffer = (unsigned char)(Elements[nBytePosition0] >> nBitOffset);
|
|
159
|
+
|
|
160
|
+
if(nBitLength > (8 - nBitOffset))
|
|
161
|
+
*pbBuffer = (unsigned char)((Elements[nBytePosition1] << (8 - nBitOffset)) | (Elements[nBytePosition0] >> nBitOffset));
|
|
162
|
+
|
|
163
|
+
*pbBuffer &= (0x01 << nBitLength) - 1;
|
|
164
|
+
}
|
|
165
|
+
return ERROR_SUCCESS;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
DWORD TMPQBits::SetBits(
|
|
169
|
+
unsigned int nBitPosition,
|
|
170
|
+
unsigned int nBitLength,
|
|
171
|
+
void * pvBuffer,
|
|
172
|
+
unsigned int nResultByteSize)
|
|
173
|
+
{
|
|
174
|
+
unsigned char * pbBuffer = (unsigned char *)pvBuffer;
|
|
175
|
+
unsigned int nBytePosition = (nBitPosition / 8);
|
|
176
|
+
unsigned int nBitOffset = (nBitPosition & 0x07);
|
|
177
|
+
unsigned short BitBuffer = 0;
|
|
178
|
+
unsigned short AndMask = 0;
|
|
179
|
+
unsigned short OneByte = 0;
|
|
180
|
+
|
|
181
|
+
// Keep compilers happy for platforms where nResultByteSize is not used
|
|
182
|
+
STORMLIB_UNUSED(nResultByteSize);
|
|
183
|
+
|
|
184
|
+
// Check for bit overflow
|
|
185
|
+
if(nBitPosition + nBitLength < nBitPosition)
|
|
186
|
+
return ERROR_BUFFER_OVERFLOW;
|
|
187
|
+
if(nBitPosition + nBitLength > NumberOfBits)
|
|
188
|
+
return ERROR_BUFFER_OVERFLOW;
|
|
189
|
+
if(nBitLength / 8 > nResultByteSize)
|
|
190
|
+
return ERROR_BUFFER_OVERFLOW;
|
|
191
|
+
|
|
192
|
+
#ifndef STORMLIB_LITTLE_ENDIAN
|
|
193
|
+
// Adjust the buffer pointer for big endian platforms
|
|
194
|
+
pbBuffer += (nResultByteSize - 1);
|
|
195
|
+
#endif
|
|
196
|
+
|
|
197
|
+
// Copy whole bytes, if any
|
|
198
|
+
while(nBitLength > 8)
|
|
199
|
+
{
|
|
200
|
+
// Reload the bit buffer
|
|
201
|
+
#ifdef STORMLIB_LITTLE_ENDIAN
|
|
202
|
+
OneByte = *pbBuffer++;
|
|
203
|
+
#else
|
|
204
|
+
OneByte = *pbBuffer--;
|
|
205
|
+
#endif
|
|
206
|
+
// Update the BitBuffer and AndMask for the bit array
|
|
207
|
+
BitBuffer = (BitBuffer >> 0x08) | (OneByte << nBitOffset);
|
|
208
|
+
AndMask = (AndMask >> 0x08) | (0x00FF << nBitOffset);
|
|
209
|
+
|
|
210
|
+
// Update the byte in the array
|
|
211
|
+
Elements[nBytePosition] = (BYTE)((Elements[nBytePosition] & ~AndMask) | BitBuffer);
|
|
212
|
+
|
|
213
|
+
// Move byte positions and lengths
|
|
214
|
+
nBytePosition++;
|
|
215
|
+
nBitLength -= 0x08;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if(nBitLength != 0)
|
|
219
|
+
{
|
|
220
|
+
// Reload the bit buffer
|
|
221
|
+
OneByte = *pbBuffer;
|
|
222
|
+
|
|
223
|
+
// Update the AND mask for the last bit
|
|
224
|
+
BitBuffer = (BitBuffer >> 0x08) | (OneByte << nBitOffset);
|
|
225
|
+
AndMask = (AndMask >> 0x08) | (SetBitsMask[nBitLength] << nBitOffset);
|
|
226
|
+
|
|
227
|
+
// Update the byte in the array
|
|
228
|
+
Elements[nBytePosition] = (BYTE)((Elements[nBytePosition] & ~AndMask) | BitBuffer);
|
|
229
|
+
|
|
230
|
+
// Update the next byte, if needed
|
|
231
|
+
if(AndMask & 0xFF00)
|
|
232
|
+
{
|
|
233
|
+
nBytePosition++;
|
|
234
|
+
BitBuffer >>= 0x08;
|
|
235
|
+
AndMask >>= 0x08;
|
|
236
|
+
|
|
237
|
+
Elements[nBytePosition] = (BYTE)((Elements[nBytePosition] & ~AndMask) | BitBuffer);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return ERROR_SUCCESS;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
void GetMPQBits(TMPQBits * pBits, unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, int nResultByteSize)
|
|
244
|
+
{
|
|
245
|
+
pBits->GetBits(nBitPosition, nBitLength, pvBuffer, nResultByteSize);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
//-----------------------------------------------------------------------------
|
|
249
|
+
// Support for MPQ header
|
|
250
|
+
|
|
251
|
+
static bool VerifyTablePosition64(
|
|
252
|
+
ULONGLONG MpqOffset, // Position of the MPQ header
|
|
253
|
+
ULONGLONG TableOffset, // Position of the MPQ table, relative to MPQ header
|
|
254
|
+
ULONGLONG TableSize, // Size of the MPQ table, in bytes
|
|
255
|
+
ULONGLONG FileSize) // Size of the entire file, in bytes
|
|
256
|
+
{
|
|
257
|
+
if(TableOffset != 0)
|
|
258
|
+
{
|
|
259
|
+
// Verify overflows
|
|
260
|
+
if((MpqOffset + TableOffset) < MpqOffset)
|
|
261
|
+
return false;
|
|
262
|
+
if((MpqOffset + TableOffset + TableSize) < MpqOffset)
|
|
263
|
+
return false;
|
|
264
|
+
|
|
265
|
+
// Verify sizes
|
|
266
|
+
if(TableOffset >= FileSize || TableSize >= FileSize)
|
|
267
|
+
return false;
|
|
268
|
+
if((MpqOffset + TableOffset) >= FileSize)
|
|
269
|
+
return false;
|
|
270
|
+
if((MpqOffset + TableOffset + TableSize) >= FileSize)
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
static bool VerifyTableTandemPositions(
|
|
277
|
+
ULONGLONG MpqOffset, // Position of the MPQ header
|
|
278
|
+
ULONGLONG TableOffset1, // 1st table: Position, relative to MPQ header
|
|
279
|
+
ULONGLONG TableSize1, // 1st table: Size in bytes
|
|
280
|
+
ULONGLONG TableOffset2, // 2nd table: Position, relative to MPQ header
|
|
281
|
+
ULONGLONG TableSize2, // 2nd table: Size in bytes
|
|
282
|
+
ULONGLONG FileSize) // Size of the entire file, in bytes
|
|
283
|
+
{
|
|
284
|
+
return VerifyTablePosition64(MpqOffset, TableOffset1, TableSize1, FileSize) &&
|
|
285
|
+
VerifyTablePosition64(MpqOffset, TableOffset2, TableSize2, FileSize);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
static ULONGLONG DetermineArchiveSize_V1(
|
|
289
|
+
TMPQArchive * ha,
|
|
290
|
+
TMPQHeader * pHeader,
|
|
291
|
+
ULONGLONG MpqOffset,
|
|
292
|
+
ULONGLONG FileSize)
|
|
293
|
+
{
|
|
294
|
+
ULONGLONG ByteOffset;
|
|
295
|
+
ULONGLONG EndOfMpq = FileSize;
|
|
296
|
+
DWORD SignatureHeader = 0;
|
|
297
|
+
DWORD dwArchiveSize32;
|
|
298
|
+
|
|
299
|
+
// This could only be called for MPQs version 1.0
|
|
300
|
+
assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1);
|
|
301
|
+
|
|
302
|
+
// Check if we can rely on the archive size in the header
|
|
303
|
+
if(pHeader->dwBlockTablePos < pHeader->dwArchiveSize)
|
|
304
|
+
{
|
|
305
|
+
// The block table cannot be compressed, so the sizes must match
|
|
306
|
+
if((pHeader->dwArchiveSize - pHeader->dwBlockTablePos) == (pHeader->dwBlockTableSize * sizeof(TMPQBlock)))
|
|
307
|
+
return pHeader->dwArchiveSize;
|
|
308
|
+
|
|
309
|
+
// If the archive size in the header is less than real file size
|
|
310
|
+
dwArchiveSize32 = (DWORD)(FileSize - MpqOffset);
|
|
311
|
+
if(pHeader->dwArchiveSize == dwArchiveSize32)
|
|
312
|
+
return pHeader->dwArchiveSize;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Check if there is a signature header
|
|
316
|
+
if((EndOfMpq - MpqOffset) > (MPQ_STRONG_SIGNATURE_SIZE + 4))
|
|
317
|
+
{
|
|
318
|
+
ByteOffset = EndOfMpq - MPQ_STRONG_SIGNATURE_SIZE - 4;
|
|
319
|
+
if(FileStream_Read(ha->pStream, &ByteOffset, &SignatureHeader, sizeof(DWORD)))
|
|
320
|
+
{
|
|
321
|
+
if(BSWAP_INT32_UNSIGNED(SignatureHeader) == MPQ_STRONG_SIGNATURE_ID)
|
|
322
|
+
EndOfMpq = EndOfMpq - MPQ_STRONG_SIGNATURE_SIZE - 4;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Return the returned archive size
|
|
327
|
+
return (EndOfMpq - MpqOffset);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
static ULONGLONG DetermineBlockTableSize_V2(TMPQHeader * pHeader, ULONGLONG MpqHeaderPos, ULONGLONG FileSize)
|
|
331
|
+
{
|
|
332
|
+
ULONGLONG BlockTablePos = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
|
|
333
|
+
ULONGLONG ArchiveSize = FileSize - MpqHeaderPos;
|
|
334
|
+
|
|
335
|
+
// If there is a hi-block table and it is beyond the block table,
|
|
336
|
+
// we can determine the block table size from it
|
|
337
|
+
if(pHeader->HiBlockTablePos64 != 0)
|
|
338
|
+
{
|
|
339
|
+
if(pHeader->HiBlockTablePos64 > BlockTablePos)
|
|
340
|
+
{
|
|
341
|
+
return (pHeader->HiBlockTablePos64 - BlockTablePos);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// If we have valid archive size, we can determine the block table size from the archive size
|
|
346
|
+
else
|
|
347
|
+
{
|
|
348
|
+
if((BlockTablePos >> 0x20) == 0 && (ArchiveSize >> 0x20) == 0)
|
|
349
|
+
{
|
|
350
|
+
DWORD dwBlockTablePos32 = (DWORD)(BlockTablePos);
|
|
351
|
+
DWORD dwArchiveSize32 = (DWORD)(ArchiveSize);
|
|
352
|
+
|
|
353
|
+
if(pHeader->dwArchiveSize == dwArchiveSize32)
|
|
354
|
+
{
|
|
355
|
+
return (dwArchiveSize32 - dwBlockTablePos32);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Default is the block table size from MPQ header
|
|
361
|
+
return (ULONGLONG)(pHeader->dwBlockTableSize) * sizeof(TMPQBlock);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
static ULONGLONG DetermineArchiveSize_V4(
|
|
365
|
+
TMPQHeader * pHeader,
|
|
366
|
+
ULONGLONG /* MpqOffset */,
|
|
367
|
+
ULONGLONG /* FileSize */)
|
|
368
|
+
{
|
|
369
|
+
ULONGLONG ArchiveSize = 0;
|
|
370
|
+
ULONGLONG EndOfTable;
|
|
371
|
+
|
|
372
|
+
// This could only be called for MPQs version 4
|
|
373
|
+
assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_4);
|
|
374
|
+
|
|
375
|
+
// Check position of BET table, if correct
|
|
376
|
+
if((pHeader->BetTablePos64 >> 0x20) == 0 && (pHeader->BetTableSize64 >> 0x20) == 0)
|
|
377
|
+
{
|
|
378
|
+
EndOfTable = pHeader->BetTablePos64 + pHeader->BetTableSize64;
|
|
379
|
+
if(EndOfTable > ArchiveSize)
|
|
380
|
+
ArchiveSize = EndOfTable;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Check position of HET table, if correct
|
|
384
|
+
if((pHeader->HetTablePos64 >> 0x20) == 0 && (pHeader->HetTableSize64 >> 0x20) == 0)
|
|
385
|
+
{
|
|
386
|
+
EndOfTable = pHeader->HetTablePos64 + pHeader->HetTableSize64;
|
|
387
|
+
if(EndOfTable > ArchiveSize)
|
|
388
|
+
ArchiveSize = EndOfTable;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
EndOfTable = pHeader->dwHashTablePos + pHeader->dwHashTableSize * sizeof(TMPQHash);
|
|
392
|
+
if(EndOfTable > ArchiveSize)
|
|
393
|
+
ArchiveSize = EndOfTable;
|
|
394
|
+
|
|
395
|
+
EndOfTable = pHeader->dwBlockTablePos + pHeader->dwBlockTableSize * sizeof(TMPQBlock);
|
|
396
|
+
if(EndOfTable > ArchiveSize)
|
|
397
|
+
ArchiveSize = EndOfTable;
|
|
398
|
+
|
|
399
|
+
// Return the calculated archive size
|
|
400
|
+
return ArchiveSize;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
ULONGLONG GetFileOffsetMask(TMPQArchive * ha)
|
|
404
|
+
{
|
|
405
|
+
ULONGLONG FileOffsetMask = (ULONGLONG)(-1);
|
|
406
|
+
|
|
407
|
+
// Sanity checks
|
|
408
|
+
assert(ha != NULL);
|
|
409
|
+
assert(ha->pHeader != NULL);
|
|
410
|
+
|
|
411
|
+
// MPQs of format 1 are 32-bit only
|
|
412
|
+
if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1)
|
|
413
|
+
FileOffsetMask = (ULONGLONG)(DWORD)(-1);
|
|
414
|
+
return FileOffsetMask;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
ULONGLONG FileOffsetFromMpqOffset(TMPQArchive * ha, ULONGLONG MpqOffset)
|
|
418
|
+
{
|
|
419
|
+
return (ha->MpqPos + MpqOffset) & ha->FileOffsetMask;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
//ULONGLONG FileOffsetFromMpqOffset(TMPQArchive * ha, ULONGLONG MpqOffset)
|
|
423
|
+
//{
|
|
424
|
+
// if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1)
|
|
425
|
+
// {
|
|
426
|
+
// // For MPQ archive v1, any file offset is only 32-bit
|
|
427
|
+
// return (ULONGLONG)((DWORD)ha->MpqPos + (DWORD)MpqOffset);
|
|
428
|
+
// }
|
|
429
|
+
// else
|
|
430
|
+
// {
|
|
431
|
+
// // For MPQ archive v2+, file offsets are full 64-bit
|
|
432
|
+
// return ha->MpqPos + MpqOffset;
|
|
433
|
+
// }
|
|
434
|
+
//}
|
|
435
|
+
|
|
436
|
+
ULONGLONG CalculateRawSectorOffset(
|
|
437
|
+
TMPQFile * hf,
|
|
438
|
+
DWORD dwSectorOffset)
|
|
439
|
+
{
|
|
440
|
+
ULONGLONG RawFilePos;
|
|
441
|
+
|
|
442
|
+
// Must be used for files within a MPQ
|
|
443
|
+
assert(hf->ha != NULL);
|
|
444
|
+
assert(hf->ha->pHeader != NULL);
|
|
445
|
+
|
|
446
|
+
//
|
|
447
|
+
// Some MPQ protectors place the sector offset table after the actual file data.
|
|
448
|
+
// Sector offsets in the sector offset table are negative. When added
|
|
449
|
+
// to MPQ file offset from the block table entry, the result is a correct
|
|
450
|
+
// position of the file data in the MPQ.
|
|
451
|
+
//
|
|
452
|
+
// For MPQs version 1.0, the offset is purely 32-bit
|
|
453
|
+
//
|
|
454
|
+
|
|
455
|
+
RawFilePos = (hf->RawFilePos + dwSectorOffset) & hf->ha->FileOffsetMask;
|
|
456
|
+
|
|
457
|
+
// We also have to add patch header size, if patch header is present
|
|
458
|
+
if(hf->pPatchInfo != NULL)
|
|
459
|
+
RawFilePos += hf->pPatchInfo->dwLength;
|
|
460
|
+
|
|
461
|
+
// Return the result offset
|
|
462
|
+
return RawFilePos;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// This function converts the MPQ header so it always looks like version 4
|
|
466
|
+
DWORD ConvertMpqHeaderToFormat4(
|
|
467
|
+
TMPQArchive * ha,
|
|
468
|
+
ULONGLONG ByteOffset,
|
|
469
|
+
ULONGLONG FileSize,
|
|
470
|
+
DWORD dwFlags,
|
|
471
|
+
MTYPE MapType)
|
|
472
|
+
{
|
|
473
|
+
TMPQHeader * pHeader = (TMPQHeader *)ha->HeaderData;
|
|
474
|
+
ULONGLONG BlockTablePos64 = 0;
|
|
475
|
+
ULONGLONG HashTablePos64 = 0;
|
|
476
|
+
ULONGLONG BlockTableMask = (ULONGLONG)-1;
|
|
477
|
+
ULONGLONG MaxOffset;
|
|
478
|
+
USHORT wFormatVersion = BSWAP_INT16_UNSIGNED(pHeader->wFormatVersion);
|
|
479
|
+
bool bHashBlockOffsetOK = false;
|
|
480
|
+
bool bHetBetOffsetOK = false;
|
|
481
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
482
|
+
|
|
483
|
+
// If version 1.0 is forced, then the format version is forced to be 1.0
|
|
484
|
+
// Reason: Storm.dll in Warcraft III ignores format version value
|
|
485
|
+
if((MapType == MapTypeWarcraft3) || (dwFlags & MPQ_OPEN_FORCE_MPQ_V1))
|
|
486
|
+
wFormatVersion = MPQ_FORMAT_VERSION_1;
|
|
487
|
+
|
|
488
|
+
// Don't accept format 3 for Starcraft II maps
|
|
489
|
+
if((MapType == MapTypeStarcraft2) && (pHeader->wFormatVersion > MPQ_FORMAT_VERSION_2))
|
|
490
|
+
wFormatVersion = MPQ_FORMAT_VERSION_4;
|
|
491
|
+
|
|
492
|
+
// Format-specific fixes
|
|
493
|
+
switch(wFormatVersion)
|
|
494
|
+
{
|
|
495
|
+
case MPQ_FORMAT_VERSION_1:
|
|
496
|
+
|
|
497
|
+
// Make sure that the MPQ Header is properly swapped
|
|
498
|
+
BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_1);
|
|
499
|
+
|
|
500
|
+
// Check for blatantly wrong MPQ header by the hash table position
|
|
501
|
+
if(((ByteOffset + pHeader->dwHashTablePos) & 0xFFFFFFFF) > FileSize)
|
|
502
|
+
return ERROR_FAKE_MPQ_HEADER;
|
|
503
|
+
if(((ByteOffset + pHeader->dwBlockTablePos) & 0xFFFFFFFF) > FileSize)
|
|
504
|
+
return ERROR_FAKE_MPQ_HEADER;
|
|
505
|
+
|
|
506
|
+
// Check for malformed MPQ header version 1.0
|
|
507
|
+
if(pHeader->wFormatVersion != MPQ_FORMAT_VERSION_1 || pHeader->dwHeaderSize != MPQ_HEADER_SIZE_V1)
|
|
508
|
+
{
|
|
509
|
+
pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1;
|
|
510
|
+
pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1;
|
|
511
|
+
ha->dwFlags |= MPQ_FLAG_MALFORMED;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
//
|
|
515
|
+
// Note: The value of "dwArchiveSize" member in the MPQ header
|
|
516
|
+
// is ignored by Storm.dll and can contain garbage value
|
|
517
|
+
// ("w3xmaster" protector).
|
|
518
|
+
//
|
|
519
|
+
|
|
520
|
+
Label_ArchiveVersion1:
|
|
521
|
+
if(pHeader->dwBlockTableSize > 1) // Prevent empty MPQs being marked as malformed
|
|
522
|
+
{
|
|
523
|
+
if(pHeader->dwHashTablePos <= pHeader->dwHeaderSize || (pHeader->dwHashTablePos & 0x80000000))
|
|
524
|
+
ha->dwFlags |= MPQ_FLAG_MALFORMED;
|
|
525
|
+
if(pHeader->dwBlockTablePos <= pHeader->dwHeaderSize || (pHeader->dwBlockTablePos & 0x80000000))
|
|
526
|
+
ha->dwFlags |= MPQ_FLAG_MALFORMED;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// Only low byte of sector size is really used
|
|
530
|
+
if(pHeader->wSectorSize & 0xFF00)
|
|
531
|
+
ha->dwFlags |= MPQ_FLAG_MALFORMED;
|
|
532
|
+
pHeader->wSectorSize = pHeader->wSectorSize & 0xFF;
|
|
533
|
+
|
|
534
|
+
// Fill the rest of the header
|
|
535
|
+
memset((LPBYTE)pHeader + MPQ_HEADER_SIZE_V1, 0, sizeof(TMPQHeader) - MPQ_HEADER_SIZE_V1);
|
|
536
|
+
pHeader->BlockTableSize64 = pHeader->dwBlockTableSize * sizeof(TMPQBlock);
|
|
537
|
+
pHeader->HashTableSize64 = pHeader->dwHashTableSize * sizeof(TMPQHash);
|
|
538
|
+
pHeader->ArchiveSize64 = pHeader->dwArchiveSize;
|
|
539
|
+
|
|
540
|
+
// Block table position must be calculated as 32-bit value
|
|
541
|
+
// Note: BOBA protector puts block table before the MPQ header, so it is negative
|
|
542
|
+
BlockTablePos64 = (ULONGLONG)((DWORD)ByteOffset + pHeader->dwBlockTablePos);
|
|
543
|
+
BlockTableMask = 0xFFFFFFF0;
|
|
544
|
+
|
|
545
|
+
// Determine the archive size on malformed MPQs
|
|
546
|
+
if(ha->dwFlags & MPQ_FLAG_MALFORMED)
|
|
547
|
+
{
|
|
548
|
+
// Calculate the archive size
|
|
549
|
+
pHeader->ArchiveSize64 = DetermineArchiveSize_V1(ha, pHeader, ByteOffset, FileSize);
|
|
550
|
+
pHeader->dwArchiveSize = (DWORD)pHeader->ArchiveSize64;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// EWIX_v8_7.w3x: TMPQHeader::dwBlockTableSize = 0x00319601
|
|
554
|
+
// Size of TFileTable goes to ~200MB, so we artificially cut it
|
|
555
|
+
if(BlockTablePos64 + (pHeader->dwBlockTableSize * sizeof(TMPQBlock)) > FileSize)
|
|
556
|
+
{
|
|
557
|
+
pHeader->dwBlockTableSize = (DWORD)((FileSize - BlockTablePos64) / sizeof(TMPQBlock));
|
|
558
|
+
pHeader->BlockTableSize64 = pHeader->dwBlockTableSize * sizeof(TMPQBlock);
|
|
559
|
+
}
|
|
560
|
+
break;
|
|
561
|
+
|
|
562
|
+
case MPQ_FORMAT_VERSION_2:
|
|
563
|
+
|
|
564
|
+
// Check for malformed MPQ header version 1.0
|
|
565
|
+
BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_2);
|
|
566
|
+
if(pHeader->wFormatVersion != MPQ_FORMAT_VERSION_2 || pHeader->dwHeaderSize != MPQ_HEADER_SIZE_V2)
|
|
567
|
+
{
|
|
568
|
+
pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1;
|
|
569
|
+
pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1;
|
|
570
|
+
ha->dwFlags |= MPQ_FLAG_MALFORMED;
|
|
571
|
+
goto Label_ArchiveVersion1;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// Fill the rest of the header with zeros
|
|
575
|
+
memset((LPBYTE)pHeader + MPQ_HEADER_SIZE_V2, 0, sizeof(TMPQHeader) - MPQ_HEADER_SIZE_V2);
|
|
576
|
+
|
|
577
|
+
// Check position of the hi-block table
|
|
578
|
+
if(pHeader->HiBlockTablePos64 > FileSize)
|
|
579
|
+
return ERROR_FILE_CORRUPT;
|
|
580
|
+
|
|
581
|
+
// Calculate the expected hash table size
|
|
582
|
+
pHeader->HashTableSize64 = (pHeader->dwHashTableSize * sizeof(TMPQHash));
|
|
583
|
+
HashTablePos64 = MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos);
|
|
584
|
+
|
|
585
|
+
// Calculate the expected block table size
|
|
586
|
+
pHeader->BlockTableSize64 = (pHeader->dwBlockTableSize * sizeof(TMPQBlock));
|
|
587
|
+
BlockTablePos64 = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
|
|
588
|
+
|
|
589
|
+
// We require the block table to follow hash table
|
|
590
|
+
if(BlockTablePos64 >= HashTablePos64)
|
|
591
|
+
{
|
|
592
|
+
// Determine whether the hash table is compressed. This can be detected
|
|
593
|
+
// by subtracting hash table position from the block table position.
|
|
594
|
+
pHeader->HashTableSize64 = BlockTablePos64 - HashTablePos64;
|
|
595
|
+
|
|
596
|
+
// Also, block table may be compressed. We check whether the HiBlockTable is there.
|
|
597
|
+
// If not, we try to use the archive size. Note that ArchiveSize may have
|
|
598
|
+
// an arbitrary value, because it is not tested by Blizzard games anymore
|
|
599
|
+
pHeader->BlockTableSize64 = DetermineBlockTableSize_V2(pHeader, ByteOffset, FileSize);
|
|
600
|
+
}
|
|
601
|
+
else
|
|
602
|
+
{
|
|
603
|
+
pHeader->ArchiveSize64 = pHeader->dwArchiveSize;
|
|
604
|
+
ha->dwFlags |= MPQ_FLAG_MALFORMED;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Add the MPQ Offset
|
|
608
|
+
BlockTablePos64 += ByteOffset;
|
|
609
|
+
break;
|
|
610
|
+
|
|
611
|
+
case MPQ_FORMAT_VERSION_3:
|
|
612
|
+
|
|
613
|
+
// In MPQ format 3.0, the entire header is optional
|
|
614
|
+
// and the size of the header can actually be identical
|
|
615
|
+
// to size of header 2.0
|
|
616
|
+
BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_3);
|
|
617
|
+
if(pHeader->dwHeaderSize < MPQ_HEADER_SIZE_V3)
|
|
618
|
+
{
|
|
619
|
+
pHeader->ArchiveSize64 = pHeader->dwArchiveSize;
|
|
620
|
+
pHeader->HetTablePos64 = 0;
|
|
621
|
+
pHeader->BetTablePos64 = 0;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// Fixup malformed MPQ header sizes
|
|
625
|
+
pHeader->dwHeaderSize = STORMLIB_MIN(pHeader->dwHeaderSize, MPQ_HEADER_SIZE_V3);
|
|
626
|
+
|
|
627
|
+
//
|
|
628
|
+
// We need to calculate the compressed size of each table. We assume the following order:
|
|
629
|
+
// 1) HET table
|
|
630
|
+
// 2) BET table
|
|
631
|
+
// 3) Classic hash table
|
|
632
|
+
// 4) Classic block table
|
|
633
|
+
// 5) Hi-block table
|
|
634
|
+
//
|
|
635
|
+
|
|
636
|
+
// Fill the rest of the header with zeros
|
|
637
|
+
memset((LPBYTE)pHeader + MPQ_HEADER_SIZE_V3, 0, sizeof(TMPQHeader) - MPQ_HEADER_SIZE_V3);
|
|
638
|
+
BlockTablePos64 = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
|
|
639
|
+
HashTablePos64 = MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos);
|
|
640
|
+
MaxOffset = pHeader->ArchiveSize64;
|
|
641
|
+
|
|
642
|
+
// Size of the hi-block table
|
|
643
|
+
if(pHeader->HiBlockTablePos64)
|
|
644
|
+
{
|
|
645
|
+
if(pHeader->HiBlockTablePos64 > FileSize)
|
|
646
|
+
return ERROR_FILE_CORRUPT;
|
|
647
|
+
pHeader->HiBlockTableSize64 = MaxOffset - pHeader->HiBlockTablePos64;
|
|
648
|
+
MaxOffset = pHeader->HiBlockTablePos64;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// Size of the block table
|
|
652
|
+
if(BlockTablePos64)
|
|
653
|
+
{
|
|
654
|
+
if(BlockTablePos64 > FileSize)
|
|
655
|
+
return ERROR_FILE_CORRUPT;
|
|
656
|
+
pHeader->BlockTableSize64 = MaxOffset - BlockTablePos64;
|
|
657
|
+
MaxOffset = BlockTablePos64;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// Size of the hash table
|
|
661
|
+
if(HashTablePos64)
|
|
662
|
+
{
|
|
663
|
+
if(HashTablePos64 > FileSize)
|
|
664
|
+
return ERROR_FILE_CORRUPT;
|
|
665
|
+
pHeader->HashTableSize64 = MaxOffset - HashTablePos64;
|
|
666
|
+
MaxOffset = HashTablePos64;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// Size of the BET table
|
|
670
|
+
if(pHeader->BetTablePos64)
|
|
671
|
+
{
|
|
672
|
+
if(pHeader->BetTablePos64 > FileSize)
|
|
673
|
+
return ERROR_FILE_CORRUPT;
|
|
674
|
+
pHeader->BetTableSize64 = MaxOffset - pHeader->BetTablePos64;
|
|
675
|
+
MaxOffset = pHeader->BetTablePos64;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// Size of the HET table
|
|
679
|
+
if(pHeader->HetTablePos64)
|
|
680
|
+
{
|
|
681
|
+
if(pHeader->HetTablePos64 > FileSize)
|
|
682
|
+
return ERROR_FILE_CORRUPT;
|
|
683
|
+
pHeader->HetTableSize64 = MaxOffset - pHeader->HetTablePos64;
|
|
684
|
+
// MaxOffset = pHeader->HetTablePos64;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Add the MPQ Offset
|
|
688
|
+
BlockTablePos64 += ByteOffset;
|
|
689
|
+
break;
|
|
690
|
+
|
|
691
|
+
case MPQ_FORMAT_VERSION_4:
|
|
692
|
+
|
|
693
|
+
// Verify header MD5. Header MD5 is calculated from the MPQ header since the 'MPQ\x1A'
|
|
694
|
+
// signature until the position of header MD5 at offset 0xC0
|
|
695
|
+
// Apparently, Starcraft II only accepts MPQ headers where the MPQ header hash matches
|
|
696
|
+
// If MD5 doesn't match, we ignore this offset. We also ignore it if there's no MD5 at all
|
|
697
|
+
if(!IsValidMD5(pHeader->MD5_MpqHeader))
|
|
698
|
+
return ERROR_FAKE_MPQ_HEADER;
|
|
699
|
+
if(!VerifyDataBlockHash(pHeader, MPQ_HEADER_SIZE_V4 - MD5_DIGEST_SIZE, pHeader->MD5_MpqHeader))
|
|
700
|
+
return ERROR_FAKE_MPQ_HEADER;
|
|
701
|
+
|
|
702
|
+
// Byteswap after header MD5 is verified
|
|
703
|
+
BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_4);
|
|
704
|
+
|
|
705
|
+
// Fixup malformed MPQ header sizes
|
|
706
|
+
pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V4;
|
|
707
|
+
|
|
708
|
+
// HiBlockTable must be 0 for archives under 4GB
|
|
709
|
+
if((pHeader->ArchiveSize64 >> 0x20) == 0 && pHeader->HiBlockTablePos64 != 0)
|
|
710
|
+
return ERROR_FAKE_MPQ_HEADER;
|
|
711
|
+
|
|
712
|
+
// Is the "HET&BET" table tandem OK?
|
|
713
|
+
bHetBetOffsetOK = VerifyTableTandemPositions(ByteOffset,
|
|
714
|
+
pHeader->HetTablePos64, pHeader->HetTableSize64,
|
|
715
|
+
pHeader->BetTablePos64, pHeader->BetTableSize64,
|
|
716
|
+
FileSize);
|
|
717
|
+
|
|
718
|
+
// Is the "Hash&Block" table tandem OK?
|
|
719
|
+
bHashBlockOffsetOK = VerifyTableTandemPositions(ByteOffset,
|
|
720
|
+
pHeader->dwHashTablePos, pHeader->HashTableSize64,
|
|
721
|
+
pHeader->dwBlockTablePos, pHeader->BlockTableSize64,
|
|
722
|
+
FileSize);
|
|
723
|
+
|
|
724
|
+
// At least one pair must be OK
|
|
725
|
+
if(bHetBetOffsetOK == false && bHashBlockOffsetOK == false)
|
|
726
|
+
return ERROR_FAKE_MPQ_HEADER;
|
|
727
|
+
|
|
728
|
+
// Check for malformed MPQs
|
|
729
|
+
if(pHeader->wFormatVersion != MPQ_FORMAT_VERSION_4 || (ByteOffset + pHeader->ArchiveSize64) > FileSize || (ByteOffset + pHeader->HiBlockTablePos64) >= FileSize)
|
|
730
|
+
{
|
|
731
|
+
pHeader->wFormatVersion = MPQ_FORMAT_VERSION_4;
|
|
732
|
+
pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V4;
|
|
733
|
+
ha->dwFlags |= MPQ_FLAG_MALFORMED;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// Recalculate archive size
|
|
737
|
+
if(ha->dwFlags & MPQ_FLAG_MALFORMED)
|
|
738
|
+
{
|
|
739
|
+
// Calculate the archive size
|
|
740
|
+
pHeader->ArchiveSize64 = DetermineArchiveSize_V4(pHeader, ByteOffset, FileSize);
|
|
741
|
+
pHeader->dwArchiveSize = (DWORD)pHeader->ArchiveSize64;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// Calculate the block table position
|
|
745
|
+
BlockTablePos64 = ByteOffset + MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
|
|
746
|
+
break;
|
|
747
|
+
|
|
748
|
+
default:
|
|
749
|
+
|
|
750
|
+
// Check if it's a War of the Immortal data file (SQP)
|
|
751
|
+
// If not, we treat it as malformed MPQ version 1.0
|
|
752
|
+
if(ConvertSqpHeaderToFormat4(ha, FileSize, dwFlags) != ERROR_SUCCESS)
|
|
753
|
+
{
|
|
754
|
+
pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1;
|
|
755
|
+
pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1;
|
|
756
|
+
ha->dwFlags |= MPQ_FLAG_MALFORMED;
|
|
757
|
+
goto Label_ArchiveVersion1;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// Calculate the block table position
|
|
761
|
+
BlockTablePos64 = ByteOffset + MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
|
|
762
|
+
break;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// Handle case when block table is placed before the MPQ header
|
|
766
|
+
// Used by BOBA protector
|
|
767
|
+
if(BlockTablePos64 < ByteOffset)
|
|
768
|
+
ha->dwFlags |= MPQ_FLAG_MALFORMED;
|
|
769
|
+
return dwErrCode;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
//-----------------------------------------------------------------------------
|
|
773
|
+
// Support for hash table
|
|
774
|
+
|
|
775
|
+
// Hash entry verification when the file table does not exist yet
|
|
776
|
+
bool IsValidHashEntry(TMPQArchive * ha, TMPQHash * pHash)
|
|
777
|
+
{
|
|
778
|
+
TFileEntry * pFileEntry = ha->pFileTable + MPQ_BLOCK_INDEX(pHash);
|
|
779
|
+
|
|
780
|
+
return ((MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) && (pFileEntry->dwFlags & MPQ_FILE_EXISTS)) ? true : false;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// Hash entry verification when the file table does not exist yet
|
|
784
|
+
static bool IsValidHashEntry1(TMPQArchive * ha, TMPQHash * pHash, TMPQBlock * pBlockTable)
|
|
785
|
+
{
|
|
786
|
+
ULONGLONG ByteOffset;
|
|
787
|
+
TMPQBlock * pBlock;
|
|
788
|
+
|
|
789
|
+
// The block index is considered valid if it's less than block table size
|
|
790
|
+
if(MPQ_BLOCK_INDEX(pHash) < ha->pHeader->dwBlockTableSize)
|
|
791
|
+
{
|
|
792
|
+
// Calculate the block table position
|
|
793
|
+
pBlock = pBlockTable + MPQ_BLOCK_INDEX(pHash);
|
|
794
|
+
|
|
795
|
+
// Check whether this is an existing file
|
|
796
|
+
if(pBlock->dwFlags & MPQ_FILE_EXISTS)
|
|
797
|
+
{
|
|
798
|
+
// We don't allow to be file size greater than 2GB in malformed archives
|
|
799
|
+
if((ha->dwFlags & MPQ_FLAG_MALFORMED) && (pBlock->dwFSize >= 0x80000000))
|
|
800
|
+
return false;
|
|
801
|
+
|
|
802
|
+
// The begin of the file must be within the archive
|
|
803
|
+
ByteOffset = FileOffsetFromMpqOffset(ha, pBlock->dwFilePos);
|
|
804
|
+
return (ByteOffset < ha->FileSize);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
return false;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// Returns a hash table entry in the following order:
|
|
812
|
+
// 1) A hash table entry with the preferred locale and platform
|
|
813
|
+
// 2) A hash table entry with the neutral|matching locale and neutral|matching platform
|
|
814
|
+
// 3) NULL
|
|
815
|
+
// Storm_2016.dll: 15020940
|
|
816
|
+
static TMPQHash * GetHashEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcFileLocale)
|
|
817
|
+
{
|
|
818
|
+
TMPQHash * pFirstHash = GetFirstHashEntry(ha, szFileName);
|
|
819
|
+
TMPQHash * pBestEntry = NULL;
|
|
820
|
+
TMPQHash * pHash = pFirstHash;
|
|
821
|
+
USHORT Locale = SFILE_LOCALE(lcFileLocale);
|
|
822
|
+
BYTE Platform = SFILE_PLATFORM(lcFileLocale);
|
|
823
|
+
|
|
824
|
+
// Parse the found hashes
|
|
825
|
+
while(pHash != NULL)
|
|
826
|
+
{
|
|
827
|
+
// Storm_2016.dll: 150209CB
|
|
828
|
+
// If the hash entry matches both locale and platform, return it immediately
|
|
829
|
+
// Only do that for non-0 locale&platform, because for loc&plat=0, there's different
|
|
830
|
+
// processing in Warcraft III vs. Starcraft, which is abused by some protectors.
|
|
831
|
+
if((Locale || Platform) && pHash->Locale == Locale && pHash->Platform == Platform)
|
|
832
|
+
return pHash;
|
|
833
|
+
|
|
834
|
+
// Storm_2016.dll: 150209D9
|
|
835
|
+
// If (locale matches or is neutral) AND (platform matches or is neutral), remember this as the best entry
|
|
836
|
+
// Also remember the first matching entry for Starcraft maps
|
|
837
|
+
if(pHash->Locale == 0 || pHash->Locale == Locale)
|
|
838
|
+
{
|
|
839
|
+
if(pHash->Platform == 0 || pHash->Platform == Platform)
|
|
840
|
+
{
|
|
841
|
+
pBestEntry = pHash;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Get the next hash entry for that file
|
|
846
|
+
pHash = GetNextHashEntry(ha, pFirstHash, pHash);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// Return the best entry that we found
|
|
850
|
+
return pBestEntry;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// Returns a hash table entry in the following order:
|
|
854
|
+
// 1) A hash table entry with the preferred locale&platform
|
|
855
|
+
// 2) NULL
|
|
856
|
+
// In case there are multiple items with the same locale&platform,
|
|
857
|
+
// we need to return the last one. This is because it must correspond to SFileOpenFileEx
|
|
858
|
+
static TMPQHash * GetHashEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcFileLocale)
|
|
859
|
+
{
|
|
860
|
+
TMPQHash * pFirstHash = GetFirstHashEntry(ha, szFileName);
|
|
861
|
+
TMPQHash * pBestHash = NULL;
|
|
862
|
+
TMPQHash * pHash = pFirstHash;
|
|
863
|
+
USHORT Locale = SFILE_LOCALE(lcFileLocale);
|
|
864
|
+
BYTE Platform = SFILE_PLATFORM(lcFileLocale);
|
|
865
|
+
|
|
866
|
+
// Parse the found hashes
|
|
867
|
+
while(pHash != NULL)
|
|
868
|
+
{
|
|
869
|
+
// If the locales match, we remember this one as the best one
|
|
870
|
+
if(pHash->Locale == Locale && pHash->Platform == Platform)
|
|
871
|
+
pBestHash = pHash;
|
|
872
|
+
|
|
873
|
+
// Get the next hash entry for that file
|
|
874
|
+
pHash = GetNextHashEntry(ha, pFirstHash, pHash);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// Return the best hash or NULL
|
|
878
|
+
return pBestHash;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// Defragment the file table so it does not contain any gaps
|
|
882
|
+
// Note: As long as all values of all TMPQHash::dwBlockIndex
|
|
883
|
+
// are not HASH_ENTRY_FREE, the startup search index does not matter.
|
|
884
|
+
// Hash table is circular, so as long as there is no terminator,
|
|
885
|
+
// all entries will be found.
|
|
886
|
+
/*
|
|
887
|
+
static TMPQHash * DefragmentHashTable(
|
|
888
|
+
TMPQArchive * ha,
|
|
889
|
+
TMPQHash * pHashTable,
|
|
890
|
+
TMPQBlock * pBlockTable)
|
|
891
|
+
{
|
|
892
|
+
TMPQHeader * pHeader = ha->pHeader;
|
|
893
|
+
TMPQHash * pHashTableEnd = pHashTable + pHeader->dwHashTableSize;
|
|
894
|
+
TMPQHash * pSource = pHashTable;
|
|
895
|
+
TMPQHash * pTarget = pHashTable;
|
|
896
|
+
DWORD dwFirstFreeEntry;
|
|
897
|
+
DWORD dwNewTableSize;
|
|
898
|
+
|
|
899
|
+
// Sanity checks
|
|
900
|
+
assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1);
|
|
901
|
+
assert(pHeader->HiBlockTablePos64 == 0);
|
|
902
|
+
|
|
903
|
+
// Parse the hash table and move the entries to the begin of it
|
|
904
|
+
for(pSource = pHashTable; pSource < pHashTableEnd; pSource++)
|
|
905
|
+
{
|
|
906
|
+
// Check whether this is a valid hash table entry
|
|
907
|
+
if(IsValidHashEntry1(ha, pSource, pBlockTable))
|
|
908
|
+
{
|
|
909
|
+
// Copy the hash table entry back
|
|
910
|
+
if(pSource > pTarget)
|
|
911
|
+
pTarget[0] = pSource[0];
|
|
912
|
+
|
|
913
|
+
// Move the target
|
|
914
|
+
pTarget++;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
// Calculate how many entries in the hash table we really need
|
|
919
|
+
dwFirstFreeEntry = (DWORD)(pTarget - pHashTable);
|
|
920
|
+
dwNewTableSize = GetNearestPowerOfTwo(dwFirstFreeEntry);
|
|
921
|
+
|
|
922
|
+
// Fill the rest with entries that look like deleted
|
|
923
|
+
pHashTableEnd = pHashTable + dwNewTableSize;
|
|
924
|
+
pSource = pHashTable + dwFirstFreeEntry;
|
|
925
|
+
memset(pSource, 0xFF, (dwNewTableSize - dwFirstFreeEntry) * sizeof(TMPQHash));
|
|
926
|
+
|
|
927
|
+
// Mark the block indexes as deleted
|
|
928
|
+
for(; pSource < pHashTableEnd; pSource++)
|
|
929
|
+
pSource->dwBlockIndex = HASH_ENTRY_DELETED;
|
|
930
|
+
|
|
931
|
+
// Free some of the space occupied by the hash table
|
|
932
|
+
if(dwNewTableSize < pHeader->dwHashTableSize)
|
|
933
|
+
{
|
|
934
|
+
pHashTable = STORM_REALLOC(TMPQHash, pHashTable, dwNewTableSize);
|
|
935
|
+
ha->pHeader->BlockTableSize64 = dwNewTableSize * sizeof(TMPQHash);
|
|
936
|
+
ha->pHeader->dwHashTableSize = dwNewTableSize;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
return pHashTable;
|
|
940
|
+
}
|
|
941
|
+
*/
|
|
942
|
+
|
|
943
|
+
static DWORD BuildFileTableFromBlockTable(
|
|
944
|
+
TMPQArchive * ha,
|
|
945
|
+
TMPQBlock * pBlockTable)
|
|
946
|
+
{
|
|
947
|
+
TFileEntry * pFileEntry;
|
|
948
|
+
TMPQHeader * pHeader = ha->pHeader;
|
|
949
|
+
TMPQBlock * pBlock;
|
|
950
|
+
TMPQHash * pHashTableEnd;
|
|
951
|
+
TMPQHash * pHash;
|
|
952
|
+
LPDWORD DefragmentTable = NULL;
|
|
953
|
+
DWORD dwItemCount = 0;
|
|
954
|
+
|
|
955
|
+
// Sanity checks
|
|
956
|
+
assert(ha->pFileTable != NULL);
|
|
957
|
+
assert(ha->dwFileTableSize >= ha->dwMaxFileCount);
|
|
958
|
+
|
|
959
|
+
//
|
|
960
|
+
// Defragmentation of the hash table was removed. The reason is a MPQ protector,
|
|
961
|
+
// two hash entries with the same name, where only the second one is valid.
|
|
962
|
+
// The index of the first entry (HashString(szFileName, 0)) points to the second one:
|
|
963
|
+
//
|
|
964
|
+
// NameA NameB BlkIdx Name
|
|
965
|
+
// B701656E FCFB1EED 0000001C staredit\scenario.chk (correct one)
|
|
966
|
+
// --> B701656E FCFB1EED 0000001D staredit\scenario.chk (corrupt one)
|
|
967
|
+
//
|
|
968
|
+
// Defragmenting the hash table corrupts the order and "staredit\scenario.chk" can't be read
|
|
969
|
+
// Example MPQ: MPQ_2022_v1_Sniper.scx
|
|
970
|
+
//
|
|
971
|
+
|
|
972
|
+
//if(ha->dwFlags & MPQ_FLAG_HASH_TABLE_CUT)
|
|
973
|
+
//{
|
|
974
|
+
// ha->pHashTable = DefragmentHashTable(ha, ha->pHashTable, pBlockTable);
|
|
975
|
+
// ha->dwMaxFileCount = pHeader->dwHashTableSize;
|
|
976
|
+
//}
|
|
977
|
+
|
|
978
|
+
// If the hash table or block table is cut,
|
|
979
|
+
// we will defragment the block table
|
|
980
|
+
if(ha->dwFlags & (MPQ_FLAG_HASH_TABLE_CUT | MPQ_FLAG_BLOCK_TABLE_CUT))
|
|
981
|
+
{
|
|
982
|
+
// Sanity checks
|
|
983
|
+
assert(pHeader->HiBlockTablePos64 == 0);
|
|
984
|
+
|
|
985
|
+
// Allocate the translation table
|
|
986
|
+
DefragmentTable = STORM_ALLOC(DWORD, pHeader->dwBlockTableSize);
|
|
987
|
+
if(DefragmentTable == NULL)
|
|
988
|
+
return ERROR_NOT_ENOUGH_MEMORY;
|
|
989
|
+
|
|
990
|
+
// Fill the translation table
|
|
991
|
+
memset(DefragmentTable, 0xFF, pHeader->dwBlockTableSize * sizeof(DWORD));
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// Parse the entire hash table
|
|
995
|
+
pHashTableEnd = ha->pHashTable + pHeader->dwHashTableSize;
|
|
996
|
+
for(pHash = ha->pHashTable; pHash < pHashTableEnd; pHash++)
|
|
997
|
+
{
|
|
998
|
+
//
|
|
999
|
+
// We need to properly handle these cases:
|
|
1000
|
+
// - Multiple hash entries (same file name) point to the same block entry
|
|
1001
|
+
// - Multiple hash entries (different file name) point to the same block entry
|
|
1002
|
+
//
|
|
1003
|
+
// Ignore all hash table entries where:
|
|
1004
|
+
// - Block Index >= BlockTableSize
|
|
1005
|
+
// - Flags of the appropriate block table entry
|
|
1006
|
+
//
|
|
1007
|
+
|
|
1008
|
+
if(IsValidHashEntry1(ha, pHash, pBlockTable))
|
|
1009
|
+
{
|
|
1010
|
+
DWORD dwOldIndex = MPQ_BLOCK_INDEX(pHash);
|
|
1011
|
+
DWORD dwNewIndex = MPQ_BLOCK_INDEX(pHash);
|
|
1012
|
+
|
|
1013
|
+
// Determine the new block index
|
|
1014
|
+
if(DefragmentTable != NULL)
|
|
1015
|
+
{
|
|
1016
|
+
// Need to handle case when multiple hash
|
|
1017
|
+
// entries point to the same block entry
|
|
1018
|
+
if(DefragmentTable[dwOldIndex] == HASH_ENTRY_FREE)
|
|
1019
|
+
{
|
|
1020
|
+
DefragmentTable[dwOldIndex] = dwItemCount;
|
|
1021
|
+
dwNewIndex = dwItemCount++;
|
|
1022
|
+
}
|
|
1023
|
+
else
|
|
1024
|
+
{
|
|
1025
|
+
dwNewIndex = DefragmentTable[dwOldIndex];
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
// Fix the pointer in the hash entry
|
|
1029
|
+
pHash->dwBlockIndex = dwNewIndex;
|
|
1030
|
+
|
|
1031
|
+
// Dump the relocation entry
|
|
1032
|
+
// printf("Relocating hash entry %08X-%08X: %08X -> %08X\n", pHash->dwName1, pHash->dwName2, dwBlockIndex, dwNewIndex);
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// Get the pointer to the file entry and the block entry
|
|
1036
|
+
pFileEntry = ha->pFileTable + dwNewIndex;
|
|
1037
|
+
pBlock = pBlockTable + dwOldIndex;
|
|
1038
|
+
|
|
1039
|
+
// ByteOffset is only valid if file size is not zero
|
|
1040
|
+
pFileEntry->ByteOffset = pBlock->dwFilePos;
|
|
1041
|
+
if(pFileEntry->ByteOffset == 0 && pBlock->dwFSize == 0)
|
|
1042
|
+
pFileEntry->ByteOffset = ha->pHeader->dwHeaderSize;
|
|
1043
|
+
|
|
1044
|
+
// Clear file flags that are unknown to this type of map.
|
|
1045
|
+
pFileEntry->dwFlags = pBlock->dwFlags & ha->dwValidFileFlags;
|
|
1046
|
+
|
|
1047
|
+
// Fill the rest of the file entry
|
|
1048
|
+
pFileEntry->dwFileSize = pBlock->dwFSize;
|
|
1049
|
+
pFileEntry->dwCmpSize = pBlock->dwCSize;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// Free the translation table
|
|
1054
|
+
if(DefragmentTable != NULL)
|
|
1055
|
+
{
|
|
1056
|
+
// If we defragmented the block table in the process,
|
|
1057
|
+
// free some memory by shrinking the file table
|
|
1058
|
+
if(ha->dwFileTableSize > ha->dwMaxFileCount)
|
|
1059
|
+
{
|
|
1060
|
+
ha->pFileTable = STORM_REALLOC(TFileEntry, ha->pFileTable, ha->dwMaxFileCount);
|
|
1061
|
+
ha->pHeader->BlockTableSize64 = ha->dwMaxFileCount * sizeof(TMPQBlock);
|
|
1062
|
+
ha->pHeader->dwBlockTableSize = ha->dwMaxFileCount;
|
|
1063
|
+
ha->dwFileTableSize = ha->dwMaxFileCount;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// DumpFileTable(ha->pFileTable, ha->dwFileTableSize);
|
|
1067
|
+
|
|
1068
|
+
// Free the translation table
|
|
1069
|
+
STORM_FREE(DefragmentTable);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
return ERROR_SUCCESS;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
static TMPQHash * TranslateHashTable(
|
|
1076
|
+
TMPQArchive * ha,
|
|
1077
|
+
ULONGLONG * pcbTableSize)
|
|
1078
|
+
{
|
|
1079
|
+
TMPQHash * pHashTable;
|
|
1080
|
+
size_t HashTableSize;
|
|
1081
|
+
|
|
1082
|
+
// Allocate copy of the hash table
|
|
1083
|
+
pHashTable = STORM_ALLOC(TMPQHash, ha->pHeader->dwHashTableSize);
|
|
1084
|
+
if(pHashTable != NULL)
|
|
1085
|
+
{
|
|
1086
|
+
// Copy the hash table
|
|
1087
|
+
HashTableSize = sizeof(TMPQHash) * ha->pHeader->dwHashTableSize;
|
|
1088
|
+
memcpy(pHashTable, ha->pHashTable, HashTableSize);
|
|
1089
|
+
|
|
1090
|
+
// Give the size to the caller
|
|
1091
|
+
if(pcbTableSize != NULL)
|
|
1092
|
+
{
|
|
1093
|
+
*pcbTableSize = (ULONGLONG)HashTableSize;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
return pHashTable;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// Also used in SFileGetFileInfo
|
|
1101
|
+
TMPQBlock * TranslateBlockTable(
|
|
1102
|
+
TMPQArchive * ha,
|
|
1103
|
+
ULONGLONG * pcbTableSize,
|
|
1104
|
+
bool * pbNeedHiBlockTable)
|
|
1105
|
+
{
|
|
1106
|
+
TFileEntry * pFileEntry = ha->pFileTable;
|
|
1107
|
+
TMPQBlock * pBlockTable;
|
|
1108
|
+
TMPQBlock * pBlock;
|
|
1109
|
+
DWORD NeedHiBlockTable = 0;
|
|
1110
|
+
DWORD dwBlockTableSize = ha->pHeader->dwBlockTableSize;
|
|
1111
|
+
|
|
1112
|
+
// Allocate copy of the hash table
|
|
1113
|
+
pBlockTable = pBlock = STORM_ALLOC(TMPQBlock, dwBlockTableSize);
|
|
1114
|
+
if(pBlockTable != NULL)
|
|
1115
|
+
{
|
|
1116
|
+
// Convert the block table
|
|
1117
|
+
for(DWORD i = 0; i < dwBlockTableSize; i++)
|
|
1118
|
+
{
|
|
1119
|
+
NeedHiBlockTable |= (DWORD)(pFileEntry->ByteOffset >> 32);
|
|
1120
|
+
pBlock->dwFilePos = (DWORD)pFileEntry->ByteOffset;
|
|
1121
|
+
pBlock->dwFSize = pFileEntry->dwFileSize;
|
|
1122
|
+
pBlock->dwCSize = pFileEntry->dwCmpSize;
|
|
1123
|
+
pBlock->dwFlags = pFileEntry->dwFlags;
|
|
1124
|
+
|
|
1125
|
+
pFileEntry++;
|
|
1126
|
+
pBlock++;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
// Give the size to the caller
|
|
1130
|
+
if(pcbTableSize != NULL)
|
|
1131
|
+
*pcbTableSize = (ULONGLONG)dwBlockTableSize * sizeof(TMPQBlock);
|
|
1132
|
+
|
|
1133
|
+
if(pbNeedHiBlockTable != NULL)
|
|
1134
|
+
*pbNeedHiBlockTable = NeedHiBlockTable ? true : false;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
return pBlockTable;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
static USHORT * TranslateHiBlockTable(
|
|
1141
|
+
TMPQArchive * ha,
|
|
1142
|
+
ULONGLONG * pcbTableSize)
|
|
1143
|
+
{
|
|
1144
|
+
TFileEntry * pFileEntry = ha->pFileTable;
|
|
1145
|
+
USHORT * pHiBlockTable;
|
|
1146
|
+
USHORT * pHiBlock;
|
|
1147
|
+
DWORD dwBlockTableSize = ha->pHeader->dwBlockTableSize;
|
|
1148
|
+
|
|
1149
|
+
// Allocate copy of the hash table
|
|
1150
|
+
pHiBlockTable = pHiBlock = STORM_ALLOC(USHORT, dwBlockTableSize);
|
|
1151
|
+
if(pHiBlockTable != NULL)
|
|
1152
|
+
{
|
|
1153
|
+
// Copy the block table
|
|
1154
|
+
for(DWORD i = 0; i < dwBlockTableSize; i++)
|
|
1155
|
+
pHiBlock[i] = (USHORT)(pFileEntry[i].ByteOffset >> 0x20);
|
|
1156
|
+
|
|
1157
|
+
// Give the size to the caller
|
|
1158
|
+
if(pcbTableSize != NULL)
|
|
1159
|
+
*pcbTableSize = (ULONGLONG)dwBlockTableSize * sizeof(USHORT);
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
return pHiBlockTable;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
//-----------------------------------------------------------------------------
|
|
1166
|
+
// General EXT table functions
|
|
1167
|
+
|
|
1168
|
+
TMPQExtHeader * LoadExtTable(
|
|
1169
|
+
TMPQArchive * ha,
|
|
1170
|
+
ULONGLONG ByteOffset,
|
|
1171
|
+
size_t Size,
|
|
1172
|
+
DWORD dwSignature,
|
|
1173
|
+
DWORD dwKey)
|
|
1174
|
+
{
|
|
1175
|
+
TMPQExtHeader * pCompressed = NULL; // Compressed table
|
|
1176
|
+
TMPQExtHeader * pExtTable = NULL; // Uncompressed table
|
|
1177
|
+
|
|
1178
|
+
// Do nothing if the size is zero
|
|
1179
|
+
if(ByteOffset != 0 && Size != 0)
|
|
1180
|
+
{
|
|
1181
|
+
// Allocate size for the compressed table
|
|
1182
|
+
pExtTable = (TMPQExtHeader *)STORM_ALLOC(BYTE, Size);
|
|
1183
|
+
if(pExtTable != NULL)
|
|
1184
|
+
{
|
|
1185
|
+
// Load the table from the MPQ
|
|
1186
|
+
ByteOffset += ha->MpqPos;
|
|
1187
|
+
if(!FileStream_Read(ha->pStream, &ByteOffset, pExtTable, (DWORD)Size))
|
|
1188
|
+
{
|
|
1189
|
+
STORM_FREE(pExtTable);
|
|
1190
|
+
return NULL;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
// Swap the ext table header
|
|
1194
|
+
BSWAP_ARRAY32_UNSIGNED(pExtTable, sizeof(TMPQExtHeader));
|
|
1195
|
+
if(pExtTable->dwSignature != dwSignature)
|
|
1196
|
+
{
|
|
1197
|
+
STORM_FREE(pExtTable);
|
|
1198
|
+
return NULL;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// Decrypt the block
|
|
1202
|
+
BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize);
|
|
1203
|
+
DecryptMpqBlock(pExtTable + 1, (DWORD)(Size - sizeof(TMPQExtHeader)), dwKey);
|
|
1204
|
+
BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize);
|
|
1205
|
+
|
|
1206
|
+
// If the table is compressed, decompress it
|
|
1207
|
+
if((pExtTable->dwDataSize + sizeof(TMPQExtHeader)) > Size)
|
|
1208
|
+
{
|
|
1209
|
+
pCompressed = pExtTable;
|
|
1210
|
+
pExtTable = (TMPQExtHeader *)STORM_ALLOC(BYTE, sizeof(TMPQExtHeader) + pCompressed->dwDataSize);
|
|
1211
|
+
if(pExtTable != NULL)
|
|
1212
|
+
{
|
|
1213
|
+
int cbOutBuffer = (int)pCompressed->dwDataSize;
|
|
1214
|
+
int cbInBuffer = (int)Size;
|
|
1215
|
+
|
|
1216
|
+
// Decompress the extended table
|
|
1217
|
+
pExtTable->dwSignature = pCompressed->dwSignature;
|
|
1218
|
+
pExtTable->dwVersion = pCompressed->dwVersion;
|
|
1219
|
+
pExtTable->dwDataSize = pCompressed->dwDataSize;
|
|
1220
|
+
if(!SCompDecompress2(pExtTable + 1, &cbOutBuffer, pCompressed + 1, cbInBuffer))
|
|
1221
|
+
{
|
|
1222
|
+
STORM_FREE(pExtTable);
|
|
1223
|
+
pExtTable = NULL;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
// Free the compressed block
|
|
1228
|
+
STORM_FREE(pCompressed);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// Return the decompressed table to the caller
|
|
1234
|
+
return pExtTable;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
static DWORD SaveMpqTable(
|
|
1238
|
+
TMPQArchive * ha,
|
|
1239
|
+
void * pMpqTable,
|
|
1240
|
+
ULONGLONG ByteOffset,
|
|
1241
|
+
size_t Size,
|
|
1242
|
+
unsigned char * md5,
|
|
1243
|
+
DWORD dwKey,
|
|
1244
|
+
bool bCompress)
|
|
1245
|
+
{
|
|
1246
|
+
ULONGLONG FileOffset;
|
|
1247
|
+
void * pCompressed = NULL;
|
|
1248
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1249
|
+
|
|
1250
|
+
// Do we have to compress the table?
|
|
1251
|
+
if(bCompress)
|
|
1252
|
+
{
|
|
1253
|
+
int cbOutBuffer = (int)Size;
|
|
1254
|
+
int cbInBuffer = (int)Size;
|
|
1255
|
+
|
|
1256
|
+
// Allocate extra space for compressed table
|
|
1257
|
+
pCompressed = STORM_ALLOC(BYTE, Size);
|
|
1258
|
+
if(pCompressed == NULL)
|
|
1259
|
+
return ERROR_NOT_ENOUGH_MEMORY;
|
|
1260
|
+
|
|
1261
|
+
// Compress the table
|
|
1262
|
+
SCompCompress(pCompressed, &cbOutBuffer, pMpqTable, cbInBuffer, MPQ_COMPRESSION_ZLIB, 0, 0);
|
|
1263
|
+
|
|
1264
|
+
// If the compression failed, revert it. Otherwise, swap the tables
|
|
1265
|
+
if(cbOutBuffer >= cbInBuffer)
|
|
1266
|
+
{
|
|
1267
|
+
STORM_FREE(pCompressed);
|
|
1268
|
+
pCompressed = NULL;
|
|
1269
|
+
}
|
|
1270
|
+
else
|
|
1271
|
+
{
|
|
1272
|
+
pMpqTable = pCompressed;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
// Encrypt the table
|
|
1277
|
+
if(dwKey != 0)
|
|
1278
|
+
{
|
|
1279
|
+
BSWAP_ARRAY32_UNSIGNED(pMpqTable, Size);
|
|
1280
|
+
EncryptMpqBlock(pMpqTable, (DWORD)Size, dwKey);
|
|
1281
|
+
BSWAP_ARRAY32_UNSIGNED(pMpqTable, Size);
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
// Calculate the MD5
|
|
1285
|
+
if(md5 != NULL)
|
|
1286
|
+
{
|
|
1287
|
+
CalculateDataBlockHash(pMpqTable, (DWORD)Size, md5);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
// Save the table to the MPQ
|
|
1291
|
+
BSWAP_ARRAY32_UNSIGNED(pMpqTable, Size);
|
|
1292
|
+
FileOffset = ha->MpqPos + ByteOffset;
|
|
1293
|
+
if(!FileStream_Write(ha->pStream, &FileOffset, pMpqTable, (DWORD)Size))
|
|
1294
|
+
dwErrCode = GetLastError();
|
|
1295
|
+
|
|
1296
|
+
// Free the compressed table, if any
|
|
1297
|
+
if(pCompressed != NULL)
|
|
1298
|
+
STORM_FREE(pCompressed);
|
|
1299
|
+
return dwErrCode;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
static DWORD SaveExtTable(
|
|
1303
|
+
TMPQArchive * ha,
|
|
1304
|
+
TMPQExtHeader * pExtTable,
|
|
1305
|
+
ULONGLONG ByteOffset,
|
|
1306
|
+
DWORD dwTableSize,
|
|
1307
|
+
unsigned char * md5,
|
|
1308
|
+
DWORD dwKey,
|
|
1309
|
+
bool bCompress,
|
|
1310
|
+
LPDWORD pcbTotalSize)
|
|
1311
|
+
{
|
|
1312
|
+
ULONGLONG FileOffset;
|
|
1313
|
+
TMPQExtHeader * pCompressed = NULL;
|
|
1314
|
+
DWORD cbTotalSize = 0;
|
|
1315
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1316
|
+
|
|
1317
|
+
// Do we have to compress the table?
|
|
1318
|
+
if(bCompress)
|
|
1319
|
+
{
|
|
1320
|
+
int cbOutBuffer = (int)dwTableSize;
|
|
1321
|
+
int cbInBuffer = (int)dwTableSize;
|
|
1322
|
+
|
|
1323
|
+
// Allocate extra space for compressed table
|
|
1324
|
+
pCompressed = (TMPQExtHeader *)STORM_ALLOC(BYTE, dwTableSize);
|
|
1325
|
+
if(pCompressed == NULL)
|
|
1326
|
+
return ERROR_NOT_ENOUGH_MEMORY;
|
|
1327
|
+
|
|
1328
|
+
// Compress the table
|
|
1329
|
+
pCompressed->dwSignature = pExtTable->dwSignature;
|
|
1330
|
+
pCompressed->dwVersion = pExtTable->dwVersion;
|
|
1331
|
+
pCompressed->dwDataSize = pExtTable->dwDataSize;
|
|
1332
|
+
SCompCompress((pCompressed + 1), &cbOutBuffer, (pExtTable + 1), cbInBuffer, MPQ_COMPRESSION_ZLIB, 0, 0);
|
|
1333
|
+
|
|
1334
|
+
// If the compression failed, revert it. Otherwise, swap the tables
|
|
1335
|
+
if(cbOutBuffer >= cbInBuffer)
|
|
1336
|
+
{
|
|
1337
|
+
STORM_FREE(pCompressed);
|
|
1338
|
+
pCompressed = NULL;
|
|
1339
|
+
}
|
|
1340
|
+
else
|
|
1341
|
+
{
|
|
1342
|
+
pExtTable = pCompressed;
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
// Encrypt the table
|
|
1347
|
+
if(dwKey != 0)
|
|
1348
|
+
{
|
|
1349
|
+
BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize);
|
|
1350
|
+
EncryptMpqBlock(pExtTable + 1, (DWORD)(dwTableSize - sizeof(TMPQExtHeader)), dwKey);
|
|
1351
|
+
BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize);
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
// Calculate the MD5 of the table after
|
|
1355
|
+
if(md5 != NULL)
|
|
1356
|
+
{
|
|
1357
|
+
CalculateDataBlockHash(pExtTable, dwTableSize, md5);
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
// Save the table to the MPQ
|
|
1361
|
+
FileOffset = ha->MpqPos + ByteOffset;
|
|
1362
|
+
if(FileStream_Write(ha->pStream, &FileOffset, pExtTable, dwTableSize))
|
|
1363
|
+
cbTotalSize += dwTableSize;
|
|
1364
|
+
else
|
|
1365
|
+
dwErrCode = GetLastError();
|
|
1366
|
+
|
|
1367
|
+
// We have to write raw data MD5
|
|
1368
|
+
if(dwErrCode == ERROR_SUCCESS && ha->pHeader->dwRawChunkSize != 0)
|
|
1369
|
+
{
|
|
1370
|
+
dwErrCode = WriteMemDataMD5(ha->pStream,
|
|
1371
|
+
FileOffset,
|
|
1372
|
+
pExtTable,
|
|
1373
|
+
dwTableSize,
|
|
1374
|
+
ha->pHeader->dwRawChunkSize,
|
|
1375
|
+
&cbTotalSize);
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
// Give the total written size, if needed
|
|
1379
|
+
if(pcbTotalSize != NULL)
|
|
1380
|
+
*pcbTotalSize = cbTotalSize;
|
|
1381
|
+
|
|
1382
|
+
// Free the compressed table, if any
|
|
1383
|
+
if(pCompressed != NULL)
|
|
1384
|
+
STORM_FREE(pCompressed);
|
|
1385
|
+
return dwErrCode;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
//-----------------------------------------------------------------------------
|
|
1389
|
+
// Support for HET table
|
|
1390
|
+
|
|
1391
|
+
static void CreateHetHeader(
|
|
1392
|
+
TMPQHetTable * pHetTable,
|
|
1393
|
+
TMPQHetHeader * pHetHeader)
|
|
1394
|
+
{
|
|
1395
|
+
// Fill the common header
|
|
1396
|
+
pHetHeader->ExtHdr.dwSignature = HET_TABLE_SIGNATURE;
|
|
1397
|
+
pHetHeader->ExtHdr.dwVersion = 1;
|
|
1398
|
+
pHetHeader->ExtHdr.dwDataSize = 0;
|
|
1399
|
+
|
|
1400
|
+
// Fill the HET header
|
|
1401
|
+
pHetHeader->dwEntryCount = pHetTable->dwEntryCount;
|
|
1402
|
+
pHetHeader->dwTotalCount = pHetTable->dwTotalCount;
|
|
1403
|
+
pHetHeader->dwNameHashBitSize = pHetTable->dwNameHashBitSize;
|
|
1404
|
+
pHetHeader->dwIndexSizeTotal = pHetTable->dwIndexSizeTotal;
|
|
1405
|
+
pHetHeader->dwIndexSizeExtra = pHetTable->dwIndexSizeExtra;
|
|
1406
|
+
pHetHeader->dwIndexSize = pHetTable->dwIndexSize;
|
|
1407
|
+
pHetHeader->dwIndexTableSize = ((pHetHeader->dwIndexSizeTotal * pHetTable->dwTotalCount) + 7) / 8;
|
|
1408
|
+
|
|
1409
|
+
// Calculate the total size needed for holding HET table
|
|
1410
|
+
pHetHeader->ExtHdr.dwDataSize =
|
|
1411
|
+
pHetHeader->dwTableSize = sizeof(TMPQHetHeader) - sizeof(TMPQExtHeader) +
|
|
1412
|
+
pHetHeader->dwTotalCount +
|
|
1413
|
+
pHetHeader->dwIndexTableSize;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
TMPQHetTable * CreateHetTable(DWORD dwEntryCount, DWORD dwTotalCount, DWORD dwNameHashBitSize, LPBYTE pbSrcData)
|
|
1417
|
+
{
|
|
1418
|
+
TMPQHetTable * pHetTable;
|
|
1419
|
+
|
|
1420
|
+
pHetTable = STORM_ALLOC(TMPQHetTable, 1);
|
|
1421
|
+
if(pHetTable != NULL)
|
|
1422
|
+
{
|
|
1423
|
+
// Zero the HET table
|
|
1424
|
+
memset(pHetTable, 0, sizeof(TMPQHetTable));
|
|
1425
|
+
|
|
1426
|
+
// Hash sizes less than 0x40 bits are not tested
|
|
1427
|
+
assert(dwNameHashBitSize == 0x40);
|
|
1428
|
+
|
|
1429
|
+
// Calculate masks
|
|
1430
|
+
pHetTable->AndMask64 = ((dwNameHashBitSize != 0x40) ? ((ULONGLONG)1 << dwNameHashBitSize) : 0) - 1;
|
|
1431
|
+
pHetTable->OrMask64 = (ULONGLONG)1 << (dwNameHashBitSize - 1);
|
|
1432
|
+
|
|
1433
|
+
// If the total count is not entered, use default
|
|
1434
|
+
if(dwTotalCount == 0)
|
|
1435
|
+
dwTotalCount = (dwEntryCount * 4) / 3;
|
|
1436
|
+
|
|
1437
|
+
// Store the HET table parameters
|
|
1438
|
+
pHetTable->dwEntryCount = dwEntryCount;
|
|
1439
|
+
pHetTable->dwTotalCount = dwTotalCount;
|
|
1440
|
+
pHetTable->dwNameHashBitSize = dwNameHashBitSize;
|
|
1441
|
+
pHetTable->dwIndexSizeTotal = GetNecessaryBitCount(dwEntryCount);
|
|
1442
|
+
pHetTable->dwIndexSizeExtra = 0;
|
|
1443
|
+
pHetTable->dwIndexSize = pHetTable->dwIndexSizeTotal;
|
|
1444
|
+
|
|
1445
|
+
// Allocate array of hashes
|
|
1446
|
+
pHetTable->pNameHashes = STORM_ALLOC(BYTE, dwTotalCount);
|
|
1447
|
+
if(pHetTable->pNameHashes != NULL)
|
|
1448
|
+
{
|
|
1449
|
+
// Make sure the data are initialized
|
|
1450
|
+
memset(pHetTable->pNameHashes, 0, dwTotalCount);
|
|
1451
|
+
|
|
1452
|
+
// Allocate the bit array for file indexes
|
|
1453
|
+
pHetTable->pBetIndexes = TMPQBits::Create(dwTotalCount * pHetTable->dwIndexSizeTotal, 0xFF);
|
|
1454
|
+
if(pHetTable->pBetIndexes != NULL)
|
|
1455
|
+
{
|
|
1456
|
+
// Initialize the HET table from the source data (if given)
|
|
1457
|
+
if(pbSrcData != NULL)
|
|
1458
|
+
{
|
|
1459
|
+
// Copy the name hashes
|
|
1460
|
+
memcpy(pHetTable->pNameHashes, pbSrcData, dwTotalCount);
|
|
1461
|
+
|
|
1462
|
+
// Copy the file indexes
|
|
1463
|
+
memcpy(pHetTable->pBetIndexes->Elements, pbSrcData + dwTotalCount, pHetTable->pBetIndexes->NumberOfBytes);
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
// Return the result HET table
|
|
1467
|
+
return pHetTable;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
// Free the name hashes
|
|
1471
|
+
STORM_FREE(pHetTable->pNameHashes);
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
STORM_FREE(pHetTable);
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
// Failed
|
|
1478
|
+
return NULL;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
static DWORD InsertHetEntry(TMPQHetTable * pHetTable, ULONGLONG FileNameHash, DWORD dwFileIndex)
|
|
1482
|
+
{
|
|
1483
|
+
DWORD StartIndex;
|
|
1484
|
+
DWORD Index;
|
|
1485
|
+
BYTE NameHash1;
|
|
1486
|
+
|
|
1487
|
+
// Get the start index and the high 8 bits of the name hash
|
|
1488
|
+
StartIndex = Index = (DWORD)(FileNameHash % pHetTable->dwTotalCount);
|
|
1489
|
+
NameHash1 = (BYTE)(FileNameHash >> (pHetTable->dwNameHashBitSize - 8));
|
|
1490
|
+
|
|
1491
|
+
// Find a place where to put it
|
|
1492
|
+
for(;;)
|
|
1493
|
+
{
|
|
1494
|
+
// Did we find a free HET entry?
|
|
1495
|
+
if(pHetTable->pNameHashes[Index] == HET_ENTRY_FREE)
|
|
1496
|
+
{
|
|
1497
|
+
// Set the entry in the name hash table
|
|
1498
|
+
pHetTable->pNameHashes[Index] = NameHash1;
|
|
1499
|
+
|
|
1500
|
+
// Set the entry in the file index table
|
|
1501
|
+
pHetTable->pBetIndexes->SetBits(pHetTable->dwIndexSizeTotal * Index,
|
|
1502
|
+
pHetTable->dwIndexSize,
|
|
1503
|
+
&dwFileIndex,
|
|
1504
|
+
4);
|
|
1505
|
+
return ERROR_SUCCESS;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
// Move to the next entry in the HET table
|
|
1509
|
+
// If we came to the start index again, we are done
|
|
1510
|
+
Index = (Index + 1) % pHetTable->dwTotalCount;
|
|
1511
|
+
if(Index == StartIndex)
|
|
1512
|
+
break;
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
// No space in the HET table. Should never happen,
|
|
1516
|
+
// because the HET table is created according to the number of files
|
|
1517
|
+
assert(false);
|
|
1518
|
+
return ERROR_DISK_FULL;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
static TMPQHetTable * TranslateHetTable(TMPQHetHeader * pHetHeader)
|
|
1522
|
+
{
|
|
1523
|
+
TMPQHetTable * pHetTable = NULL;
|
|
1524
|
+
LPBYTE pbSrcData = (LPBYTE)(pHetHeader + 1);
|
|
1525
|
+
|
|
1526
|
+
// Sanity check
|
|
1527
|
+
assert(pHetHeader->ExtHdr.dwSignature == HET_TABLE_SIGNATURE);
|
|
1528
|
+
assert(pHetHeader->ExtHdr.dwVersion == 1);
|
|
1529
|
+
|
|
1530
|
+
// Verify size of the HET table
|
|
1531
|
+
if(pHetHeader->ExtHdr.dwDataSize >= (sizeof(TMPQHetHeader) - sizeof(TMPQExtHeader)))
|
|
1532
|
+
{
|
|
1533
|
+
// Verify the size of the table in the header
|
|
1534
|
+
if(pHetHeader->ExtHdr.dwDataSize >= pHetHeader->dwTableSize)
|
|
1535
|
+
{
|
|
1536
|
+
// The size of the HET table must be sum of header, hash and index table size
|
|
1537
|
+
if((sizeof(TMPQHetHeader) - sizeof(TMPQExtHeader) + pHetHeader->dwTotalCount + pHetHeader->dwIndexTableSize) == pHetHeader->dwTableSize)
|
|
1538
|
+
{
|
|
1539
|
+
// So far, all MPQs with HET Table have had total number of entries equal to 4/3 of file count
|
|
1540
|
+
// Exception: "2010 - Starcraft II\!maps\Tya's Zerg Defense (unprotected).SC2Map"
|
|
1541
|
+
// assert(((pHetHeader->dwEntryCount * 4) / 3) == pHetHeader->dwTotalCount);
|
|
1542
|
+
|
|
1543
|
+
// The size of one index is predictable as well
|
|
1544
|
+
assert(GetNecessaryBitCount(pHetHeader->dwEntryCount) == pHetHeader->dwIndexSizeTotal);
|
|
1545
|
+
|
|
1546
|
+
// The size of index table (in entries) is expected
|
|
1547
|
+
// to be the same like the hash table size (in bytes)
|
|
1548
|
+
assert(((pHetHeader->dwTotalCount * pHetHeader->dwIndexSizeTotal) + 7) / 8 == pHetHeader->dwIndexTableSize);
|
|
1549
|
+
|
|
1550
|
+
// Create translated table
|
|
1551
|
+
pHetTable = CreateHetTable(pHetHeader->dwEntryCount, pHetHeader->dwTotalCount, pHetHeader->dwNameHashBitSize, pbSrcData);
|
|
1552
|
+
if(pHetTable != NULL)
|
|
1553
|
+
{
|
|
1554
|
+
// Now the sizes in the hash table should be already set
|
|
1555
|
+
assert(pHetTable->dwEntryCount == pHetHeader->dwEntryCount);
|
|
1556
|
+
assert(pHetTable->dwTotalCount == pHetHeader->dwTotalCount);
|
|
1557
|
+
assert(pHetTable->dwIndexSizeTotal == pHetHeader->dwIndexSizeTotal);
|
|
1558
|
+
|
|
1559
|
+
// Copy the missing variables
|
|
1560
|
+
pHetTable->dwIndexSizeExtra = pHetHeader->dwIndexSizeExtra;
|
|
1561
|
+
pHetTable->dwIndexSize = pHetHeader->dwIndexSize;
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
return pHetTable;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
static TMPQExtHeader * TranslateHetTable(TMPQHetTable * pHetTable, ULONGLONG * pcbHetTable)
|
|
1571
|
+
{
|
|
1572
|
+
TMPQHetHeader * pHetHeader = NULL;
|
|
1573
|
+
TMPQHetHeader HetHeader;
|
|
1574
|
+
LPBYTE pbLinearTable = NULL;
|
|
1575
|
+
LPBYTE pbTrgData;
|
|
1576
|
+
|
|
1577
|
+
// Prepare header of the HET table
|
|
1578
|
+
CreateHetHeader(pHetTable, &HetHeader);
|
|
1579
|
+
|
|
1580
|
+
// Allocate space for the linear table
|
|
1581
|
+
pbLinearTable = STORM_ALLOC(BYTE, sizeof(TMPQExtHeader) + HetHeader.dwTableSize);
|
|
1582
|
+
if(pbLinearTable != NULL)
|
|
1583
|
+
{
|
|
1584
|
+
// Copy the table header
|
|
1585
|
+
pHetHeader = (TMPQHetHeader *)pbLinearTable;
|
|
1586
|
+
memcpy(pHetHeader, &HetHeader, sizeof(TMPQHetHeader));
|
|
1587
|
+
pbTrgData = (LPBYTE)(pHetHeader + 1);
|
|
1588
|
+
|
|
1589
|
+
// Copy the array of name hashes
|
|
1590
|
+
memcpy(pbTrgData, pHetTable->pNameHashes, pHetTable->dwTotalCount);
|
|
1591
|
+
pbTrgData += pHetTable->dwTotalCount;
|
|
1592
|
+
|
|
1593
|
+
// Copy the bit array of BET indexes
|
|
1594
|
+
memcpy(pbTrgData, pHetTable->pBetIndexes->Elements, HetHeader.dwIndexTableSize);
|
|
1595
|
+
|
|
1596
|
+
// Calculate the total size of the table, including the TMPQExtHeader
|
|
1597
|
+
if(pcbHetTable != NULL)
|
|
1598
|
+
{
|
|
1599
|
+
*pcbHetTable = (ULONGLONG)(sizeof(TMPQExtHeader) + HetHeader.dwTableSize);
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
// Keep Coverity happy
|
|
1604
|
+
assert((TMPQExtHeader *)&pHetHeader->ExtHdr == (TMPQExtHeader *)pbLinearTable);
|
|
1605
|
+
return (TMPQExtHeader *)pbLinearTable;
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
static DWORD GetFileIndex_Het(TMPQArchive * ha, const char * szFileName)
|
|
1609
|
+
{
|
|
1610
|
+
TMPQHetTable * pHetTable = ha->pHetTable;
|
|
1611
|
+
ULONGLONG FileNameHash;
|
|
1612
|
+
DWORD StartIndex;
|
|
1613
|
+
DWORD Index;
|
|
1614
|
+
BYTE NameHash1; // Upper 8 bits of the masked file name hash
|
|
1615
|
+
|
|
1616
|
+
// If there are no entries in the HET table, do nothing
|
|
1617
|
+
if(pHetTable->dwEntryCount == 0)
|
|
1618
|
+
return HASH_ENTRY_FREE;
|
|
1619
|
+
|
|
1620
|
+
// Do nothing if the MPQ has no HET table
|
|
1621
|
+
assert(ha->pHetTable != NULL);
|
|
1622
|
+
|
|
1623
|
+
// Calculate 64-bit hash of the file name
|
|
1624
|
+
FileNameHash = (HashStringJenkins(szFileName) & pHetTable->AndMask64) | pHetTable->OrMask64;
|
|
1625
|
+
|
|
1626
|
+
// Split the file name hash into two parts:
|
|
1627
|
+
// NameHash1: The highest 8 bits of the name hash
|
|
1628
|
+
// NameHash2: File name hash limited to hash size
|
|
1629
|
+
// Note: Our file table contains full name hash, no need to cut the high 8 bits before comparison
|
|
1630
|
+
NameHash1 = (BYTE)(FileNameHash >> (pHetTable->dwNameHashBitSize - 8));
|
|
1631
|
+
|
|
1632
|
+
// Calculate the starting index to the hash table
|
|
1633
|
+
StartIndex = Index = (DWORD)(FileNameHash % pHetTable->dwTotalCount);
|
|
1634
|
+
|
|
1635
|
+
// Go through HET table until we find a terminator
|
|
1636
|
+
while(pHetTable->pNameHashes[Index] != HET_ENTRY_FREE)
|
|
1637
|
+
{
|
|
1638
|
+
// Did we find a match ?
|
|
1639
|
+
if(pHetTable->pNameHashes[Index] == NameHash1)
|
|
1640
|
+
{
|
|
1641
|
+
DWORD dwFileIndex = 0;
|
|
1642
|
+
|
|
1643
|
+
// Get the file index
|
|
1644
|
+
if(pHetTable->pBetIndexes->GetBits(pHetTable->dwIndexSizeTotal * Index,
|
|
1645
|
+
pHetTable->dwIndexSize,
|
|
1646
|
+
&dwFileIndex,
|
|
1647
|
+
sizeof(DWORD)) == ERROR_SUCCESS)
|
|
1648
|
+
{
|
|
1649
|
+
// Verify the FileNameHash against the entry in the table of name hashes
|
|
1650
|
+
if(dwFileIndex <= ha->dwFileTableSize && ha->pFileTable[dwFileIndex].FileNameHash == FileNameHash)
|
|
1651
|
+
{
|
|
1652
|
+
return dwFileIndex;
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
// Move to the next entry in the HET table
|
|
1658
|
+
// If we came to the start index again, we are done
|
|
1659
|
+
Index = (Index + 1) % pHetTable->dwTotalCount;
|
|
1660
|
+
if(Index == StartIndex)
|
|
1661
|
+
break;
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
// File not found
|
|
1665
|
+
return HASH_ENTRY_FREE;
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
void FreeHetTable(TMPQHetTable * pHetTable)
|
|
1669
|
+
{
|
|
1670
|
+
if(pHetTable != NULL)
|
|
1671
|
+
{
|
|
1672
|
+
if(pHetTable->pNameHashes != NULL)
|
|
1673
|
+
STORM_FREE(pHetTable->pNameHashes);
|
|
1674
|
+
if(pHetTable->pBetIndexes != NULL)
|
|
1675
|
+
STORM_FREE(pHetTable->pBetIndexes);
|
|
1676
|
+
|
|
1677
|
+
STORM_FREE(pHetTable);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
//-----------------------------------------------------------------------------
|
|
1682
|
+
// Support for BET table
|
|
1683
|
+
|
|
1684
|
+
static bool VerifyBetHeaderSize(TMPQArchive * /* ha */, TMPQBetHeader * pBetHeader)
|
|
1685
|
+
{
|
|
1686
|
+
LPBYTE pbSrcData = (LPBYTE)(pBetHeader + 1);
|
|
1687
|
+
LPBYTE pbSrcEnd = (LPBYTE)(pBetHeader) + pBetHeader->dwTableSize;
|
|
1688
|
+
|
|
1689
|
+
// Move past the flags
|
|
1690
|
+
pbSrcData = pbSrcData + (pBetHeader->dwFlagCount * sizeof(DWORD)) + (pBetHeader->dwEntryCount * pBetHeader->dwTableEntrySize) / 8;
|
|
1691
|
+
return (pbSrcData <= pbSrcEnd);
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
static void CreateBetHeader(
|
|
1695
|
+
TMPQArchive * ha,
|
|
1696
|
+
TMPQBetHeader * pBetHeader)
|
|
1697
|
+
{
|
|
1698
|
+
TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
|
|
1699
|
+
TFileEntry * pFileEntry;
|
|
1700
|
+
ULONGLONG MaxByteOffset = 0;
|
|
1701
|
+
DWORD FlagArray[MAX_FLAG_INDEX];
|
|
1702
|
+
DWORD dwMaxFlagIndex = 0;
|
|
1703
|
+
DWORD dwMaxFileSize = 0;
|
|
1704
|
+
DWORD dwMaxCmpSize = 0;
|
|
1705
|
+
DWORD dwFlagIndex;
|
|
1706
|
+
|
|
1707
|
+
// Initialize array of flag combinations
|
|
1708
|
+
InitFileFlagArray(FlagArray);
|
|
1709
|
+
|
|
1710
|
+
// Fill the common header
|
|
1711
|
+
pBetHeader->ExtHdr.dwSignature = BET_TABLE_SIGNATURE;
|
|
1712
|
+
pBetHeader->ExtHdr.dwVersion = 1;
|
|
1713
|
+
pBetHeader->ExtHdr.dwDataSize = 0;
|
|
1714
|
+
|
|
1715
|
+
// Get the maximum values for the BET table
|
|
1716
|
+
pFileTableEnd = ha->pFileTable + ha->pHeader->dwBlockTableSize;
|
|
1717
|
+
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
|
|
1718
|
+
{
|
|
1719
|
+
//
|
|
1720
|
+
// Note: Deleted files must be counted as well
|
|
1721
|
+
//
|
|
1722
|
+
|
|
1723
|
+
// Highest file position in the MPQ
|
|
1724
|
+
if(pFileEntry->ByteOffset > MaxByteOffset)
|
|
1725
|
+
MaxByteOffset = pFileEntry->ByteOffset;
|
|
1726
|
+
|
|
1727
|
+
// Biggest file size
|
|
1728
|
+
if(pFileEntry->dwFileSize > dwMaxFileSize)
|
|
1729
|
+
dwMaxFileSize = pFileEntry->dwFileSize;
|
|
1730
|
+
|
|
1731
|
+
// Biggest compressed size
|
|
1732
|
+
if(pFileEntry->dwCmpSize > dwMaxCmpSize)
|
|
1733
|
+
dwMaxCmpSize = pFileEntry->dwCmpSize;
|
|
1734
|
+
|
|
1735
|
+
// Check if this flag was there before
|
|
1736
|
+
dwFlagIndex = GetFileFlagIndex(FlagArray, pFileEntry->dwFlags);
|
|
1737
|
+
if(dwFlagIndex > dwMaxFlagIndex)
|
|
1738
|
+
dwMaxFlagIndex = dwFlagIndex;
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
// Now save bit count for every piece of file information
|
|
1742
|
+
pBetHeader->dwBitIndex_FilePos = 0;
|
|
1743
|
+
pBetHeader->dwBitCount_FilePos = GetNecessaryBitCount(MaxByteOffset);
|
|
1744
|
+
|
|
1745
|
+
pBetHeader->dwBitIndex_FileSize = pBetHeader->dwBitIndex_FilePos + pBetHeader->dwBitCount_FilePos;
|
|
1746
|
+
pBetHeader->dwBitCount_FileSize = GetNecessaryBitCount(dwMaxFileSize);
|
|
1747
|
+
|
|
1748
|
+
pBetHeader->dwBitIndex_CmpSize = pBetHeader->dwBitIndex_FileSize + pBetHeader->dwBitCount_FileSize;
|
|
1749
|
+
pBetHeader->dwBitCount_CmpSize = GetNecessaryBitCount(dwMaxCmpSize);
|
|
1750
|
+
|
|
1751
|
+
pBetHeader->dwBitIndex_FlagIndex = pBetHeader->dwBitIndex_CmpSize + pBetHeader->dwBitCount_CmpSize;
|
|
1752
|
+
pBetHeader->dwBitCount_FlagIndex = GetNecessaryBitCount(dwMaxFlagIndex + 1);
|
|
1753
|
+
|
|
1754
|
+
pBetHeader->dwBitIndex_Unknown = pBetHeader->dwBitIndex_FlagIndex + pBetHeader->dwBitCount_FlagIndex;
|
|
1755
|
+
pBetHeader->dwBitCount_Unknown = 0;
|
|
1756
|
+
|
|
1757
|
+
// Calculate the total size of one entry
|
|
1758
|
+
pBetHeader->dwTableEntrySize = pBetHeader->dwBitCount_FilePos +
|
|
1759
|
+
pBetHeader->dwBitCount_FileSize +
|
|
1760
|
+
pBetHeader->dwBitCount_CmpSize +
|
|
1761
|
+
pBetHeader->dwBitCount_FlagIndex +
|
|
1762
|
+
pBetHeader->dwBitCount_Unknown;
|
|
1763
|
+
|
|
1764
|
+
// Save the file count and flag count
|
|
1765
|
+
pBetHeader->dwEntryCount = ha->pHeader->dwBlockTableSize;
|
|
1766
|
+
pBetHeader->dwFlagCount = dwMaxFlagIndex + 1;
|
|
1767
|
+
pBetHeader->dwUnknown08 = 0x10;
|
|
1768
|
+
|
|
1769
|
+
// Save the total size of the BET hash
|
|
1770
|
+
pBetHeader->dwBitTotal_NameHash2 = ha->pHetTable->dwNameHashBitSize - 0x08;
|
|
1771
|
+
pBetHeader->dwBitExtra_NameHash2 = 0;
|
|
1772
|
+
pBetHeader->dwBitCount_NameHash2 = pBetHeader->dwBitTotal_NameHash2;
|
|
1773
|
+
pBetHeader->dwNameHashArraySize = ((pBetHeader->dwBitTotal_NameHash2 * pBetHeader->dwEntryCount) + 7) / 8;
|
|
1774
|
+
|
|
1775
|
+
// Save the total table size
|
|
1776
|
+
pBetHeader->ExtHdr.dwDataSize =
|
|
1777
|
+
pBetHeader->dwTableSize = sizeof(TMPQBetHeader) - sizeof(TMPQExtHeader) +
|
|
1778
|
+
pBetHeader->dwFlagCount * sizeof(DWORD) +
|
|
1779
|
+
((pBetHeader->dwTableEntrySize * pBetHeader->dwEntryCount) + 7) / 8 +
|
|
1780
|
+
pBetHeader->dwNameHashArraySize;
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
TMPQBetTable * CreateBetTable(DWORD dwEntryCount)
|
|
1784
|
+
{
|
|
1785
|
+
TMPQBetTable * pBetTable;
|
|
1786
|
+
|
|
1787
|
+
// Allocate BET table
|
|
1788
|
+
pBetTable = STORM_ALLOC(TMPQBetTable, 1);
|
|
1789
|
+
if(pBetTable != NULL)
|
|
1790
|
+
{
|
|
1791
|
+
memset(pBetTable, 0, sizeof(TMPQBetTable));
|
|
1792
|
+
pBetTable->dwEntryCount = dwEntryCount;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
return pBetTable;
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
static TMPQBetTable * TranslateBetTable(
|
|
1799
|
+
TMPQArchive * ha,
|
|
1800
|
+
TMPQBetHeader * pBetHeader)
|
|
1801
|
+
{
|
|
1802
|
+
TMPQBetTable * pBetTable = NULL;
|
|
1803
|
+
LPBYTE pbSrcData = (LPBYTE)(pBetHeader + 1);
|
|
1804
|
+
DWORD LengthInBytes = 0;
|
|
1805
|
+
|
|
1806
|
+
// Sanity check
|
|
1807
|
+
assert(pBetHeader->ExtHdr.dwSignature == BET_TABLE_SIGNATURE);
|
|
1808
|
+
assert(pBetHeader->ExtHdr.dwVersion == 1);
|
|
1809
|
+
assert(ha->pHetTable != NULL);
|
|
1810
|
+
ha = ha;
|
|
1811
|
+
|
|
1812
|
+
// Verify size of the HET table
|
|
1813
|
+
if(pBetHeader->ExtHdr.dwDataSize >= (sizeof(TMPQBetHeader) - sizeof(TMPQExtHeader)))
|
|
1814
|
+
{
|
|
1815
|
+
// Verify the size of the table in the header
|
|
1816
|
+
if(pBetHeader->ExtHdr.dwDataSize >= pBetHeader->dwTableSize)
|
|
1817
|
+
{
|
|
1818
|
+
// The number of entries in the BET table must be the same like number of entries in the block table
|
|
1819
|
+
// Note: Ignored if there is no block table
|
|
1820
|
+
//assert(pBetHeader->dwEntryCount == ha->pHeader->dwBlockTableSize);
|
|
1821
|
+
assert(pBetHeader->dwEntryCount <= ha->dwMaxFileCount);
|
|
1822
|
+
|
|
1823
|
+
// The number of entries in the BET table must be the same like number of entries in the HET table
|
|
1824
|
+
// Note that if it's not, it is not a problem
|
|
1825
|
+
//assert(pBetHeader->dwEntryCount == ha->pHetTable->dwEntryCount);
|
|
1826
|
+
|
|
1827
|
+
// Verify an obviously-wrong values
|
|
1828
|
+
if(VerifyBetHeaderSize(ha, pBetHeader))
|
|
1829
|
+
{
|
|
1830
|
+
// Create translated table
|
|
1831
|
+
pBetTable = CreateBetTable(pBetHeader->dwEntryCount);
|
|
1832
|
+
if(pBetTable != NULL)
|
|
1833
|
+
{
|
|
1834
|
+
// Copy the variables from the header to the BetTable
|
|
1835
|
+
pBetTable->dwTableEntrySize = pBetHeader->dwTableEntrySize;
|
|
1836
|
+
pBetTable->dwBitIndex_FilePos = pBetHeader->dwBitIndex_FilePos;
|
|
1837
|
+
pBetTable->dwBitIndex_FileSize = pBetHeader->dwBitIndex_FileSize;
|
|
1838
|
+
pBetTable->dwBitIndex_CmpSize = pBetHeader->dwBitIndex_CmpSize;
|
|
1839
|
+
pBetTable->dwBitIndex_FlagIndex = pBetHeader->dwBitIndex_FlagIndex;
|
|
1840
|
+
pBetTable->dwBitIndex_Unknown = pBetHeader->dwBitIndex_Unknown;
|
|
1841
|
+
pBetTable->dwBitCount_FilePos = pBetHeader->dwBitCount_FilePos;
|
|
1842
|
+
pBetTable->dwBitCount_FileSize = pBetHeader->dwBitCount_FileSize;
|
|
1843
|
+
pBetTable->dwBitCount_CmpSize = pBetHeader->dwBitCount_CmpSize;
|
|
1844
|
+
pBetTable->dwBitCount_FlagIndex = pBetHeader->dwBitCount_FlagIndex;
|
|
1845
|
+
pBetTable->dwBitCount_Unknown = pBetHeader->dwBitCount_Unknown;
|
|
1846
|
+
|
|
1847
|
+
// Since we don't know what the "unknown" is, we'll assert when it's zero
|
|
1848
|
+
assert(pBetTable->dwBitCount_Unknown == 0);
|
|
1849
|
+
|
|
1850
|
+
// Allocate array for flags
|
|
1851
|
+
if(pBetHeader->dwFlagCount != 0)
|
|
1852
|
+
{
|
|
1853
|
+
// Allocate array for file flags and load it
|
|
1854
|
+
pBetTable->pFileFlags = STORM_ALLOC(DWORD, pBetHeader->dwFlagCount);
|
|
1855
|
+
if(pBetTable->pFileFlags != NULL)
|
|
1856
|
+
{
|
|
1857
|
+
LengthInBytes = pBetHeader->dwFlagCount * sizeof(DWORD);
|
|
1858
|
+
memcpy(pBetTable->pFileFlags, pbSrcData, LengthInBytes);
|
|
1859
|
+
BSWAP_ARRAY32_UNSIGNED(pBetTable->pFileFlags, LengthInBytes);
|
|
1860
|
+
pbSrcData += LengthInBytes;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
// Save the number of flags
|
|
1864
|
+
pBetTable->dwFlagCount = pBetHeader->dwFlagCount;
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
// Load the bit-based file table
|
|
1868
|
+
pBetTable->pFileTable = TMPQBits::Create(pBetTable->dwTableEntrySize * pBetHeader->dwEntryCount, 0);
|
|
1869
|
+
if(pBetTable->pFileTable != NULL)
|
|
1870
|
+
{
|
|
1871
|
+
LengthInBytes = (pBetTable->pFileTable->NumberOfBits + 7) / 8;
|
|
1872
|
+
memcpy(pBetTable->pFileTable->Elements, pbSrcData, LengthInBytes);
|
|
1873
|
+
pbSrcData += LengthInBytes;
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
// Fill the sizes of BET hash
|
|
1877
|
+
pBetTable->dwBitTotal_NameHash2 = pBetHeader->dwBitTotal_NameHash2;
|
|
1878
|
+
pBetTable->dwBitExtra_NameHash2 = pBetHeader->dwBitExtra_NameHash2;
|
|
1879
|
+
pBetTable->dwBitCount_NameHash2 = pBetHeader->dwBitCount_NameHash2;
|
|
1880
|
+
|
|
1881
|
+
// Create and load the array of BET hashes
|
|
1882
|
+
pBetTable->pNameHashes = TMPQBits::Create(pBetTable->dwBitTotal_NameHash2 * pBetHeader->dwEntryCount, 0);
|
|
1883
|
+
if(pBetTable->pNameHashes != NULL)
|
|
1884
|
+
{
|
|
1885
|
+
LengthInBytes = (pBetTable->pNameHashes->NumberOfBits + 7) / 8;
|
|
1886
|
+
memcpy(pBetTable->pNameHashes->Elements, pbSrcData, LengthInBytes);
|
|
1887
|
+
// pbSrcData += LengthInBytes;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
// Dump both tables
|
|
1891
|
+
// DumpHetAndBetTable(ha->pHetTable, pBetTable);
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
return pBetTable;
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
TMPQExtHeader * TranslateBetTable(
|
|
1901
|
+
TMPQArchive * ha,
|
|
1902
|
+
ULONGLONG * pcbBetTable)
|
|
1903
|
+
{
|
|
1904
|
+
TMPQBetHeader * pBetHeader = NULL;
|
|
1905
|
+
TMPQBetHeader BetHeader;
|
|
1906
|
+
TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
|
|
1907
|
+
TFileEntry * pFileEntry;
|
|
1908
|
+
TMPQBits * pBitArray = NULL;
|
|
1909
|
+
LPBYTE pbLinearTable = NULL;
|
|
1910
|
+
LPBYTE pbTrgData;
|
|
1911
|
+
DWORD LengthInBytes;
|
|
1912
|
+
DWORD FlagArray[MAX_FLAG_INDEX];
|
|
1913
|
+
|
|
1914
|
+
// Calculate the bit sizes of various entries
|
|
1915
|
+
InitFileFlagArray(FlagArray);
|
|
1916
|
+
CreateBetHeader(ha, &BetHeader);
|
|
1917
|
+
|
|
1918
|
+
// Allocate space
|
|
1919
|
+
pbLinearTable = STORM_ALLOC(BYTE, sizeof(TMPQExtHeader) + BetHeader.dwTableSize);
|
|
1920
|
+
if(pbLinearTable != NULL)
|
|
1921
|
+
{
|
|
1922
|
+
// Copy the BET header to the linear buffer
|
|
1923
|
+
pBetHeader = (TMPQBetHeader *)pbLinearTable;
|
|
1924
|
+
memcpy(pBetHeader, &BetHeader, sizeof(TMPQBetHeader));
|
|
1925
|
+
pbTrgData = (LPBYTE)(pBetHeader + 1);
|
|
1926
|
+
|
|
1927
|
+
// Save the bit-based block table
|
|
1928
|
+
pBitArray = TMPQBits::Create(BetHeader.dwEntryCount * BetHeader.dwTableEntrySize, 0);
|
|
1929
|
+
if(pBitArray != NULL)
|
|
1930
|
+
{
|
|
1931
|
+
DWORD dwFlagIndex = 0;
|
|
1932
|
+
DWORD nBitOffset = 0;
|
|
1933
|
+
|
|
1934
|
+
// Construct the bit-based file table
|
|
1935
|
+
pFileTableEnd = ha->pFileTable + BetHeader.dwEntryCount;
|
|
1936
|
+
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
|
|
1937
|
+
{
|
|
1938
|
+
//
|
|
1939
|
+
// Note: Missing files must be included as well
|
|
1940
|
+
//
|
|
1941
|
+
|
|
1942
|
+
// Save the byte offset
|
|
1943
|
+
pBitArray->SetBits(nBitOffset + BetHeader.dwBitIndex_FilePos,
|
|
1944
|
+
BetHeader.dwBitCount_FilePos,
|
|
1945
|
+
&pFileEntry->ByteOffset,
|
|
1946
|
+
8);
|
|
1947
|
+
pBitArray->SetBits(nBitOffset + BetHeader.dwBitIndex_FileSize,
|
|
1948
|
+
BetHeader.dwBitCount_FileSize,
|
|
1949
|
+
&pFileEntry->dwFileSize,
|
|
1950
|
+
4);
|
|
1951
|
+
pBitArray->SetBits(nBitOffset + BetHeader.dwBitIndex_CmpSize,
|
|
1952
|
+
BetHeader.dwBitCount_CmpSize,
|
|
1953
|
+
&pFileEntry->dwCmpSize,
|
|
1954
|
+
4);
|
|
1955
|
+
|
|
1956
|
+
// Save the flag index
|
|
1957
|
+
dwFlagIndex = GetFileFlagIndex(FlagArray, pFileEntry->dwFlags);
|
|
1958
|
+
pBitArray->SetBits(nBitOffset + BetHeader.dwBitIndex_FlagIndex,
|
|
1959
|
+
BetHeader.dwBitCount_FlagIndex,
|
|
1960
|
+
&dwFlagIndex,
|
|
1961
|
+
4);
|
|
1962
|
+
|
|
1963
|
+
// Move the bit offset
|
|
1964
|
+
nBitOffset += BetHeader.dwTableEntrySize;
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1967
|
+
// Write the array of flags
|
|
1968
|
+
LengthInBytes = BetHeader.dwFlagCount * sizeof(DWORD);
|
|
1969
|
+
memcpy(pbTrgData, FlagArray, LengthInBytes);
|
|
1970
|
+
BSWAP_ARRAY32_UNSIGNED(pbTrgData, LengthInBytes);
|
|
1971
|
+
pbTrgData += LengthInBytes;
|
|
1972
|
+
|
|
1973
|
+
// Write the bit-based block table
|
|
1974
|
+
LengthInBytes = (pBitArray->NumberOfBits + 7) / 8;
|
|
1975
|
+
memcpy(pbTrgData, pBitArray->Elements, LengthInBytes);
|
|
1976
|
+
pbTrgData += LengthInBytes;
|
|
1977
|
+
|
|
1978
|
+
// Free the bit array
|
|
1979
|
+
STORM_FREE(pBitArray);
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
// Create bit array for name hashes
|
|
1983
|
+
pBitArray = TMPQBits::Create(BetHeader.dwBitTotal_NameHash2 * BetHeader.dwEntryCount, 0);
|
|
1984
|
+
if(pBitArray != NULL)
|
|
1985
|
+
{
|
|
1986
|
+
DWORD dwFileIndex = 0;
|
|
1987
|
+
|
|
1988
|
+
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
|
|
1989
|
+
{
|
|
1990
|
+
// Insert the name hash to the bit array
|
|
1991
|
+
pBitArray->SetBits(BetHeader.dwBitTotal_NameHash2 * dwFileIndex,
|
|
1992
|
+
BetHeader.dwBitCount_NameHash2,
|
|
1993
|
+
&pFileEntry->FileNameHash,
|
|
1994
|
+
8);
|
|
1995
|
+
|
|
1996
|
+
assert(dwFileIndex < BetHeader.dwEntryCount);
|
|
1997
|
+
dwFileIndex++;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
// Write the array of BET hashes
|
|
2001
|
+
LengthInBytes = (pBitArray->NumberOfBits + 7) / 8;
|
|
2002
|
+
memcpy(pbTrgData, pBitArray->Elements, LengthInBytes);
|
|
2003
|
+
// pbTrgData += LengthInBytes;
|
|
2004
|
+
|
|
2005
|
+
// Free the bit array
|
|
2006
|
+
STORM_FREE(pBitArray);
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
// Write the size of the BET table in the MPQ
|
|
2010
|
+
if(pcbBetTable != NULL)
|
|
2011
|
+
{
|
|
2012
|
+
*pcbBetTable = (ULONGLONG)(sizeof(TMPQExtHeader) + BetHeader.dwTableSize);
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
// Keep Coverity happy
|
|
2017
|
+
assert((TMPQExtHeader *)&pBetHeader->ExtHdr == (TMPQExtHeader *)pbLinearTable);
|
|
2018
|
+
return (TMPQExtHeader *)pbLinearTable;
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
void FreeBetTable(TMPQBetTable * pBetTable)
|
|
2022
|
+
{
|
|
2023
|
+
if(pBetTable != NULL)
|
|
2024
|
+
{
|
|
2025
|
+
if(pBetTable->pFileTable != NULL)
|
|
2026
|
+
STORM_FREE(pBetTable->pFileTable);
|
|
2027
|
+
if(pBetTable->pFileFlags != NULL)
|
|
2028
|
+
STORM_FREE(pBetTable->pFileFlags);
|
|
2029
|
+
if(pBetTable->pNameHashes != NULL)
|
|
2030
|
+
STORM_FREE(pBetTable->pNameHashes);
|
|
2031
|
+
|
|
2032
|
+
STORM_FREE(pBetTable);
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
//-----------------------------------------------------------------------------
|
|
2037
|
+
// Support for file table
|
|
2038
|
+
|
|
2039
|
+
TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcFileLocale, LPDWORD PtrHashIndex)
|
|
2040
|
+
{
|
|
2041
|
+
TMPQHash * pHash;
|
|
2042
|
+
DWORD dwFileIndex;
|
|
2043
|
+
|
|
2044
|
+
// First, we have to search the classic hash table
|
|
2045
|
+
// This is because on renaming, deleting, or changing locale,
|
|
2046
|
+
// we will need the pointer to hash table entry
|
|
2047
|
+
if(ha->pHashTable != NULL)
|
|
2048
|
+
{
|
|
2049
|
+
pHash = GetHashEntryLocale(ha, szFileName, lcFileLocale);
|
|
2050
|
+
if(pHash != NULL && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
|
|
2051
|
+
{
|
|
2052
|
+
if(PtrHashIndex != NULL)
|
|
2053
|
+
PtrHashIndex[0] = (DWORD)(pHash - ha->pHashTable);
|
|
2054
|
+
return ha->pFileTable + MPQ_BLOCK_INDEX(pHash);
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2058
|
+
// If we have HET table in the MPQ, try to find the file in HET table
|
|
2059
|
+
if(ha->pHetTable != NULL)
|
|
2060
|
+
{
|
|
2061
|
+
dwFileIndex = GetFileIndex_Het(ha, szFileName);
|
|
2062
|
+
if(dwFileIndex != HASH_ENTRY_FREE)
|
|
2063
|
+
return ha->pFileTable + dwFileIndex;
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
// Not found
|
|
2067
|
+
return NULL;
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcFileLocale, LPDWORD PtrHashIndex)
|
|
2071
|
+
{
|
|
2072
|
+
TMPQHash * pHash;
|
|
2073
|
+
DWORD dwFileIndex;
|
|
2074
|
+
|
|
2075
|
+
// If the hash table is present, find the entry from hash table
|
|
2076
|
+
if(ha->pHashTable != NULL)
|
|
2077
|
+
{
|
|
2078
|
+
pHash = GetHashEntryExact(ha, szFileName, lcFileLocale);
|
|
2079
|
+
if(pHash != NULL && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
|
|
2080
|
+
{
|
|
2081
|
+
if(PtrHashIndex != NULL)
|
|
2082
|
+
PtrHashIndex[0] = (DWORD)(pHash - ha->pHashTable);
|
|
2083
|
+
return ha->pFileTable + MPQ_BLOCK_INDEX(pHash);
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
// If we have HET table in the MPQ, try to find the file in HET table
|
|
2088
|
+
if(ha->pHetTable != NULL)
|
|
2089
|
+
{
|
|
2090
|
+
dwFileIndex = GetFileIndex_Het(ha, szFileName);
|
|
2091
|
+
if(dwFileIndex != HASH_ENTRY_FREE)
|
|
2092
|
+
{
|
|
2093
|
+
if(PtrHashIndex != NULL)
|
|
2094
|
+
PtrHashIndex[0] = HASH_ENTRY_FREE;
|
|
2095
|
+
return ha->pFileTable + dwFileIndex;
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
// Not found
|
|
2100
|
+
return NULL;
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
void AllocateFileName(TMPQArchive * ha, TFileEntry * pFileEntry, const char * szFileName)
|
|
2104
|
+
{
|
|
2105
|
+
// Sanity check
|
|
2106
|
+
assert(pFileEntry != NULL);
|
|
2107
|
+
|
|
2108
|
+
// If the file name is pseudo file name, free it at this point
|
|
2109
|
+
if(IsPseudoFileName(pFileEntry->szFileName, NULL))
|
|
2110
|
+
{
|
|
2111
|
+
if(pFileEntry->szFileName != NULL)
|
|
2112
|
+
STORM_FREE(pFileEntry->szFileName);
|
|
2113
|
+
pFileEntry->szFileName = NULL;
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
// Only allocate new file name if it's not there yet
|
|
2117
|
+
if(pFileEntry->szFileName == NULL)
|
|
2118
|
+
{
|
|
2119
|
+
pFileEntry->szFileName = STORM_ALLOC(char, strlen(szFileName) + 1);
|
|
2120
|
+
if(pFileEntry->szFileName != NULL)
|
|
2121
|
+
strcpy(pFileEntry->szFileName, szFileName);
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
// We also need to create the file name hash
|
|
2125
|
+
if(ha->pHetTable != NULL)
|
|
2126
|
+
{
|
|
2127
|
+
ULONGLONG AndMask64 = ha->pHetTable->AndMask64;
|
|
2128
|
+
ULONGLONG OrMask64 = ha->pHetTable->OrMask64;
|
|
2129
|
+
|
|
2130
|
+
pFileEntry->FileNameHash = (HashStringJenkins(szFileName) & AndMask64) | OrMask64;
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
TFileEntry * AllocateFileEntry(TMPQArchive * ha, const char * szFileName, LCID lcFileLocale, LPDWORD PtrHashIndex)
|
|
2135
|
+
{
|
|
2136
|
+
TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
|
|
2137
|
+
TFileEntry * pFreeEntry = NULL;
|
|
2138
|
+
TFileEntry * pFileEntry;
|
|
2139
|
+
TMPQHash * pHash = NULL;
|
|
2140
|
+
DWORD dwReservedFiles = ha->dwReservedFiles;
|
|
2141
|
+
DWORD dwFreeCount = 0;
|
|
2142
|
+
|
|
2143
|
+
// Sanity check: File table size must be greater or equal to max file count
|
|
2144
|
+
assert(ha->dwFileTableSize >= ha->dwMaxFileCount);
|
|
2145
|
+
|
|
2146
|
+
// If we are saving MPQ tables, we don't tale number of reserved files into account
|
|
2147
|
+
dwReservedFiles = (ha->dwFlags & MPQ_FLAG_SAVING_TABLES) ? 0 : ha->dwReservedFiles;
|
|
2148
|
+
|
|
2149
|
+
// Now find a free entry in the file table.
|
|
2150
|
+
// Note that in the case when free entries are in the middle,
|
|
2151
|
+
// we need to use these
|
|
2152
|
+
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
|
|
2153
|
+
{
|
|
2154
|
+
if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0)
|
|
2155
|
+
{
|
|
2156
|
+
// Remember the first free entry
|
|
2157
|
+
if(pFreeEntry == NULL)
|
|
2158
|
+
pFreeEntry = pFileEntry;
|
|
2159
|
+
dwFreeCount++;
|
|
2160
|
+
|
|
2161
|
+
// If the number of free items is greater than number
|
|
2162
|
+
// of reserved items, We can add the file
|
|
2163
|
+
if(dwFreeCount > dwReservedFiles)
|
|
2164
|
+
break;
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
// If the total number of free entries is less than number of reserved files,
|
|
2169
|
+
// we cannot add the file to the archive
|
|
2170
|
+
if(pFreeEntry == NULL || dwFreeCount <= dwReservedFiles)
|
|
2171
|
+
return NULL;
|
|
2172
|
+
|
|
2173
|
+
// Initialize the file entry and set its file name
|
|
2174
|
+
memset(pFreeEntry, 0, sizeof(TFileEntry));
|
|
2175
|
+
AllocateFileName(ha, pFreeEntry, szFileName);
|
|
2176
|
+
|
|
2177
|
+
// If the archive has a hash table, we need to first free entry there
|
|
2178
|
+
if(ha->pHashTable != NULL)
|
|
2179
|
+
{
|
|
2180
|
+
// Make sure that the entry is not there yet
|
|
2181
|
+
assert(GetHashEntryExact(ha, szFileName, lcFileLocale) == NULL);
|
|
2182
|
+
|
|
2183
|
+
// Find a free hash table entry for the name
|
|
2184
|
+
pHash = AllocateHashEntry(ha, pFreeEntry, lcFileLocale);
|
|
2185
|
+
if(pHash == NULL)
|
|
2186
|
+
return NULL;
|
|
2187
|
+
|
|
2188
|
+
// Set the file index to the hash table
|
|
2189
|
+
pHash->dwBlockIndex = (DWORD)(pFreeEntry - ha->pFileTable);
|
|
2190
|
+
PtrHashIndex[0] = (DWORD)(pHash - ha->pHashTable);
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
// If the archive has a HET table, just do some checks
|
|
2194
|
+
// Note: Don't bother modifying the HET table. It will be rebuilt from scratch after, anyway
|
|
2195
|
+
if(ha->pHetTable != NULL)
|
|
2196
|
+
{
|
|
2197
|
+
assert(GetFileIndex_Het(ha, szFileName) == HASH_ENTRY_FREE);
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
// Return the free table entry
|
|
2201
|
+
return pFreeEntry;
|
|
2202
|
+
}
|
|
2203
|
+
|
|
2204
|
+
DWORD RenameFileEntry(
|
|
2205
|
+
TMPQArchive * ha,
|
|
2206
|
+
TMPQFile * hf,
|
|
2207
|
+
const char * szNewFileName)
|
|
2208
|
+
{
|
|
2209
|
+
TFileEntry * pFileEntry = hf->pFileEntry;
|
|
2210
|
+
TMPQHash * pHashEntry = hf->pHashEntry;
|
|
2211
|
+
LCID lcFileLocale = 0;
|
|
2212
|
+
|
|
2213
|
+
// If the archive hash hash table, we need to free the hash table entry
|
|
2214
|
+
if(ha->pHashTable != NULL)
|
|
2215
|
+
{
|
|
2216
|
+
// The file must have hash table entry assigned
|
|
2217
|
+
// Will exit if there are multiple HASH entries pointing to the same file entry
|
|
2218
|
+
if(pHashEntry == NULL)
|
|
2219
|
+
return ERROR_NOT_SUPPORTED;
|
|
2220
|
+
|
|
2221
|
+
// Save the locale
|
|
2222
|
+
lcFileLocale = SFILE_MAKE_LCID(pHashEntry->Locale, pHashEntry->Platform);
|
|
2223
|
+
|
|
2224
|
+
// Mark the hash table entry as deleted
|
|
2225
|
+
pHashEntry->dwName1 = 0xFFFFFFFF;
|
|
2226
|
+
pHashEntry->dwName2 = 0xFFFFFFFF;
|
|
2227
|
+
pHashEntry->Locale = 0xFFFF;
|
|
2228
|
+
pHashEntry->Platform = 0xFF;
|
|
2229
|
+
pHashEntry->Reserved = 0xFF;
|
|
2230
|
+
pHashEntry->dwBlockIndex = HASH_ENTRY_DELETED;
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
// Free the old file name
|
|
2234
|
+
if(pFileEntry->szFileName != NULL)
|
|
2235
|
+
STORM_FREE(pFileEntry->szFileName);
|
|
2236
|
+
pFileEntry->szFileName = NULL;
|
|
2237
|
+
|
|
2238
|
+
// Allocate new file name
|
|
2239
|
+
AllocateFileName(ha, pFileEntry, szNewFileName);
|
|
2240
|
+
|
|
2241
|
+
// Allocate new hash entry
|
|
2242
|
+
if(ha->pHashTable != NULL)
|
|
2243
|
+
{
|
|
2244
|
+
// Since we freed one hash entry before, this must succeed
|
|
2245
|
+
hf->pHashEntry = AllocateHashEntry(ha, pFileEntry, lcFileLocale);
|
|
2246
|
+
assert(hf->pHashEntry != NULL);
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
return ERROR_SUCCESS;
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
DWORD DeleteFileEntry(TMPQArchive * ha, TMPQFile * hf)
|
|
2253
|
+
{
|
|
2254
|
+
TFileEntry * pFileEntry = hf->pFileEntry;
|
|
2255
|
+
TMPQHash * pHashEntry = hf->pHashEntry;
|
|
2256
|
+
|
|
2257
|
+
// If the archive hash hash table, we need to free the hash table entry
|
|
2258
|
+
if(ha->pHashTable != NULL)
|
|
2259
|
+
{
|
|
2260
|
+
// The file must have hash table entry assigned
|
|
2261
|
+
// Will exit if there are multiple HASH entries pointing to the same file entry
|
|
2262
|
+
if(pHashEntry == NULL)
|
|
2263
|
+
return ERROR_NOT_SUPPORTED;
|
|
2264
|
+
|
|
2265
|
+
// Mark the hash table entry as deleted
|
|
2266
|
+
pHashEntry->dwName1 = 0xFFFFFFFF;
|
|
2267
|
+
pHashEntry->dwName2 = 0xFFFFFFFF;
|
|
2268
|
+
pHashEntry->Locale = 0xFFFF;
|
|
2269
|
+
pHashEntry->Platform = 0xFF;
|
|
2270
|
+
pHashEntry->Reserved = 0xFF;
|
|
2271
|
+
pHashEntry->dwBlockIndex = HASH_ENTRY_DELETED;
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
// Free the file name, and set the file entry as deleted
|
|
2275
|
+
if(pFileEntry->szFileName != NULL)
|
|
2276
|
+
STORM_FREE(pFileEntry->szFileName);
|
|
2277
|
+
pFileEntry->szFileName = NULL;
|
|
2278
|
+
|
|
2279
|
+
//
|
|
2280
|
+
// Don't modify the HET table, because it gets recreated by the caller
|
|
2281
|
+
// Don't decrement the number of entries in the file table
|
|
2282
|
+
// Keep Byte Offset, file size, compressed size, CRC32 and MD5
|
|
2283
|
+
// Clear the file name hash and the MPQ_FILE_EXISTS bit
|
|
2284
|
+
//
|
|
2285
|
+
|
|
2286
|
+
pFileEntry->dwFlags &= ~MPQ_FILE_EXISTS;
|
|
2287
|
+
pFileEntry->FileNameHash = 0;
|
|
2288
|
+
return ERROR_SUCCESS;
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
DWORD InvalidateInternalFile(TMPQArchive * ha, const char * szFileName, DWORD dwFlagNone, DWORD dwFlagNew, DWORD dwForceAddTheFile = 0)
|
|
2292
|
+
{
|
|
2293
|
+
TMPQFile * hf = NULL;
|
|
2294
|
+
DWORD dwFileFlags = MPQ_FILE_DEFAULT_INTERNAL;
|
|
2295
|
+
DWORD dwErrCode = ERROR_FILE_NOT_FOUND;
|
|
2296
|
+
|
|
2297
|
+
// Open the file from the MPQ
|
|
2298
|
+
if(SFileOpenFileEx((HANDLE)ha, szFileName, SFILE_OPEN_BASE_FILE, (HANDLE *)&hf))
|
|
2299
|
+
{
|
|
2300
|
+
// Remember the file flags
|
|
2301
|
+
dwFileFlags = hf->pFileEntry->dwFlags;
|
|
2302
|
+
|
|
2303
|
+
// Delete the file entry
|
|
2304
|
+
dwErrCode = DeleteFileEntry(ha, hf);
|
|
2305
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2306
|
+
dwForceAddTheFile = 1;
|
|
2307
|
+
|
|
2308
|
+
// Close the file
|
|
2309
|
+
FreeFileHandle(hf);
|
|
2310
|
+
}
|
|
2311
|
+
|
|
2312
|
+
// Are we going to add the file?
|
|
2313
|
+
if(dwForceAddTheFile)
|
|
2314
|
+
{
|
|
2315
|
+
ha->dwFlags |= dwFlagNew;
|
|
2316
|
+
ha->dwReservedFiles++;
|
|
2317
|
+
}
|
|
2318
|
+
else
|
|
2319
|
+
{
|
|
2320
|
+
ha->dwFlags |= dwFlagNone;
|
|
2321
|
+
dwFileFlags = 0;
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
// Return the intended file flags
|
|
2325
|
+
return dwFileFlags;
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
void InvalidateInternalFiles(TMPQArchive * ha)
|
|
2329
|
+
{
|
|
2330
|
+
// Do nothing if we are in the middle of saving internal files
|
|
2331
|
+
if(!(ha->dwFlags & MPQ_FLAG_SAVING_TABLES))
|
|
2332
|
+
{
|
|
2333
|
+
//
|
|
2334
|
+
// We clear the file entries for (listfile), (attributes) and (signature)
|
|
2335
|
+
// For each internal file cleared, we increment the number
|
|
2336
|
+
// of reserved entries in the file table.
|
|
2337
|
+
//
|
|
2338
|
+
|
|
2339
|
+
// Invalidate the (listfile), if not done yet
|
|
2340
|
+
if((ha->dwFlags & (MPQ_FLAG_LISTFILE_NONE | MPQ_FLAG_LISTFILE_NEW)) == 0)
|
|
2341
|
+
{
|
|
2342
|
+
ha->dwFileFlags1 = InvalidateInternalFile(ha, LISTFILE_NAME, MPQ_FLAG_LISTFILE_NONE, MPQ_FLAG_LISTFILE_NEW, (ha->dwFlags & MPQ_FLAG_LISTFILE_FORCE));
|
|
2343
|
+
}
|
|
2344
|
+
|
|
2345
|
+
// Invalidate the (attributes), if not done yet
|
|
2346
|
+
if((ha->dwFlags & (MPQ_FLAG_ATTRIBUTES_NONE | MPQ_FLAG_ATTRIBUTES_NEW)) == 0)
|
|
2347
|
+
{
|
|
2348
|
+
ha->dwFileFlags2 = InvalidateInternalFile(ha, ATTRIBUTES_NAME, MPQ_FLAG_ATTRIBUTES_NONE, MPQ_FLAG_ATTRIBUTES_NEW);
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
// Invalidate the (signature), if not done yet
|
|
2352
|
+
if((ha->dwFlags & (MPQ_FLAG_SIGNATURE_NONE | MPQ_FLAG_SIGNATURE_NEW)) == 0)
|
|
2353
|
+
{
|
|
2354
|
+
ha->dwFileFlags3 = InvalidateInternalFile(ha, SIGNATURE_NAME, MPQ_FLAG_SIGNATURE_NONE, MPQ_FLAG_SIGNATURE_NEW);
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
// Remember that the MPQ has been changed
|
|
2358
|
+
ha->dwFlags |= MPQ_FLAG_CHANGED;
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
|
|
2362
|
+
//-----------------------------------------------------------------------------
|
|
2363
|
+
// Support for file tables - hash table, block table, hi-block table
|
|
2364
|
+
|
|
2365
|
+
DWORD CreateHashTable(TMPQArchive * ha, DWORD dwHashTableSize)
|
|
2366
|
+
{
|
|
2367
|
+
TMPQHash * pHashTable;
|
|
2368
|
+
|
|
2369
|
+
// Sanity checks
|
|
2370
|
+
assert((dwHashTableSize & (dwHashTableSize - 1)) == 0);
|
|
2371
|
+
assert(ha->pHashTable == NULL);
|
|
2372
|
+
|
|
2373
|
+
// If the required hash table size is zero, don't create anything
|
|
2374
|
+
if(dwHashTableSize == 0)
|
|
2375
|
+
dwHashTableSize = HASH_TABLE_SIZE_DEFAULT;
|
|
2376
|
+
|
|
2377
|
+
// Create the hash table
|
|
2378
|
+
pHashTable = STORM_ALLOC(TMPQHash, dwHashTableSize);
|
|
2379
|
+
if(pHashTable == NULL)
|
|
2380
|
+
return ERROR_NOT_ENOUGH_MEMORY;
|
|
2381
|
+
|
|
2382
|
+
// Fill it
|
|
2383
|
+
memset(pHashTable, 0xFF, dwHashTableSize * sizeof(TMPQHash));
|
|
2384
|
+
ha->pHeader->dwHashTableSize = dwHashTableSize;
|
|
2385
|
+
ha->dwMaxFileCount = dwHashTableSize;
|
|
2386
|
+
ha->pHashTable = pHashTable;
|
|
2387
|
+
return ERROR_SUCCESS;
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
static TMPQHash * LoadHashTable(TMPQArchive * ha)
|
|
2391
|
+
{
|
|
2392
|
+
TMPQHeader * pHeader = ha->pHeader;
|
|
2393
|
+
ULONGLONG ByteOffset;
|
|
2394
|
+
TMPQHash * pHashTable = NULL;
|
|
2395
|
+
DWORD dwTableSize;
|
|
2396
|
+
DWORD dwCmpSize;
|
|
2397
|
+
DWORD dwRealTableSize = 0;
|
|
2398
|
+
|
|
2399
|
+
// Note: It is allowed to load hash table if it is at offset 0.
|
|
2400
|
+
// Example: MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x
|
|
2401
|
+
// if(pHeader->dwHashTablePos == 0 && pHeader->wHashTablePosHi == 0)
|
|
2402
|
+
// return NULL;
|
|
2403
|
+
|
|
2404
|
+
// If the hash table size is zero, do nothing
|
|
2405
|
+
if(pHeader->dwHashTableSize == 0)
|
|
2406
|
+
return NULL;
|
|
2407
|
+
|
|
2408
|
+
// Load the hash table for MPQ variations
|
|
2409
|
+
switch(ha->dwSubType)
|
|
2410
|
+
{
|
|
2411
|
+
case MPQ_SUBTYPE_MPQ:
|
|
2412
|
+
|
|
2413
|
+
// Calculate the position and size of the hash table
|
|
2414
|
+
ByteOffset = FileOffsetFromMpqOffset(ha, MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos));
|
|
2415
|
+
dwTableSize = pHeader->dwHashTableSize * sizeof(TMPQHash);
|
|
2416
|
+
dwCmpSize = (DWORD)pHeader->HashTableSize64;
|
|
2417
|
+
|
|
2418
|
+
// Read, decrypt and uncompress the hash table
|
|
2419
|
+
pHashTable = (TMPQHash *)LoadMpqTable(ha, ByteOffset, pHeader->MD5_HashTable, dwCmpSize, dwTableSize, g_dwHashTableKey, &dwRealTableSize);
|
|
2420
|
+
// DumpHashTable(pHashTable, pHeader->dwHashTableSize);
|
|
2421
|
+
|
|
2422
|
+
// If the hash table was cut, we can/have to defragment it
|
|
2423
|
+
if(pHashTable != NULL && dwRealTableSize != 0 && dwRealTableSize < dwTableSize)
|
|
2424
|
+
{
|
|
2425
|
+
ha->dwRealHashTableSize = dwRealTableSize;
|
|
2426
|
+
ha->dwFlags |= (MPQ_FLAG_MALFORMED | MPQ_FLAG_HASH_TABLE_CUT);
|
|
2427
|
+
}
|
|
2428
|
+
break;
|
|
2429
|
+
|
|
2430
|
+
case MPQ_SUBTYPE_SQP:
|
|
2431
|
+
pHashTable = LoadSqpHashTable(ha);
|
|
2432
|
+
break;
|
|
2433
|
+
|
|
2434
|
+
case MPQ_SUBTYPE_MPK:
|
|
2435
|
+
pHashTable = LoadMpkHashTable(ha);
|
|
2436
|
+
break;
|
|
2437
|
+
}
|
|
2438
|
+
|
|
2439
|
+
// Return the loaded hash table
|
|
2440
|
+
return pHashTable;
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2443
|
+
DWORD CreateFileTable(TMPQArchive * ha, DWORD dwFileTableSize)
|
|
2444
|
+
{
|
|
2445
|
+
ha->pFileTable = STORM_ALLOC(TFileEntry, dwFileTableSize);
|
|
2446
|
+
if(ha->pFileTable == NULL)
|
|
2447
|
+
return ERROR_NOT_ENOUGH_MEMORY;
|
|
2448
|
+
|
|
2449
|
+
memset(ha->pFileTable, 0x00, sizeof(TFileEntry) * dwFileTableSize);
|
|
2450
|
+
ha->dwFileTableSize = dwFileTableSize;
|
|
2451
|
+
return ERROR_SUCCESS;
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
TMPQBlock * LoadBlockTable(TMPQArchive * ha, bool /* bDontFixEntries */)
|
|
2455
|
+
{
|
|
2456
|
+
TMPQHeader * pHeader = ha->pHeader;
|
|
2457
|
+
TMPQBlock * pBlockTable = NULL;
|
|
2458
|
+
ULONGLONG ByteOffset;
|
|
2459
|
+
DWORD dwTableSize;
|
|
2460
|
+
DWORD dwCmpSize;
|
|
2461
|
+
DWORD dwRealTableSize;
|
|
2462
|
+
|
|
2463
|
+
// Note: It is possible that the block table starts at offset 0
|
|
2464
|
+
// Example: MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x
|
|
2465
|
+
// if(pHeader->dwBlockTablePos == 0 && pHeader->wBlockTablePosHi == 0)
|
|
2466
|
+
// return NULL;
|
|
2467
|
+
|
|
2468
|
+
// Do nothing if the block table size is zero
|
|
2469
|
+
if(pHeader->dwBlockTableSize == 0)
|
|
2470
|
+
return NULL;
|
|
2471
|
+
|
|
2472
|
+
// Load the block table for MPQ variations
|
|
2473
|
+
switch(ha->dwSubType)
|
|
2474
|
+
{
|
|
2475
|
+
case MPQ_SUBTYPE_MPQ:
|
|
2476
|
+
|
|
2477
|
+
// Calculate byte position of the block table
|
|
2478
|
+
ByteOffset = FileOffsetFromMpqOffset(ha, MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos));
|
|
2479
|
+
dwTableSize = pHeader->dwBlockTableSize * sizeof(TMPQBlock);
|
|
2480
|
+
dwCmpSize = (DWORD)pHeader->BlockTableSize64;
|
|
2481
|
+
|
|
2482
|
+
// Read, decrypt and uncompress the block table
|
|
2483
|
+
pBlockTable = (TMPQBlock * )LoadMpqTable(ha, ByteOffset, NULL, dwCmpSize, dwTableSize, g_dwBlockTableKey, &dwRealTableSize);
|
|
2484
|
+
|
|
2485
|
+
// If the block table was cut, we need to remember it
|
|
2486
|
+
if(pBlockTable != NULL && dwRealTableSize && dwRealTableSize < dwTableSize)
|
|
2487
|
+
ha->dwFlags |= (MPQ_FLAG_MALFORMED | MPQ_FLAG_BLOCK_TABLE_CUT);
|
|
2488
|
+
break;
|
|
2489
|
+
|
|
2490
|
+
case MPQ_SUBTYPE_SQP:
|
|
2491
|
+
pBlockTable = LoadSqpBlockTable(ha);
|
|
2492
|
+
break;
|
|
2493
|
+
|
|
2494
|
+
case MPQ_SUBTYPE_MPK:
|
|
2495
|
+
pBlockTable = LoadMpkBlockTable(ha);
|
|
2496
|
+
break;
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
return pBlockTable;
|
|
2500
|
+
}
|
|
2501
|
+
|
|
2502
|
+
TMPQHetTable * LoadHetTable(TMPQArchive * ha)
|
|
2503
|
+
{
|
|
2504
|
+
TMPQExtHeader * pExtTable;
|
|
2505
|
+
TMPQHetTable * pHetTable = NULL;
|
|
2506
|
+
TMPQHeader * pHeader = ha->pHeader;
|
|
2507
|
+
|
|
2508
|
+
// If the HET table position is not 0, we expect the table to be present
|
|
2509
|
+
if(pHeader->HetTablePos64 && pHeader->HetTableSize64)
|
|
2510
|
+
{
|
|
2511
|
+
// Attempt to load the HET table (Hash Extended Table)
|
|
2512
|
+
pExtTable = LoadExtTable(ha, pHeader->HetTablePos64, (size_t)pHeader->HetTableSize64, HET_TABLE_SIGNATURE, MPQ_KEY_HASH_TABLE);
|
|
2513
|
+
if(pExtTable != NULL)
|
|
2514
|
+
{
|
|
2515
|
+
// Translate the loaded table into HET table.
|
|
2516
|
+
pHetTable = TranslateHetTable((TMPQHetHeader *)pExtTable);
|
|
2517
|
+
STORM_FREE(pExtTable);
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
return pHetTable;
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
TMPQBetTable * LoadBetTable(TMPQArchive * ha)
|
|
2525
|
+
{
|
|
2526
|
+
TMPQExtHeader * pExtTable;
|
|
2527
|
+
TMPQBetTable * pBetTable = NULL;
|
|
2528
|
+
TMPQHeader * pHeader = ha->pHeader;
|
|
2529
|
+
|
|
2530
|
+
// If the BET table position is not 0, we expect the table to be present
|
|
2531
|
+
if(pHeader->BetTablePos64 && pHeader->BetTableSize64)
|
|
2532
|
+
{
|
|
2533
|
+
// Attempt to load the HET table (Hash Extended Table)
|
|
2534
|
+
pExtTable = LoadExtTable(ha, pHeader->BetTablePos64, (size_t)pHeader->BetTableSize64, BET_TABLE_SIGNATURE, MPQ_KEY_BLOCK_TABLE);
|
|
2535
|
+
if(pExtTable != NULL)
|
|
2536
|
+
{
|
|
2537
|
+
// If succeeded, we translate the BET table
|
|
2538
|
+
// to more readable form
|
|
2539
|
+
pBetTable = TranslateBetTable(ha, (TMPQBetHeader *)pExtTable);
|
|
2540
|
+
STORM_FREE(pExtTable);
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
return pBetTable;
|
|
2545
|
+
}
|
|
2546
|
+
|
|
2547
|
+
DWORD LoadAnyHashTable(TMPQArchive * ha)
|
|
2548
|
+
{
|
|
2549
|
+
TMPQHeader * pHeader = ha->pHeader;
|
|
2550
|
+
|
|
2551
|
+
// If the MPQ archive is empty, don't bother trying to load anything
|
|
2552
|
+
if(pHeader->dwHashTableSize == 0 && pHeader->HetTableSize64 == 0)
|
|
2553
|
+
return CreateHashTable(ha, HASH_TABLE_SIZE_DEFAULT);
|
|
2554
|
+
|
|
2555
|
+
// Try to load HET table
|
|
2556
|
+
if(pHeader->HetTablePos64 != 0)
|
|
2557
|
+
ha->pHetTable = LoadHetTable(ha);
|
|
2558
|
+
|
|
2559
|
+
// Try to load classic hash table
|
|
2560
|
+
// Note that we load the classic hash table even when HET table exists,
|
|
2561
|
+
// because if the MPQ gets modified and saved, hash table must be there
|
|
2562
|
+
if(pHeader->dwHashTableSize)
|
|
2563
|
+
ha->pHashTable = LoadHashTable(ha);
|
|
2564
|
+
|
|
2565
|
+
// At least one of the tables must be present
|
|
2566
|
+
if(ha->pHetTable == NULL && ha->pHashTable == NULL)
|
|
2567
|
+
return ERROR_FILE_CORRUPT;
|
|
2568
|
+
|
|
2569
|
+
// Set the maximum file count to the size of the hash table.
|
|
2570
|
+
// Note: We don't care about HET table limits, because HET table is rebuilt
|
|
2571
|
+
// after each file add/rename/delete.
|
|
2572
|
+
ha->dwMaxFileCount = (ha->pHashTable != NULL) ? pHeader->dwHashTableSize : HASH_TABLE_SIZE_MAX;
|
|
2573
|
+
return ERROR_SUCCESS;
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
static DWORD BuildFileTable_Classic(TMPQArchive * ha)
|
|
2577
|
+
{
|
|
2578
|
+
TMPQHeader * pHeader = ha->pHeader;
|
|
2579
|
+
TMPQBlock * pBlockTable;
|
|
2580
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2581
|
+
|
|
2582
|
+
// Sanity checks
|
|
2583
|
+
assert(ha->pHashTable != NULL);
|
|
2584
|
+
assert(ha->pFileTable != NULL);
|
|
2585
|
+
|
|
2586
|
+
// If the MPQ has no block table, do nothing
|
|
2587
|
+
if(pHeader->dwBlockTableSize == 0)
|
|
2588
|
+
return ERROR_SUCCESS;
|
|
2589
|
+
assert(ha->dwFileTableSize >= pHeader->dwBlockTableSize);
|
|
2590
|
+
|
|
2591
|
+
// Load the block table
|
|
2592
|
+
// WARNING! ha->pFileTable can change in the process!!
|
|
2593
|
+
pBlockTable = (TMPQBlock *)LoadBlockTable(ha);
|
|
2594
|
+
if(pBlockTable != NULL)
|
|
2595
|
+
{
|
|
2596
|
+
dwErrCode = BuildFileTableFromBlockTable(ha, pBlockTable);
|
|
2597
|
+
STORM_FREE(pBlockTable);
|
|
2598
|
+
}
|
|
2599
|
+
else
|
|
2600
|
+
{
|
|
2601
|
+
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
// Load the hi-block table
|
|
2605
|
+
if(dwErrCode == ERROR_SUCCESS && pHeader->HiBlockTablePos64 != 0)
|
|
2606
|
+
{
|
|
2607
|
+
ULONGLONG ByteOffset;
|
|
2608
|
+
USHORT * pHiBlockTable = NULL;
|
|
2609
|
+
DWORD dwTableSize = pHeader->dwBlockTableSize * sizeof(USHORT);
|
|
2610
|
+
|
|
2611
|
+
// Allocate space for the hi-block table
|
|
2612
|
+
// Note: pHeader->dwBlockTableSize can be zero !!!
|
|
2613
|
+
pHiBlockTable = STORM_ALLOC(USHORT, pHeader->dwBlockTableSize + 1);
|
|
2614
|
+
if(pHiBlockTable != NULL)
|
|
2615
|
+
{
|
|
2616
|
+
// Load the hi-block table. It is not encrypted, nor compressed
|
|
2617
|
+
ByteOffset = ha->MpqPos + pHeader->HiBlockTablePos64;
|
|
2618
|
+
if(!FileStream_Read(ha->pStream, &ByteOffset, pHiBlockTable, dwTableSize))
|
|
2619
|
+
dwErrCode = GetLastError();
|
|
2620
|
+
|
|
2621
|
+
// Now merge the hi-block table to the file table
|
|
2622
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2623
|
+
{
|
|
2624
|
+
TFileEntry * pFileEntry = ha->pFileTable;
|
|
2625
|
+
|
|
2626
|
+
// Swap the hi-block table
|
|
2627
|
+
BSWAP_ARRAY16_UNSIGNED(pHiBlockTable, dwTableSize);
|
|
2628
|
+
|
|
2629
|
+
// Add the high file offset to the base file offset.
|
|
2630
|
+
for(DWORD i = 0; i < pHeader->dwBlockTableSize; i++, pFileEntry++)
|
|
2631
|
+
pFileEntry->ByteOffset = MAKE_OFFSET64(pHiBlockTable[i], pFileEntry->ByteOffset);
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2634
|
+
// Free the hi-block table
|
|
2635
|
+
STORM_FREE(pHiBlockTable);
|
|
2636
|
+
}
|
|
2637
|
+
else
|
|
2638
|
+
{
|
|
2639
|
+
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
return dwErrCode;
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
static DWORD BuildFileTable_HetBet(TMPQArchive * ha)
|
|
2647
|
+
{
|
|
2648
|
+
TMPQHetTable * pHetTable = ha->pHetTable;
|
|
2649
|
+
TMPQBetTable * pBetTable;
|
|
2650
|
+
TFileEntry * pFileEntry = ha->pFileTable;
|
|
2651
|
+
TMPQBits * pBitArray;
|
|
2652
|
+
DWORD dwBitPosition = 0;
|
|
2653
|
+
DWORD i;
|
|
2654
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2655
|
+
|
|
2656
|
+
// Load the BET table from the MPQ
|
|
2657
|
+
pBetTable = LoadBetTable(ha);
|
|
2658
|
+
if(pBetTable != NULL)
|
|
2659
|
+
{
|
|
2660
|
+
// Verify the size of NameHash2 in the BET table.
|
|
2661
|
+
// It has to be 8 bits less than the information in HET table
|
|
2662
|
+
if((pBetTable->dwBitCount_NameHash2 + 8) != pHetTable->dwNameHashBitSize)
|
|
2663
|
+
{
|
|
2664
|
+
FreeBetTable(pBetTable);
|
|
2665
|
+
return ERROR_FILE_CORRUPT;
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2668
|
+
// Step one: Fill the name indexes
|
|
2669
|
+
for(i = 0; i < pHetTable->dwTotalCount; i++)
|
|
2670
|
+
{
|
|
2671
|
+
DWORD dwFileIndex = 0;
|
|
2672
|
+
|
|
2673
|
+
// Is the entry in the HET table occupied?
|
|
2674
|
+
if(pHetTable->pNameHashes[i] != HET_ENTRY_FREE)
|
|
2675
|
+
{
|
|
2676
|
+
// Load the index to the BET table
|
|
2677
|
+
dwErrCode = pHetTable->pBetIndexes->GetBits(pHetTable->dwIndexSizeTotal * i,
|
|
2678
|
+
pHetTable->dwIndexSize,
|
|
2679
|
+
&dwFileIndex,
|
|
2680
|
+
4);
|
|
2681
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
2682
|
+
{
|
|
2683
|
+
FreeBetTable(pBetTable);
|
|
2684
|
+
return ERROR_FILE_CORRUPT;
|
|
2685
|
+
}
|
|
2686
|
+
|
|
2687
|
+
// Overflow test
|
|
2688
|
+
if(dwFileIndex < pBetTable->dwEntryCount)
|
|
2689
|
+
{
|
|
2690
|
+
ULONGLONG NameHash1 = pHetTable->pNameHashes[i];
|
|
2691
|
+
ULONGLONG NameHash2 = 0;
|
|
2692
|
+
|
|
2693
|
+
// Load the BET hash
|
|
2694
|
+
dwErrCode = pBetTable->pNameHashes->GetBits(pBetTable->dwBitTotal_NameHash2 * dwFileIndex,
|
|
2695
|
+
pBetTable->dwBitCount_NameHash2,
|
|
2696
|
+
&NameHash2,
|
|
2697
|
+
8);
|
|
2698
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
2699
|
+
{
|
|
2700
|
+
FreeBetTable(pBetTable);
|
|
2701
|
+
return ERROR_FILE_CORRUPT;
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
// Combine both part of the name hash and put it to the file table
|
|
2705
|
+
pFileEntry = ha->pFileTable + dwFileIndex;
|
|
2706
|
+
pFileEntry->FileNameHash = (NameHash1 << pBetTable->dwBitCount_NameHash2) | NameHash2;
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2711
|
+
// Go through the entire BET table and convert it to the file table.
|
|
2712
|
+
pFileEntry = ha->pFileTable;
|
|
2713
|
+
pBitArray = pBetTable->pFileTable;
|
|
2714
|
+
for(i = 0; i < pBetTable->dwEntryCount; i++)
|
|
2715
|
+
{
|
|
2716
|
+
DWORD dwFlagIndex = 0;
|
|
2717
|
+
|
|
2718
|
+
// Read the file position
|
|
2719
|
+
if((dwErrCode = pBitArray->GetBits(dwBitPosition + pBetTable->dwBitIndex_FilePos,
|
|
2720
|
+
pBetTable->dwBitCount_FilePos,
|
|
2721
|
+
&pFileEntry->ByteOffset,
|
|
2722
|
+
8)) != ERROR_SUCCESS)
|
|
2723
|
+
break;
|
|
2724
|
+
|
|
2725
|
+
// Read the file size
|
|
2726
|
+
if((dwErrCode = pBitArray->GetBits(dwBitPosition + pBetTable->dwBitIndex_FileSize,
|
|
2727
|
+
pBetTable->dwBitCount_FileSize,
|
|
2728
|
+
&pFileEntry->dwFileSize,
|
|
2729
|
+
4)) != ERROR_SUCCESS)
|
|
2730
|
+
break;
|
|
2731
|
+
|
|
2732
|
+
// Read the compressed size
|
|
2733
|
+
if((dwErrCode = pBitArray->GetBits(dwBitPosition + pBetTable->dwBitIndex_CmpSize,
|
|
2734
|
+
pBetTable->dwBitCount_CmpSize,
|
|
2735
|
+
&pFileEntry->dwCmpSize,
|
|
2736
|
+
4)) != ERROR_SUCCESS)
|
|
2737
|
+
break;
|
|
2738
|
+
|
|
2739
|
+
// Read the flag index
|
|
2740
|
+
if(pBetTable->dwFlagCount != 0)
|
|
2741
|
+
{
|
|
2742
|
+
if((dwErrCode = pBitArray->GetBits(dwBitPosition + pBetTable->dwBitIndex_FlagIndex,
|
|
2743
|
+
pBetTable->dwBitCount_FlagIndex,
|
|
2744
|
+
&dwFlagIndex,
|
|
2745
|
+
4)) != ERROR_SUCCESS)
|
|
2746
|
+
break;
|
|
2747
|
+
|
|
2748
|
+
pFileEntry->dwFlags = pBetTable->pFileFlags[dwFlagIndex];
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2751
|
+
//
|
|
2752
|
+
// TODO: Locale (?)
|
|
2753
|
+
//
|
|
2754
|
+
|
|
2755
|
+
// Move the current bit position
|
|
2756
|
+
dwBitPosition += pBetTable->dwTableEntrySize;
|
|
2757
|
+
pFileEntry++;
|
|
2758
|
+
}
|
|
2759
|
+
|
|
2760
|
+
// Set the current size of the file table
|
|
2761
|
+
FreeBetTable(pBetTable);
|
|
2762
|
+
}
|
|
2763
|
+
else
|
|
2764
|
+
{
|
|
2765
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
2766
|
+
}
|
|
2767
|
+
return dwErrCode;
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
DWORD BuildFileTable(TMPQArchive * ha)
|
|
2771
|
+
{
|
|
2772
|
+
DWORD dwFileTableSize;
|
|
2773
|
+
bool bFileTableCreated = false;
|
|
2774
|
+
|
|
2775
|
+
// Sanity checks
|
|
2776
|
+
assert(ha->pFileTable == NULL);
|
|
2777
|
+
assert(ha->dwFileTableSize == 0);
|
|
2778
|
+
assert(ha->dwMaxFileCount != 0);
|
|
2779
|
+
|
|
2780
|
+
// Determine the allocation size for the file table
|
|
2781
|
+
dwFileTableSize = STORMLIB_MAX(ha->pHeader->dwBlockTableSize, ha->dwMaxFileCount);
|
|
2782
|
+
|
|
2783
|
+
// Allocate the file table with size determined before
|
|
2784
|
+
ha->pFileTable = STORM_ALLOC(TFileEntry, dwFileTableSize);
|
|
2785
|
+
if(ha->pFileTable == NULL)
|
|
2786
|
+
return ERROR_NOT_ENOUGH_MEMORY;
|
|
2787
|
+
|
|
2788
|
+
// Fill the table with zeros
|
|
2789
|
+
memset(ha->pFileTable, 0, dwFileTableSize * sizeof(TFileEntry));
|
|
2790
|
+
ha->dwFileTableSize = dwFileTableSize;
|
|
2791
|
+
|
|
2792
|
+
// If we have HET table, we load file table from the BET table
|
|
2793
|
+
// Note: If BET table is corrupt or missing, we set the archive as read only
|
|
2794
|
+
if(ha->pHetTable != NULL)
|
|
2795
|
+
{
|
|
2796
|
+
if(BuildFileTable_HetBet(ha) != ERROR_SUCCESS)
|
|
2797
|
+
ha->dwFlags |= MPQ_FLAG_READ_ONLY;
|
|
2798
|
+
else
|
|
2799
|
+
bFileTableCreated = true;
|
|
2800
|
+
}
|
|
2801
|
+
|
|
2802
|
+
// If we have hash table, we load the file table from the block table
|
|
2803
|
+
// Note: If block table is corrupt or missing, we set the archive as read only
|
|
2804
|
+
if(ha->pHashTable != NULL)
|
|
2805
|
+
{
|
|
2806
|
+
if(BuildFileTable_Classic(ha) != ERROR_SUCCESS)
|
|
2807
|
+
ha->dwFlags |= MPQ_FLAG_READ_ONLY;
|
|
2808
|
+
else
|
|
2809
|
+
bFileTableCreated = true;
|
|
2810
|
+
}
|
|
2811
|
+
|
|
2812
|
+
// Return result
|
|
2813
|
+
return bFileTableCreated ? ERROR_SUCCESS : ERROR_FILE_CORRUPT;
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2816
|
+
/*
|
|
2817
|
+
void UpdateBlockTableSize(TMPQArchive * ha)
|
|
2818
|
+
{
|
|
2819
|
+
TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
|
|
2820
|
+
TFileEntry * pFileEntry;
|
|
2821
|
+
DWORD dwBlockTableSize = 0;
|
|
2822
|
+
|
|
2823
|
+
// Calculate the number of files
|
|
2824
|
+
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
|
|
2825
|
+
{
|
|
2826
|
+
// If the source table entry is valid,
|
|
2827
|
+
if(pFileEntry->dwFlags & MPQ_FILE_EXISTS)
|
|
2828
|
+
dwBlockTableSize = (DWORD)(pFileEntry - ha->pFileTable) + 1;
|
|
2829
|
+
}
|
|
2830
|
+
|
|
2831
|
+
// Save the block table size to the MPQ header
|
|
2832
|
+
ha->pHeader->dwBlockTableSize = ha->dwReservedFiles + dwBlockTableSize;
|
|
2833
|
+
}
|
|
2834
|
+
*/
|
|
2835
|
+
|
|
2836
|
+
// Defragment the file table so it does not contain any gaps
|
|
2837
|
+
DWORD DefragmentFileTable(TMPQArchive * ha)
|
|
2838
|
+
{
|
|
2839
|
+
TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
|
|
2840
|
+
TFileEntry * pSource = ha->pFileTable;
|
|
2841
|
+
TFileEntry * pTarget = ha->pFileTable;
|
|
2842
|
+
LPDWORD DefragmentTable;
|
|
2843
|
+
DWORD dwBlockTableSize = 0;
|
|
2844
|
+
DWORD dwSrcIndex;
|
|
2845
|
+
DWORD dwTrgIndex;
|
|
2846
|
+
|
|
2847
|
+
// Allocate brand new file table
|
|
2848
|
+
DefragmentTable = STORM_ALLOC(DWORD, ha->dwFileTableSize);
|
|
2849
|
+
if(DefragmentTable != NULL)
|
|
2850
|
+
{
|
|
2851
|
+
// Clear the file table
|
|
2852
|
+
memset(DefragmentTable, 0xFF, sizeof(DWORD) * ha->dwFileTableSize);
|
|
2853
|
+
|
|
2854
|
+
// Parse the entire file table and defragment it
|
|
2855
|
+
for(; pSource < pFileTableEnd; pSource++)
|
|
2856
|
+
{
|
|
2857
|
+
// If the source table entry is valid,
|
|
2858
|
+
if(pSource->dwFlags & MPQ_FILE_EXISTS)
|
|
2859
|
+
{
|
|
2860
|
+
// Remember the index conversion
|
|
2861
|
+
dwSrcIndex = (DWORD)(pSource - ha->pFileTable);
|
|
2862
|
+
dwTrgIndex = (DWORD)(pTarget - ha->pFileTable);
|
|
2863
|
+
DefragmentTable[dwSrcIndex] = dwTrgIndex;
|
|
2864
|
+
|
|
2865
|
+
// Move the entry, if needed
|
|
2866
|
+
if(pTarget != pSource)
|
|
2867
|
+
pTarget[0] = pSource[0];
|
|
2868
|
+
pTarget++;
|
|
2869
|
+
|
|
2870
|
+
// Update the block table size
|
|
2871
|
+
dwBlockTableSize = (DWORD)(pTarget - ha->pFileTable);
|
|
2872
|
+
}
|
|
2873
|
+
else
|
|
2874
|
+
{
|
|
2875
|
+
// If there is file name left, free it
|
|
2876
|
+
if(pSource->szFileName != NULL)
|
|
2877
|
+
STORM_FREE(pSource->szFileName);
|
|
2878
|
+
pSource->szFileName = NULL;
|
|
2879
|
+
}
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2882
|
+
// Did we defragment something?
|
|
2883
|
+
if(pTarget < pFileTableEnd)
|
|
2884
|
+
{
|
|
2885
|
+
// Clear the remaining file entries
|
|
2886
|
+
memset(pTarget, 0, (pFileTableEnd - pTarget) * sizeof(TFileEntry));
|
|
2887
|
+
|
|
2888
|
+
// Go through the hash table and relocate the block indexes
|
|
2889
|
+
if(ha->pHashTable != NULL)
|
|
2890
|
+
{
|
|
2891
|
+
TMPQHash * pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
|
2892
|
+
TMPQHash * pHash;
|
|
2893
|
+
DWORD dwNewBlockIndex;
|
|
2894
|
+
|
|
2895
|
+
for(pHash = ha->pHashTable; pHash < pHashTableEnd; pHash++)
|
|
2896
|
+
{
|
|
2897
|
+
if(MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
|
|
2898
|
+
{
|
|
2899
|
+
// If that block entry is there, set it to the hash entry
|
|
2900
|
+
// If not, set it as DELETED
|
|
2901
|
+
dwNewBlockIndex = DefragmentTable[MPQ_BLOCK_INDEX(pHash)];
|
|
2902
|
+
pHash->dwBlockIndex = (dwNewBlockIndex != HASH_ENTRY_FREE) ? dwNewBlockIndex : HASH_ENTRY_DELETED;
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2908
|
+
// Save the block table size
|
|
2909
|
+
ha->pHeader->dwBlockTableSize = ha->dwReservedFiles + dwBlockTableSize;
|
|
2910
|
+
|
|
2911
|
+
// Free the defragment table
|
|
2912
|
+
STORM_FREE(DefragmentTable);
|
|
2913
|
+
}
|
|
2914
|
+
|
|
2915
|
+
return ERROR_SUCCESS;
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
// Rebuilds the HET table from scratch based on the file table
|
|
2919
|
+
// Used after a modifying operation (add, rename, delete)
|
|
2920
|
+
DWORD RebuildHetTable(TMPQArchive * ha)
|
|
2921
|
+
{
|
|
2922
|
+
TMPQHetTable * pOldHetTable = ha->pHetTable;
|
|
2923
|
+
TFileEntry * pFileTableEnd;
|
|
2924
|
+
TFileEntry * pFileEntry;
|
|
2925
|
+
DWORD dwBlockTableSize = ha->dwFileTableSize;
|
|
2926
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2927
|
+
|
|
2928
|
+
// If we are in the state of saving MPQ tables, the real size of block table
|
|
2929
|
+
// must already have been calculated. Use that value instead
|
|
2930
|
+
if(ha->dwFlags & MPQ_FLAG_SAVING_TABLES)
|
|
2931
|
+
{
|
|
2932
|
+
assert(ha->pHeader->dwBlockTableSize != 0);
|
|
2933
|
+
dwBlockTableSize = ha->pHeader->dwBlockTableSize;
|
|
2934
|
+
}
|
|
2935
|
+
|
|
2936
|
+
// Create new HET table based on the total number of entries in the file table
|
|
2937
|
+
// Note that if we fail to create it, we just stop using HET table
|
|
2938
|
+
ha->pHetTable = CreateHetTable(dwBlockTableSize, 0, 0x40, NULL);
|
|
2939
|
+
if(ha->pHetTable != NULL)
|
|
2940
|
+
{
|
|
2941
|
+
// Go through the file table again and insert all existing files
|
|
2942
|
+
pFileTableEnd = ha->pFileTable + dwBlockTableSize;
|
|
2943
|
+
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
|
|
2944
|
+
{
|
|
2945
|
+
if(pFileEntry->dwFlags & MPQ_FILE_EXISTS)
|
|
2946
|
+
{
|
|
2947
|
+
// Get the high
|
|
2948
|
+
dwErrCode = InsertHetEntry(ha->pHetTable, pFileEntry->FileNameHash, (DWORD)(pFileEntry - ha->pFileTable));
|
|
2949
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
2950
|
+
break;
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
}
|
|
2954
|
+
|
|
2955
|
+
// Free the old HET table
|
|
2956
|
+
FreeHetTable(pOldHetTable);
|
|
2957
|
+
return dwErrCode;
|
|
2958
|
+
}
|
|
2959
|
+
|
|
2960
|
+
// Rebuilds the file table, removing all deleted file entries.
|
|
2961
|
+
// Used when compacting the archive
|
|
2962
|
+
DWORD RebuildFileTable(TMPQArchive * ha, DWORD dwNewHashTableSize)
|
|
2963
|
+
{
|
|
2964
|
+
TFileEntry * pFileEntry;
|
|
2965
|
+
TMPQHash * pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
|
2966
|
+
TMPQHash * pOldHashTable = ha->pHashTable;
|
|
2967
|
+
TMPQHash * pHashTable = NULL;
|
|
2968
|
+
TMPQHash * pHash;
|
|
2969
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2970
|
+
|
|
2971
|
+
// The new hash table size must be greater or equal to the current hash table size
|
|
2972
|
+
assert(dwNewHashTableSize >= ha->pHeader->dwHashTableSize);
|
|
2973
|
+
assert(dwNewHashTableSize >= ha->dwMaxFileCount);
|
|
2974
|
+
assert((dwNewHashTableSize & (dwNewHashTableSize - 1)) == 0);
|
|
2975
|
+
assert(ha->pHashTable != NULL);
|
|
2976
|
+
|
|
2977
|
+
// Reallocate the new file table, if needed
|
|
2978
|
+
if(dwNewHashTableSize > ha->dwFileTableSize)
|
|
2979
|
+
{
|
|
2980
|
+
ha->pFileTable = STORM_REALLOC(TFileEntry, ha->pFileTable, dwNewHashTableSize);
|
|
2981
|
+
if(ha->pFileTable == NULL)
|
|
2982
|
+
return ERROR_NOT_ENOUGH_MEMORY;
|
|
2983
|
+
|
|
2984
|
+
memset(ha->pFileTable + ha->dwFileTableSize, 0, (dwNewHashTableSize - ha->dwFileTableSize) * sizeof(TFileEntry));
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2987
|
+
// Allocate new hash table
|
|
2988
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2989
|
+
{
|
|
2990
|
+
pHashTable = STORM_ALLOC(TMPQHash, dwNewHashTableSize);
|
|
2991
|
+
if(pHashTable == NULL)
|
|
2992
|
+
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2995
|
+
// If both succeeded, we need to rebuild the file table
|
|
2996
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2997
|
+
{
|
|
2998
|
+
// Make sure that the hash table is properly filled
|
|
2999
|
+
memset(pHashTable, 0xFF, sizeof(TMPQHash) * dwNewHashTableSize);
|
|
3000
|
+
ha->pHashTable = pHashTable;
|
|
3001
|
+
|
|
3002
|
+
// Set the new limits to the MPQ archive
|
|
3003
|
+
ha->pHeader->dwHashTableSize = dwNewHashTableSize;
|
|
3004
|
+
|
|
3005
|
+
// Parse the old hash table and copy all entries to the new table
|
|
3006
|
+
for(pHash = pOldHashTable; pHash < pHashTableEnd; pHash++)
|
|
3007
|
+
{
|
|
3008
|
+
if(IsValidHashEntry(ha, pHash))
|
|
3009
|
+
{
|
|
3010
|
+
pFileEntry = ha->pFileTable + MPQ_BLOCK_INDEX(pHash);
|
|
3011
|
+
AllocateHashEntry(ha, pFileEntry, SFILE_MAKE_LCID(pHash->Locale, pHash->Platform));
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
|
|
3015
|
+
// Increment the max file count for the file
|
|
3016
|
+
ha->dwFileTableSize = dwNewHashTableSize;
|
|
3017
|
+
ha->dwMaxFileCount = dwNewHashTableSize;
|
|
3018
|
+
ha->dwFlags |= MPQ_FLAG_CHANGED;
|
|
3019
|
+
}
|
|
3020
|
+
|
|
3021
|
+
// Now free the remaining entries
|
|
3022
|
+
if(pOldHashTable != NULL)
|
|
3023
|
+
STORM_FREE(pOldHashTable);
|
|
3024
|
+
return dwErrCode;
|
|
3025
|
+
}
|
|
3026
|
+
|
|
3027
|
+
// Saves MPQ header, hash table, block table and hi-block table.
|
|
3028
|
+
DWORD SaveMPQTables(TMPQArchive * ha)
|
|
3029
|
+
{
|
|
3030
|
+
TMPQExtHeader * pHetTable = NULL;
|
|
3031
|
+
TMPQExtHeader * pBetTable = NULL;
|
|
3032
|
+
TMPQHeader * pHeader = ha->pHeader;
|
|
3033
|
+
TMPQBlock * pBlockTable = NULL;
|
|
3034
|
+
TMPQHash * pHashTable = NULL;
|
|
3035
|
+
ULONGLONG HetTableSize64 = 0;
|
|
3036
|
+
ULONGLONG BetTableSize64 = 0;
|
|
3037
|
+
ULONGLONG HashTableSize64 = 0;
|
|
3038
|
+
ULONGLONG BlockTableSize64 = 0;
|
|
3039
|
+
ULONGLONG HiBlockTableSize64 = 0;
|
|
3040
|
+
ULONGLONG TablePos = 0; // A table position, relative to the begin of the MPQ
|
|
3041
|
+
USHORT * pHiBlockTable = NULL;
|
|
3042
|
+
DWORD cbTotalSize;
|
|
3043
|
+
bool bNeedHiBlockTable = false;
|
|
3044
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
3045
|
+
|
|
3046
|
+
// We expect this function to be called only when tables have been changed
|
|
3047
|
+
assert(ha->dwFlags & MPQ_FLAG_CHANGED);
|
|
3048
|
+
|
|
3049
|
+
// Find the space where the MPQ tables will be saved
|
|
3050
|
+
TablePos = FindFreeMpqSpace(ha);
|
|
3051
|
+
|
|
3052
|
+
// If the MPQ has HET table, we prepare a ready-to-save version
|
|
3053
|
+
if(dwErrCode == ERROR_SUCCESS && ha->pHetTable != NULL)
|
|
3054
|
+
{
|
|
3055
|
+
pHetTable = TranslateHetTable(ha->pHetTable, &HetTableSize64);
|
|
3056
|
+
if(pHetTable == NULL)
|
|
3057
|
+
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
3058
|
+
}
|
|
3059
|
+
|
|
3060
|
+
// If the MPQ has HET table, we also must create BET table to be saved
|
|
3061
|
+
if(dwErrCode == ERROR_SUCCESS && ha->pHetTable != NULL)
|
|
3062
|
+
{
|
|
3063
|
+
pBetTable = TranslateBetTable(ha, &BetTableSize64);
|
|
3064
|
+
if(pBetTable == NULL)
|
|
3065
|
+
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
3066
|
+
}
|
|
3067
|
+
|
|
3068
|
+
// Now create hash table
|
|
3069
|
+
if(dwErrCode == ERROR_SUCCESS && ha->pHashTable != NULL)
|
|
3070
|
+
{
|
|
3071
|
+
pHashTable = TranslateHashTable(ha, &HashTableSize64);
|
|
3072
|
+
if(pHashTable == NULL)
|
|
3073
|
+
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
3074
|
+
}
|
|
3075
|
+
|
|
3076
|
+
// Create block table
|
|
3077
|
+
if(dwErrCode == ERROR_SUCCESS && ha->pFileTable != NULL)
|
|
3078
|
+
{
|
|
3079
|
+
pBlockTable = TranslateBlockTable(ha, &BlockTableSize64, &bNeedHiBlockTable);
|
|
3080
|
+
if(pBlockTable == NULL)
|
|
3081
|
+
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
3082
|
+
}
|
|
3083
|
+
|
|
3084
|
+
// Create hi-block table, if needed
|
|
3085
|
+
if(dwErrCode == ERROR_SUCCESS && bNeedHiBlockTable)
|
|
3086
|
+
{
|
|
3087
|
+
pHiBlockTable = TranslateHiBlockTable(ha, &HiBlockTableSize64);
|
|
3088
|
+
if(pHiBlockTable == NULL)
|
|
3089
|
+
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
3090
|
+
}
|
|
3091
|
+
|
|
3092
|
+
// Write the HET table, if any
|
|
3093
|
+
if(dwErrCode == ERROR_SUCCESS && pHetTable != NULL)
|
|
3094
|
+
{
|
|
3095
|
+
pHeader->HetTableSize64 = HetTableSize64;
|
|
3096
|
+
pHeader->HetTablePos64 = TablePos;
|
|
3097
|
+
dwErrCode = SaveExtTable(ha, pHetTable, TablePos, (DWORD)HetTableSize64, pHeader->MD5_HetTable, MPQ_KEY_HASH_TABLE, false, &cbTotalSize);
|
|
3098
|
+
TablePos += cbTotalSize;
|
|
3099
|
+
}
|
|
3100
|
+
|
|
3101
|
+
// Write the BET table, if any
|
|
3102
|
+
if(dwErrCode == ERROR_SUCCESS && pBetTable != NULL)
|
|
3103
|
+
{
|
|
3104
|
+
pHeader->BetTableSize64 = BetTableSize64;
|
|
3105
|
+
pHeader->BetTablePos64 = TablePos;
|
|
3106
|
+
dwErrCode = SaveExtTable(ha, pBetTable, TablePos, (DWORD)BetTableSize64, pHeader->MD5_BetTable, MPQ_KEY_BLOCK_TABLE, false, &cbTotalSize);
|
|
3107
|
+
TablePos += cbTotalSize;
|
|
3108
|
+
}
|
|
3109
|
+
|
|
3110
|
+
// Write the hash table, if we have any
|
|
3111
|
+
if(dwErrCode == ERROR_SUCCESS && pHashTable != NULL)
|
|
3112
|
+
{
|
|
3113
|
+
pHeader->HashTableSize64 = HashTableSize64;
|
|
3114
|
+
pHeader->wHashTablePosHi = (USHORT)(TablePos >> 32);
|
|
3115
|
+
pHeader->dwHashTableSize = (DWORD)(HashTableSize64 / sizeof(TMPQHash));
|
|
3116
|
+
pHeader->dwHashTablePos = (DWORD)TablePos;
|
|
3117
|
+
dwErrCode = SaveMpqTable(ha, pHashTable, TablePos, (size_t)HashTableSize64, pHeader->MD5_HashTable, MPQ_KEY_HASH_TABLE, false);
|
|
3118
|
+
TablePos += HashTableSize64;
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3121
|
+
// Write the block table, if we have any
|
|
3122
|
+
if(dwErrCode == ERROR_SUCCESS && pBlockTable != NULL)
|
|
3123
|
+
{
|
|
3124
|
+
pHeader->BlockTableSize64 = BlockTableSize64;
|
|
3125
|
+
pHeader->wBlockTablePosHi = (USHORT)(TablePos >> 32);
|
|
3126
|
+
pHeader->dwBlockTableSize = (DWORD)(BlockTableSize64 / sizeof(TMPQBlock));
|
|
3127
|
+
pHeader->dwBlockTablePos = (DWORD)TablePos;
|
|
3128
|
+
dwErrCode = SaveMpqTable(ha, pBlockTable, TablePos, (size_t)BlockTableSize64, pHeader->MD5_BlockTable, MPQ_KEY_BLOCK_TABLE, false);
|
|
3129
|
+
TablePos += BlockTableSize64;
|
|
3130
|
+
}
|
|
3131
|
+
|
|
3132
|
+
// Write the hi-block table, if we have any
|
|
3133
|
+
if(dwErrCode == ERROR_SUCCESS && pHiBlockTable != NULL)
|
|
3134
|
+
{
|
|
3135
|
+
ULONGLONG ByteOffset = ha->MpqPos + TablePos;
|
|
3136
|
+
|
|
3137
|
+
pHeader->HiBlockTableSize64 = HiBlockTableSize64;
|
|
3138
|
+
pHeader->HiBlockTablePos64 = TablePos;
|
|
3139
|
+
BSWAP_ARRAY16_UNSIGNED(pHiBlockTable, HiBlockTableSize64);
|
|
3140
|
+
|
|
3141
|
+
if(!FileStream_Write(ha->pStream, &ByteOffset, pHiBlockTable, (DWORD)HiBlockTableSize64))
|
|
3142
|
+
dwErrCode = GetLastError();
|
|
3143
|
+
TablePos += HiBlockTableSize64;
|
|
3144
|
+
}
|
|
3145
|
+
|
|
3146
|
+
// Cut the MPQ
|
|
3147
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3148
|
+
{
|
|
3149
|
+
ULONGLONG FileSize = ha->MpqPos + TablePos;
|
|
3150
|
+
|
|
3151
|
+
if(!FileStream_SetSize(ha->pStream, FileSize))
|
|
3152
|
+
dwErrCode = GetLastError();
|
|
3153
|
+
}
|
|
3154
|
+
|
|
3155
|
+
// Write the MPQ header
|
|
3156
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3157
|
+
{
|
|
3158
|
+
TMPQHeader SaveMpqHeader;
|
|
3159
|
+
|
|
3160
|
+
// Update the size of the archive
|
|
3161
|
+
pHeader->ArchiveSize64 = TablePos;
|
|
3162
|
+
pHeader->dwArchiveSize = (DWORD)TablePos;
|
|
3163
|
+
|
|
3164
|
+
// Update the MD5 of the archive header
|
|
3165
|
+
CalculateDataBlockHash(pHeader, MPQ_HEADER_SIZE_V4 - MD5_DIGEST_SIZE, pHeader->MD5_MpqHeader);
|
|
3166
|
+
|
|
3167
|
+
// Write the MPQ header to the file
|
|
3168
|
+
assert(pHeader->dwHeaderSize <= sizeof(SaveMpqHeader));
|
|
3169
|
+
memcpy(&SaveMpqHeader, pHeader, pHeader->dwHeaderSize);
|
|
3170
|
+
BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_1);
|
|
3171
|
+
BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_2);
|
|
3172
|
+
BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_3);
|
|
3173
|
+
BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_4);
|
|
3174
|
+
if(!FileStream_Write(ha->pStream, &ha->MpqPos, &SaveMpqHeader, pHeader->dwHeaderSize))
|
|
3175
|
+
dwErrCode = GetLastError();
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3178
|
+
// Clear the changed flag
|
|
3179
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3180
|
+
ha->dwFlags &= ~MPQ_FLAG_CHANGED;
|
|
3181
|
+
|
|
3182
|
+
// Cleanup and exit
|
|
3183
|
+
if(pHetTable != NULL)
|
|
3184
|
+
STORM_FREE(pHetTable);
|
|
3185
|
+
if(pBetTable != NULL)
|
|
3186
|
+
STORM_FREE(pBetTable);
|
|
3187
|
+
if(pHashTable != NULL)
|
|
3188
|
+
STORM_FREE(pHashTable);
|
|
3189
|
+
if(pBlockTable != NULL)
|
|
3190
|
+
STORM_FREE(pBlockTable);
|
|
3191
|
+
if(pHiBlockTable != NULL)
|
|
3192
|
+
STORM_FREE(pHiBlockTable);
|
|
3193
|
+
return dwErrCode;
|
|
3194
|
+
}
|