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,4393 @@
|
|
|
1
|
+
/*****************************************************************************/
|
|
2
|
+
/* StormTest.cpp Copyright (c) Ladislav Zezula 2003 */
|
|
3
|
+
/*---------------------------------------------------------------------------*/
|
|
4
|
+
/* Test module for StormLib */
|
|
5
|
+
/*---------------------------------------------------------------------------*/
|
|
6
|
+
/* Date Ver Who Comment */
|
|
7
|
+
/* -------- ---- --- ------- */
|
|
8
|
+
/* 25.03.03 1.00 Lad The first version of StormTest.cpp */
|
|
9
|
+
/*****************************************************************************/
|
|
10
|
+
|
|
11
|
+
#define _CRT_NON_CONFORMING_SWPRINTFS
|
|
12
|
+
#define _CRT_SECURE_NO_DEPRECATE
|
|
13
|
+
#define __INCLUDE_CRYPTOGRAPHY__
|
|
14
|
+
#define __STORMLIB_SELF__ // Don't use StormLib.lib
|
|
15
|
+
#include <stdio.h>
|
|
16
|
+
|
|
17
|
+
#ifdef _MSC_VER
|
|
18
|
+
#include <crtdbg.h>
|
|
19
|
+
#endif
|
|
20
|
+
|
|
21
|
+
#include "../src/StormLib.h"
|
|
22
|
+
#include "../src/StormCommon.h"
|
|
23
|
+
|
|
24
|
+
#include "TLogHelper.cpp" // Helper class for showing test results
|
|
25
|
+
|
|
26
|
+
#ifdef _MSC_VER
|
|
27
|
+
#pragma warning(disable: 4505) // 'XXX' : unreferenced local function has been removed
|
|
28
|
+
#include <crtdbg.h>
|
|
29
|
+
#pragma comment(lib, "winmm.lib")
|
|
30
|
+
#endif
|
|
31
|
+
|
|
32
|
+
#ifndef STORMLIB_WINDOWS
|
|
33
|
+
#include <dirent.h>
|
|
34
|
+
#include <alsa/asoundlib.h> // sudo apt-get install libasound2-dev
|
|
35
|
+
#endif
|
|
36
|
+
|
|
37
|
+
//------------------------------------------------------------------------------
|
|
38
|
+
// Local structures
|
|
39
|
+
|
|
40
|
+
#define ID_XHSC 0x58485343 // 'XHSC'
|
|
41
|
+
|
|
42
|
+
// Artificial error code for situations where we don't know the result
|
|
43
|
+
#define ERROR_UNDETERMINED_RESULT 0xC000FFFF
|
|
44
|
+
|
|
45
|
+
// Artificial flag for not reporting open failure
|
|
46
|
+
#define MPQ_OPEN_DONT_REPORT_FAILURE 0x80000000
|
|
47
|
+
|
|
48
|
+
// Size of SHA256, in bytes
|
|
49
|
+
#define SHA256_DIGEST_SIZE 0x20
|
|
50
|
+
|
|
51
|
+
typedef DWORD (*FS_SEARCH_CALLBACK)(LPCTSTR szFullPath, void * lpContext);
|
|
52
|
+
|
|
53
|
+
typedef enum _EXTRA_TYPE
|
|
54
|
+
{
|
|
55
|
+
NoExtraType = 0,
|
|
56
|
+
ListFile,
|
|
57
|
+
Utf8File,
|
|
58
|
+
TwoFiles,
|
|
59
|
+
PatchList,
|
|
60
|
+
HashValues,
|
|
61
|
+
} EXTRA_TYPE, *PEXTRA_TYPE;
|
|
62
|
+
|
|
63
|
+
typedef struct _FILE_DATA
|
|
64
|
+
{
|
|
65
|
+
DWORD dwBlockIndex;
|
|
66
|
+
DWORD dwFileSize;
|
|
67
|
+
DWORD dwFlags;
|
|
68
|
+
DWORD dwCrc32;
|
|
69
|
+
BYTE FileData[1];
|
|
70
|
+
} FILE_DATA, *PFILE_DATA;
|
|
71
|
+
|
|
72
|
+
typedef struct _TEST_EXTRA_ONEFILE
|
|
73
|
+
{
|
|
74
|
+
EXTRA_TYPE Type; // Must be ListFile
|
|
75
|
+
LPCTSTR szFile; // The name of the (list)file
|
|
76
|
+
} TEST_EXTRA_ONEFILE, *PTEST_EXTRA_ONEFILE;
|
|
77
|
+
|
|
78
|
+
typedef struct _TEST_EXTRA_UTF8
|
|
79
|
+
{
|
|
80
|
+
EXTRA_TYPE Type; // Must be Utf8File
|
|
81
|
+
const BYTE * szMpqFile; // (UTF-8) The name of the MPQ file
|
|
82
|
+
const BYTE * szListFile; // (UTF-8) The name of the listfile
|
|
83
|
+
} TEST_EXTRA_UTF8, *PTEST_EXTRA_UTF8;
|
|
84
|
+
|
|
85
|
+
typedef struct _TEST_EXTRA_TWOFILES
|
|
86
|
+
{
|
|
87
|
+
EXTRA_TYPE Type; // Must be TwoFiles
|
|
88
|
+
LPCSTR szFile1; // The first referenced file name
|
|
89
|
+
LPCSTR szFile2; // The second referenced file name
|
|
90
|
+
} TEST_EXTRA_TWOFILES, *PTEST_EXTRA_TWOFILES;
|
|
91
|
+
|
|
92
|
+
typedef struct _TEST_EXTRA_PATCHES
|
|
93
|
+
{
|
|
94
|
+
EXTRA_TYPE Type; // Must be PatchList
|
|
95
|
+
LPCTSTR szPatchList; // Multi-SZ list of patches
|
|
96
|
+
LPCSTR szFileName; // Example of patched file
|
|
97
|
+
DWORD dwPatchCount; // Number of patches
|
|
98
|
+
} TEST_EXTRA_PATCHES, *PTEST_EXTRA_PATCHES;
|
|
99
|
+
|
|
100
|
+
typedef struct _TEST_EXTRA_HASHVAL
|
|
101
|
+
{
|
|
102
|
+
DWORD dwHash1; // Hash A of the file name
|
|
103
|
+
DWORD dwHash2; // Hash B of the file name
|
|
104
|
+
LPCSTR szFileName; // File name
|
|
105
|
+
} TEST_EXTRA_HASHVAL, *PTEST_EXTRA_HASHVAL;
|
|
106
|
+
|
|
107
|
+
typedef struct _TEST_EXTRA_HASHVALS
|
|
108
|
+
{
|
|
109
|
+
EXTRA_TYPE Type; // Must be PatchList
|
|
110
|
+
TEST_EXTRA_HASHVAL Items[2];
|
|
111
|
+
} TEST_EXTRA_HASHVALS, *PTEST_EXTRA_HASHVALS;
|
|
112
|
+
|
|
113
|
+
typedef struct _TEST_INFO1
|
|
114
|
+
{
|
|
115
|
+
LPCTSTR szName1; // MPQ name
|
|
116
|
+
LPCTSTR szName2; // ListFile name or NULL if none
|
|
117
|
+
LPCSTR szDataHash; // Compound name+data hash
|
|
118
|
+
DWORD dwFlags; // Flags for testing the file. Low 16 bits contains number of files
|
|
119
|
+
const void * pExtra;
|
|
120
|
+
} TEST_INFO1, *PTEST_INFO1;
|
|
121
|
+
|
|
122
|
+
typedef struct _TEST_INFO2
|
|
123
|
+
{
|
|
124
|
+
LPCSTR szName1; // (UTF-8) MPQ name
|
|
125
|
+
LPCSTR szName2; // (UTF-8) Added file name or NULL if none
|
|
126
|
+
LPCSTR szDataHash; // Compound name+data hash
|
|
127
|
+
DWORD dwFlags; // Flags for testing the file. Low 16 bits contains number of files
|
|
128
|
+
const void * pExtra;
|
|
129
|
+
} TEST_INFO2, *PTEST_INFO2;
|
|
130
|
+
|
|
131
|
+
typedef struct _LINE_INFO
|
|
132
|
+
{
|
|
133
|
+
LONG nLinePos;
|
|
134
|
+
DWORD nLineLen;
|
|
135
|
+
const char * szLine;
|
|
136
|
+
} LINE_INFO, *PLINE_INFO;
|
|
137
|
+
|
|
138
|
+
typedef struct _WAVE_FILE_HEADER
|
|
139
|
+
{
|
|
140
|
+
DWORD dwRiffSignature; // 'RIFF'
|
|
141
|
+
DWORD dwFileSize;
|
|
142
|
+
DWORD dwTypeSignature; // 'WAVE'
|
|
143
|
+
DWORD dwChunkMarker; // 'fmt\0'
|
|
144
|
+
DWORD dwLength; // 16
|
|
145
|
+
USHORT wFormat; // 1 = PCM
|
|
146
|
+
USHORT wChannels; // Number of channels
|
|
147
|
+
DWORD dwSamplesPerSec; // Bitrate
|
|
148
|
+
DWORD dwAvgSamplesPerSec;
|
|
149
|
+
USHORT wBlockAlign;
|
|
150
|
+
USHORT wBitsPerSample;
|
|
151
|
+
DWORD dwDataSignature; // 'data'
|
|
152
|
+
DWORD dwDataSize; // 'data'
|
|
153
|
+
} WAVE_FILE_HEADER, *PWAVE_FILE_HEADER;
|
|
154
|
+
|
|
155
|
+
//------------------------------------------------------------------------------
|
|
156
|
+
// Local variables
|
|
157
|
+
|
|
158
|
+
#ifdef STORMLIB_WINDOWS
|
|
159
|
+
#define WORK_PATH_ROOT _T("\\Multimedia\\MPQs")
|
|
160
|
+
#endif
|
|
161
|
+
|
|
162
|
+
#ifdef STORMLIB_LINUX
|
|
163
|
+
#define WORK_PATH_ROOT "/media/ladik/MPQs"
|
|
164
|
+
#endif
|
|
165
|
+
|
|
166
|
+
#ifdef STORMLIB_HAIKU
|
|
167
|
+
#define WORK_PATH_ROOT "~/StormLib/test"
|
|
168
|
+
#endif
|
|
169
|
+
|
|
170
|
+
// Definition of the path separator
|
|
171
|
+
#ifdef STORMLIB_WINDOWS
|
|
172
|
+
static LPCTSTR g_szPathSeparator = _T("\\");
|
|
173
|
+
static const TCHAR PATH_SEPARATOR = _T('\\'); // Path separator for Windows platforms
|
|
174
|
+
#else
|
|
175
|
+
static LPCSTR g_szPathSeparator = "/";
|
|
176
|
+
static const TCHAR PATH_SEPARATOR = '/'; // Path separator for Non-Windows platforms
|
|
177
|
+
#endif
|
|
178
|
+
|
|
179
|
+
// Global for the work MPQ
|
|
180
|
+
static LPCTSTR szMpqSubDir = _T("1995 - Test MPQs");
|
|
181
|
+
static TCHAR szDataFileDir[MAX_PATH] = {0};
|
|
182
|
+
static TCHAR szListFileDir[MAX_PATH] = {0};
|
|
183
|
+
static TCHAR szMpqPatchDir[MAX_PATH] = {0};
|
|
184
|
+
|
|
185
|
+
//-----------------------------------------------------------------------------
|
|
186
|
+
// Testing data
|
|
187
|
+
|
|
188
|
+
// Flags for TestOpenArchive
|
|
189
|
+
#define TFLG_VALUE_MASK 0x000FFFFF // Mask for file count
|
|
190
|
+
#define TFLG_READ_ONLY 0x00100000 // Open the archive read-only
|
|
191
|
+
#define TFLG_SIGCHECK_BEFORE 0x00200000 // Verify signature before modification
|
|
192
|
+
#define TFLG_MODIFY 0x00400000 // Modify the archive
|
|
193
|
+
#define TFLG_SIGN_ARCHIVE 0x00800000 // Sign an archive that is not signed
|
|
194
|
+
#define TFLG_SIGCHECK_AFTER 0x01000000 // Verify signature after modification
|
|
195
|
+
#define TFLG_GET_FILE_INFO 0x02000000 // Test the GetFileInfo function
|
|
196
|
+
#define TFLG_ADD_USER_DATA 0x04000000 // Add user data during MPQ copying
|
|
197
|
+
#define TFLG_HAS_LISTFILE 0x08000000 // The MPQ must have (listfile)
|
|
198
|
+
#define TFLG_HAS_ATTRIBUTES 0x10000000 // The MPQ must have (attributes)
|
|
199
|
+
#define TFLG_BIGFILE 0x20000000 // Add a big file to the MPQ
|
|
200
|
+
#define TFLG_COMPACT 0x40000000 // Perform archive compacting between two opens
|
|
201
|
+
#define TFLG_WILL_FAIL 0x80000000 // The process is expected to fail
|
|
202
|
+
|
|
203
|
+
// Flags for TestCreateArchive
|
|
204
|
+
#define CFLG_V2 0x00010000 // Create archive version 2
|
|
205
|
+
#define CFLG_V4 0x00020000 // Create archive version 4
|
|
206
|
+
#define CFLG_EMPTY 0x00040000 // The archive will be empty
|
|
207
|
+
#define CFLG_NONSTD_NAMES 0x00080000 // Create archive containing non-standard names
|
|
208
|
+
#define CFLG_MPQEDITOR 0x00100000 // Create archive like MPQEditor would do
|
|
209
|
+
|
|
210
|
+
// Flags for TestOpenArchive_SignatureTest
|
|
211
|
+
#define SFLAG_VERIFY_BEFORE 0x00000001 // Verify signature before modification
|
|
212
|
+
#define SFLAG_CREATE_ARCHIVE 0x00000002 // Create new archive
|
|
213
|
+
#define SFLAG_MODIFY_ARCHIVE 0x00000004 // Modify the archive before signing
|
|
214
|
+
#define SFLAG_SIGN_AT_CREATE 0x00000008 // Sign the archive at the creation
|
|
215
|
+
#define SFLAG_SIGN_ARCHIVE 0x00000010 // Sign the archive
|
|
216
|
+
#define SFLAG_VERIFY_AFTER 0x00000020 // Verify the signature after modification
|
|
217
|
+
|
|
218
|
+
static DWORD AddFlags[] =
|
|
219
|
+
{
|
|
220
|
+
// Compression Encryption Fixed key Single Unit Sector CRC
|
|
221
|
+
0 | 0 | 0 | 0 | 0,
|
|
222
|
+
0 | MPQ_FILE_ENCRYPTED | 0 | 0 | 0,
|
|
223
|
+
0 | MPQ_FILE_ENCRYPTED | MPQ_FILE_KEY_V2 | 0 | 0,
|
|
224
|
+
0 | 0 | 0 | MPQ_FILE_SINGLE_UNIT | 0,
|
|
225
|
+
0 | MPQ_FILE_ENCRYPTED | 0 | MPQ_FILE_SINGLE_UNIT | 0,
|
|
226
|
+
0 | MPQ_FILE_ENCRYPTED | MPQ_FILE_KEY_V2 | MPQ_FILE_SINGLE_UNIT | 0,
|
|
227
|
+
MPQ_FILE_IMPLODE | 0 | 0 | 0 | 0,
|
|
228
|
+
MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | 0 | 0 | 0,
|
|
229
|
+
MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | MPQ_FILE_KEY_V2 | 0 | 0,
|
|
230
|
+
MPQ_FILE_IMPLODE | 0 | 0 | MPQ_FILE_SINGLE_UNIT | 0,
|
|
231
|
+
MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | 0 | MPQ_FILE_SINGLE_UNIT | 0,
|
|
232
|
+
MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | MPQ_FILE_KEY_V2 | MPQ_FILE_SINGLE_UNIT | 0,
|
|
233
|
+
MPQ_FILE_IMPLODE | 0 | 0 | 0 | MPQ_FILE_SECTOR_CRC,
|
|
234
|
+
MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | 0 | 0 | MPQ_FILE_SECTOR_CRC,
|
|
235
|
+
MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | MPQ_FILE_KEY_V2 | 0 | MPQ_FILE_SECTOR_CRC,
|
|
236
|
+
MPQ_FILE_COMPRESS | 0 | 0 | 0 | 0,
|
|
237
|
+
MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | 0 | 0 | 0,
|
|
238
|
+
MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_KEY_V2 | 0 | 0,
|
|
239
|
+
MPQ_FILE_COMPRESS | 0 | 0 | MPQ_FILE_SINGLE_UNIT | 0,
|
|
240
|
+
MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | 0 | MPQ_FILE_SINGLE_UNIT | 0,
|
|
241
|
+
MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_KEY_V2 | MPQ_FILE_SINGLE_UNIT | 0,
|
|
242
|
+
MPQ_FILE_COMPRESS | 0 | 0 | 0 | MPQ_FILE_SECTOR_CRC,
|
|
243
|
+
MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | 0 | 0 | MPQ_FILE_SECTOR_CRC,
|
|
244
|
+
MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_KEY_V2 | 0 | MPQ_FILE_SECTOR_CRC,
|
|
245
|
+
0xFFFFFFFF
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
static DWORD WaveCompressions[] =
|
|
249
|
+
{
|
|
250
|
+
MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_HUFFMANN,
|
|
251
|
+
MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN,
|
|
252
|
+
MPQ_COMPRESSION_PKWARE,
|
|
253
|
+
MPQ_COMPRESSION_ZLIB,
|
|
254
|
+
MPQ_COMPRESSION_BZIP2
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
static const BYTE szPlainName_CZE[] = { 0xc4, 0x8c, 0x65, 0x73, 0x6b, 0xc3, 0xbd, 0x2e, 0x6d, 0x70, 0x71, 0x00}; // (UTF-8) Czech
|
|
258
|
+
static const BYTE szPlainName_RUS[] = { 0xd0, 0xa0, 0xd1, 0x83, 0xd1, 0x81, 0xd1, 0x81, 0xd0, 0xba, 0xd0, 0xb8, 0xd0, 0xb9, 0x2e, 0x6d, 0x70, 0x71, 0x00}; // (UTF-8) Russian
|
|
259
|
+
static const BYTE szPlainName_GRC[] = {0xce, 0xb5, 0xce, 0xbb, 0xce, 0xbb, 0xce, 0xb7, 0xce, 0xbd, 0xce, 0xb9, 0xce, 0xba, 0xce, 0xac, 0x2e, 0x6d, 0x70, 0x71, 0x00}; // (UTF-8) Greek
|
|
260
|
+
static const BYTE szPlainName_CHN[] = { 0xe6, 0x97, 0xa5, 0xe6, 0x9c, 0xac, 0xe8, 0xaa, 0x9e, 0x2e, 0x6d, 0x70, 0x71, 0x00}; // (UTF-8) Chinese
|
|
261
|
+
static const BYTE szPlainName_JPN[] = { 0xe7, 0xae, 0x80, 0xe4, 0xbd, 0x93, 0xe4, 0xb8, 0xad, 0xe6, 0x96, 0x87, 0x2e, 0x6d, 0x70, 0x71, 0x00}; // (UTF-8) Japanese
|
|
262
|
+
static const BYTE szPlainName_SAU[] = {0xd8, 0xa7, 0xd9, 0x84, 0xd8, 0xb9, 0xd8, 0xb9, 0xd8, 0xb1, 0xd8, 0xa8, 0xd9, 0x8a, 0xd8, 0xa9, 0x2e, 0x6d, 0x70, 0x71, 0x00}; // (UTF-8) Arabic
|
|
263
|
+
|
|
264
|
+
static SFILE_MARKERS MpqMarkers[] =
|
|
265
|
+
{
|
|
266
|
+
{sizeof(SFILE_MARKERS), ID_MPQ, "(hash table)", "(block table)"},
|
|
267
|
+
{sizeof(SFILE_MARKERS), ID_XHSC, "(cash table)", "(clock table)"}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
//-----------------------------------------------------------------------------
|
|
271
|
+
// Local file functions
|
|
272
|
+
|
|
273
|
+
// This must be the directory where our test MPQs are stored.
|
|
274
|
+
// We also expect a subdirectory named
|
|
275
|
+
static TCHAR szMpqDirectory[MAX_PATH+1];
|
|
276
|
+
size_t cchMpqDirectory = 0;
|
|
277
|
+
|
|
278
|
+
static EXTRA_TYPE GetExtraType(const void * pExtra)
|
|
279
|
+
{
|
|
280
|
+
if(pExtra != NULL)
|
|
281
|
+
{
|
|
282
|
+
return *(PEXTRA_TYPE)(pExtra);
|
|
283
|
+
}
|
|
284
|
+
else
|
|
285
|
+
{
|
|
286
|
+
return NoExtraType;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
LPCTSTR SwapMpqName(LPTSTR szBuffer, size_t ccBuffer, LPCTSTR szMpqName, PTEST_EXTRA_UTF8 pExtra)
|
|
291
|
+
{
|
|
292
|
+
if((pExtra != NULL) && (pExtra->Type == Utf8File))
|
|
293
|
+
{
|
|
294
|
+
StringCopy(szBuffer, ccBuffer, (LPCSTR)(pExtra->szMpqFile));
|
|
295
|
+
return szBuffer;
|
|
296
|
+
}
|
|
297
|
+
else
|
|
298
|
+
{
|
|
299
|
+
return szMpqName;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
template <typename XCHAR>
|
|
304
|
+
static bool IsFullPath(const XCHAR * szFileName)
|
|
305
|
+
{
|
|
306
|
+
#ifdef STORMLIB_WINDOWS
|
|
307
|
+
if(('A' <= szFileName[0] && szFileName[0] <= 'Z') || ('a' <= szFileName[0] && szFileName[0] <= 'z'))
|
|
308
|
+
{
|
|
309
|
+
return (szFileName[1] == ':' && szFileName[2] == PATH_SEPARATOR);
|
|
310
|
+
}
|
|
311
|
+
#endif
|
|
312
|
+
|
|
313
|
+
szFileName = szFileName;
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
LPCTSTR GetRelativePath(LPCTSTR szFullPath)
|
|
318
|
+
{
|
|
319
|
+
LPCTSTR szRelativePath;
|
|
320
|
+
|
|
321
|
+
if(szFullPath && szFullPath[0])
|
|
322
|
+
{
|
|
323
|
+
if((szRelativePath = _tcsstr(szFullPath, szMpqSubDir)) != NULL)
|
|
324
|
+
{
|
|
325
|
+
return szRelativePath;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return _T("");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Converts binary array to string.
|
|
332
|
+
// The caller must ensure that the buffer has at least ((cbBinary * 2) + 1) characters
|
|
333
|
+
template <typename xchar>
|
|
334
|
+
xchar * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, xchar * szBuffer)
|
|
335
|
+
{
|
|
336
|
+
const char * IntToHexChar = "0123456789abcdef";
|
|
337
|
+
xchar * szSaveBuffer = szBuffer;
|
|
338
|
+
|
|
339
|
+
// Verify the binary pointer
|
|
340
|
+
if(pbBinary && cbBinary)
|
|
341
|
+
{
|
|
342
|
+
// Convert the bytes to string array
|
|
343
|
+
for(size_t i = 0; i < cbBinary; i++)
|
|
344
|
+
{
|
|
345
|
+
*szBuffer++ = IntToHexChar[pbBinary[i] >> 0x04];
|
|
346
|
+
*szBuffer++ = IntToHexChar[pbBinary[i] & 0x0F];
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Terminate the string
|
|
351
|
+
*szBuffer = 0;
|
|
352
|
+
return szSaveBuffer;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const char * GetFileText(PFILE_DATA pFileData)
|
|
356
|
+
{
|
|
357
|
+
const char * szFileText = (const char *)(pFileData->FileData);
|
|
358
|
+
|
|
359
|
+
// Skip UTF-8 marker
|
|
360
|
+
if(pFileData->dwFileSize > 3 && !memcmp(szFileText, "\xEF\xBB\xBF", 3))
|
|
361
|
+
szFileText += 3;
|
|
362
|
+
return szFileText;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
static void PlayWaveSound(PFILE_DATA pFileData)
|
|
366
|
+
{
|
|
367
|
+
#ifdef STORMLIB_WINDOWS
|
|
368
|
+
PlaySound((LPCTSTR)pFileData->FileData, NULL, SND_MEMORY);
|
|
369
|
+
#endif
|
|
370
|
+
|
|
371
|
+
#ifdef STORMLIB_LINUX
|
|
372
|
+
PWAVE_FILE_HEADER pHeader = (PWAVE_FILE_HEADER)(pFileData->FileData);
|
|
373
|
+
snd_pcm_hw_params_t *params;
|
|
374
|
+
snd_pcm_t *pcm_handle;
|
|
375
|
+
unsigned int bitrate = pHeader->dwSamplesPerSec;
|
|
376
|
+
|
|
377
|
+
if(snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, 0) >= 0)
|
|
378
|
+
{
|
|
379
|
+
snd_pcm_format_t format = (pHeader->wBitsPerSample == 16) ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_S8;
|
|
380
|
+
unsigned int divider = (pHeader->wBitsPerSample == 16) ? 4 : 2;
|
|
381
|
+
void * wave_buffer = &pFileData->FileData[sizeof(WAVE_FILE_HEADER)];
|
|
382
|
+
|
|
383
|
+
snd_pcm_hw_params_alloca(¶ms);
|
|
384
|
+
snd_pcm_hw_params_any(pcm_handle, params);
|
|
385
|
+
snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
|
386
|
+
snd_pcm_hw_params_set_format(pcm_handle, params, format);
|
|
387
|
+
snd_pcm_hw_params_set_channels(pcm_handle, params, pHeader->wChannels);
|
|
388
|
+
snd_pcm_hw_params_set_rate_near(pcm_handle, params, &bitrate, 0);
|
|
389
|
+
snd_pcm_hw_params(pcm_handle, params);
|
|
390
|
+
|
|
391
|
+
snd_pcm_writei(pcm_handle, wave_buffer, pHeader->dwDataSize / divider);
|
|
392
|
+
snd_pcm_close(pcm_handle);
|
|
393
|
+
}
|
|
394
|
+
#endif
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
static bool CompareBlocks(LPBYTE pbBlock1, LPBYTE pbBlock2, DWORD dwLength, DWORD * pdwDifference)
|
|
398
|
+
{
|
|
399
|
+
for(DWORD i = 0; i < dwLength; i++)
|
|
400
|
+
{
|
|
401
|
+
if(pbBlock1[i] != pbBlock2[i])
|
|
402
|
+
{
|
|
403
|
+
pdwDifference[0] = i;
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return true;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
static DWORD CompareTwoFiles(TLogHelper & Logger, PFILE_DATA pFileData1, PFILE_DATA pFileData2)
|
|
412
|
+
{
|
|
413
|
+
DWORD dwDifference = 0;
|
|
414
|
+
|
|
415
|
+
// Compare the file sizes
|
|
416
|
+
if(pFileData1->dwFileSize != pFileData2->dwFileSize)
|
|
417
|
+
{
|
|
418
|
+
Logger.PrintMessage("File size mismatch: %u vs %u", pFileData1->dwFileSize, pFileData2->dwFileSize);
|
|
419
|
+
return ERROR_FILE_CORRUPT;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Compare the file data
|
|
423
|
+
if(memcmp(pFileData1->FileData, pFileData2->FileData, pFileData1->dwFileSize))
|
|
424
|
+
{
|
|
425
|
+
CompareBlocks(pFileData1->FileData, pFileData2->FileData, pFileData1->dwFileSize, &dwDifference);
|
|
426
|
+
Logger.PrintMessage("File data mismatch at offset %08x", dwDifference);
|
|
427
|
+
return ERROR_FILE_CORRUPT;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return ERROR_SUCCESS;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
template <typename XCHAR>
|
|
434
|
+
static const XCHAR * FindNextPathPart(const XCHAR * szPath, size_t nPartCount)
|
|
435
|
+
{
|
|
436
|
+
const XCHAR * szPathPart = szPath;
|
|
437
|
+
|
|
438
|
+
while(szPath[0] != 0 && nPartCount > 0)
|
|
439
|
+
{
|
|
440
|
+
// Is there path separator?
|
|
441
|
+
if(szPath[0] == '\\' || szPath[0] == '/')
|
|
442
|
+
{
|
|
443
|
+
szPathPart = szPath + 1;
|
|
444
|
+
nPartCount--;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Move to the next letter
|
|
448
|
+
szPath++;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return szPathPart;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
template <typename XCHAR>
|
|
455
|
+
size_t StringLength(const XCHAR * szString)
|
|
456
|
+
{
|
|
457
|
+
size_t nLength;
|
|
458
|
+
|
|
459
|
+
for(nLength = 0; szString[nLength] != 0; nLength++);
|
|
460
|
+
|
|
461
|
+
return nLength;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
template <typename XCHAR>
|
|
465
|
+
static const XCHAR * GetShortPlainName(const XCHAR * szFileName)
|
|
466
|
+
{
|
|
467
|
+
const XCHAR * szPlainName = FindNextPathPart(szFileName, 1000);
|
|
468
|
+
const XCHAR * szPlainEnd = szFileName + StringLength(szFileName);
|
|
469
|
+
|
|
470
|
+
// If the name is still too long, cut it
|
|
471
|
+
if((szPlainEnd - szPlainName) > 50)
|
|
472
|
+
szPlainName = szPlainEnd - 50;
|
|
473
|
+
|
|
474
|
+
return szPlainName;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
static size_t ConvertSha256ToText(const unsigned char * sha_digest, LPTSTR szBuffer)
|
|
478
|
+
{
|
|
479
|
+
LPCSTR szTable = "0123456789abcdef";
|
|
480
|
+
|
|
481
|
+
for(size_t i = 0; i < SHA256_DIGEST_SIZE; i++)
|
|
482
|
+
{
|
|
483
|
+
*szBuffer++ = szTable[(sha_digest[0] >> 0x04)];
|
|
484
|
+
*szBuffer++ = szTable[(sha_digest[0] & 0x0F)];
|
|
485
|
+
sha_digest++;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
*szBuffer = 0;
|
|
489
|
+
return (SHA256_DIGEST_SIZE * 2);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
static void CreateFullPathName(TCHAR * szBuffer, size_t cchBuffer, LPCTSTR szSubDir, LPCTSTR szNamePart1, LPCTSTR szNamePart2 = NULL)
|
|
493
|
+
{
|
|
494
|
+
TCHAR * szSaveBuffer = szBuffer;
|
|
495
|
+
size_t nPrefixLength = 0;
|
|
496
|
+
size_t nLength;
|
|
497
|
+
DWORD dwProvider = 0;
|
|
498
|
+
bool bIsFullPath = false;
|
|
499
|
+
char chSeparator = PATH_SEPARATOR;
|
|
500
|
+
|
|
501
|
+
// Pre-initialize the buffer
|
|
502
|
+
szBuffer[0] = 0;
|
|
503
|
+
|
|
504
|
+
// Determine the path prefix
|
|
505
|
+
if(szNamePart1 != NULL)
|
|
506
|
+
{
|
|
507
|
+
nPrefixLength = FileStream_Prefix(szNamePart1, &dwProvider);
|
|
508
|
+
if((dwProvider & BASE_PROVIDER_MASK) == BASE_PROVIDER_HTTP)
|
|
509
|
+
{
|
|
510
|
+
bIsFullPath = true;
|
|
511
|
+
chSeparator = '/';
|
|
512
|
+
}
|
|
513
|
+
else
|
|
514
|
+
bIsFullPath = IsFullPath(szNamePart1 + nPrefixLength);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Copy the MPQ prefix, if any
|
|
518
|
+
if(nPrefixLength > 0)
|
|
519
|
+
{
|
|
520
|
+
StringCat(szBuffer, cchBuffer, szNamePart1);
|
|
521
|
+
szBuffer[nPrefixLength] = 0;
|
|
522
|
+
szSaveBuffer += nPrefixLength;
|
|
523
|
+
szNamePart1 += nPrefixLength;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// If the given name is not a full path, copy the MPQ directory
|
|
527
|
+
if(bIsFullPath == false)
|
|
528
|
+
{
|
|
529
|
+
// Copy the master MPQ directory
|
|
530
|
+
StringCat(szBuffer, cchBuffer, szMpqDirectory);
|
|
531
|
+
|
|
532
|
+
// Append the subdirectory, if any
|
|
533
|
+
if(szSubDir != NULL && (nLength = _tcslen(szSubDir)) != 0)
|
|
534
|
+
{
|
|
535
|
+
// No leading or trailing separator are allowed
|
|
536
|
+
assert(szSubDir[0] != '/' && szSubDir[0] != '\\');
|
|
537
|
+
assert(szSubDir[nLength - 1] != '/' && szSubDir[nLength - 1] != '\\');
|
|
538
|
+
|
|
539
|
+
// Append the subdirectory
|
|
540
|
+
StringCat(szBuffer, cchBuffer, g_szPathSeparator);
|
|
541
|
+
StringCat(szBuffer, cchBuffer, szSubDir);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Copy the file name, if any
|
|
546
|
+
if(szNamePart1 != NULL && (nLength = _tcslen(szNamePart1)) != 0)
|
|
547
|
+
{
|
|
548
|
+
// Path separators are not allowed in the name part
|
|
549
|
+
assert(szNamePart1[0] != '\\' && szNamePart1[0] != '/');
|
|
550
|
+
assert(szNamePart1[nLength - 1] != '/' && szNamePart1[nLength - 1] != '\\');
|
|
551
|
+
|
|
552
|
+
// Append file path separator and the name part
|
|
553
|
+
if(bIsFullPath == false)
|
|
554
|
+
StringCat(szBuffer, cchBuffer, g_szPathSeparator);
|
|
555
|
+
StringCat(szBuffer, cchBuffer, szNamePart1);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Append the second part of the name
|
|
559
|
+
if(szNamePart2 != NULL && (nLength = _tcslen(szNamePart2)) != 0)
|
|
560
|
+
{
|
|
561
|
+
// Copy the file name
|
|
562
|
+
StringCat(szBuffer, cchBuffer, szNamePart2);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Normalize the path separators
|
|
566
|
+
for(; szSaveBuffer[0] != 0; szSaveBuffer++)
|
|
567
|
+
{
|
|
568
|
+
szSaveBuffer[0] = (szSaveBuffer[0] != '/' && szSaveBuffer[0] != '\\') ? szSaveBuffer[0] : chSeparator;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
#ifdef _UNICODE
|
|
573
|
+
static void CreateFullPathName(char * szBuffer, size_t cchBuffer, LPCTSTR szSubDir, LPCTSTR szNamePart1, LPCTSTR szNamePart2 = NULL)
|
|
574
|
+
{
|
|
575
|
+
TCHAR szFullPathT[MAX_PATH];
|
|
576
|
+
|
|
577
|
+
CreateFullPathName(szFullPathT, _countof(szFullPathT), szSubDir, szNamePart1, szNamePart2);
|
|
578
|
+
StringCopy(szBuffer, cchBuffer, szFullPathT);
|
|
579
|
+
}
|
|
580
|
+
#endif
|
|
581
|
+
|
|
582
|
+
static DWORD CalculateFileHash(TLogHelper * pLogger, LPCTSTR szFullPath, LPTSTR szFileHash)
|
|
583
|
+
{
|
|
584
|
+
TFileStream * pStream;
|
|
585
|
+
unsigned char file_hash[SHA256_DIGEST_SIZE];
|
|
586
|
+
LPCTSTR szShortPlainName = GetShortPlainName(szFullPath);
|
|
587
|
+
hash_state sha256_state;
|
|
588
|
+
ULONGLONG ByteOffset = 0;
|
|
589
|
+
ULONGLONG FileSize = 0;
|
|
590
|
+
LPCSTR szHashingFormat = "Hashing %s " fmt_X_of_Y_a;
|
|
591
|
+
LPBYTE pbFileBlock;
|
|
592
|
+
DWORD cbBytesToRead;
|
|
593
|
+
DWORD cbFileBlock = 0x100000;
|
|
594
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
595
|
+
|
|
596
|
+
// Notify the user
|
|
597
|
+
pLogger->PrintProgress(_T("Hashing %s ..."), szShortPlainName);
|
|
598
|
+
szFileHash[0] = 0;
|
|
599
|
+
|
|
600
|
+
// Open the file to be verified
|
|
601
|
+
pStream = FileStream_OpenFile(szFullPath, STREAM_FLAG_READ_ONLY);
|
|
602
|
+
if(pStream != NULL)
|
|
603
|
+
{
|
|
604
|
+
// Retrieve the size of the file
|
|
605
|
+
FileStream_GetSize(pStream, &FileSize);
|
|
606
|
+
|
|
607
|
+
// Allocate the buffer for loading file parts
|
|
608
|
+
pbFileBlock = STORM_ALLOC(BYTE, cbFileBlock);
|
|
609
|
+
if(pbFileBlock != NULL)
|
|
610
|
+
{
|
|
611
|
+
// Initialize SHA256 calculation
|
|
612
|
+
sha256_init(&sha256_state);
|
|
613
|
+
|
|
614
|
+
// Calculate the SHA256 of the file
|
|
615
|
+
while(ByteOffset < FileSize)
|
|
616
|
+
{
|
|
617
|
+
// Notify the user
|
|
618
|
+
pLogger->PrintProgress(szHashingFormat, szShortPlainName, ByteOffset, FileSize);
|
|
619
|
+
|
|
620
|
+
// Load the file block
|
|
621
|
+
cbBytesToRead = ((FileSize - ByteOffset) > cbFileBlock) ? cbFileBlock : (DWORD)(FileSize - ByteOffset);
|
|
622
|
+
if(!FileStream_Read(pStream, &ByteOffset, pbFileBlock, cbBytesToRead))
|
|
623
|
+
{
|
|
624
|
+
dwErrCode = GetLastError();
|
|
625
|
+
break;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// Add to SHA256
|
|
629
|
+
sha256_process(&sha256_state, pbFileBlock, cbBytesToRead);
|
|
630
|
+
ByteOffset += cbBytesToRead;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Notify the user
|
|
634
|
+
pLogger->PrintProgress(szHashingFormat, szShortPlainName, ByteOffset, FileSize);
|
|
635
|
+
|
|
636
|
+
// Finalize SHA256
|
|
637
|
+
sha256_done(&sha256_state, file_hash);
|
|
638
|
+
|
|
639
|
+
// Convert the SHA256 to ANSI text
|
|
640
|
+
ConvertSha256ToText(file_hash, szFileHash);
|
|
641
|
+
STORM_FREE(pbFileBlock);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
FileStream_Close(pStream);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// If we calculated something, return OK
|
|
648
|
+
if(dwErrCode == ERROR_SUCCESS && szFileHash[0] == 0)
|
|
649
|
+
dwErrCode = ERROR_CAN_NOT_COMPLETE;
|
|
650
|
+
return dwErrCode;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
//-----------------------------------------------------------------------------
|
|
654
|
+
// Directory search
|
|
655
|
+
|
|
656
|
+
static HANDLE InitDirectorySearch(LPCTSTR szDirectory)
|
|
657
|
+
{
|
|
658
|
+
#ifdef STORMLIB_WINDOWS
|
|
659
|
+
|
|
660
|
+
WIN32_FIND_DATA wf;
|
|
661
|
+
HANDLE hFind;
|
|
662
|
+
TCHAR szSearchMask[MAX_PATH];
|
|
663
|
+
|
|
664
|
+
// Construct the directory mask
|
|
665
|
+
_stprintf(szSearchMask, _T("%s\\*"), szDirectory);
|
|
666
|
+
|
|
667
|
+
// Perform the search
|
|
668
|
+
hFind = FindFirstFile(szSearchMask, &wf);
|
|
669
|
+
return (hFind != INVALID_HANDLE_VALUE) ? hFind : NULL;
|
|
670
|
+
|
|
671
|
+
#endif
|
|
672
|
+
|
|
673
|
+
#if defined(STORMLIB_LINUX) || defined(STORMLIB_MAC)
|
|
674
|
+
|
|
675
|
+
// Open the directory
|
|
676
|
+
return (HANDLE)opendir(szDirectory);
|
|
677
|
+
|
|
678
|
+
#endif
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
static bool SearchDirectory(HANDLE hFind, LPTSTR szDirEntry, size_t cchDirEntry, bool & IsDirectory)
|
|
682
|
+
{
|
|
683
|
+
#ifdef STORMLIB_WINDOWS
|
|
684
|
+
|
|
685
|
+
WIN32_FIND_DATA wf;
|
|
686
|
+
|
|
687
|
+
// Search for the hnext entry.
|
|
688
|
+
if(FindNextFile(hFind, &wf))
|
|
689
|
+
{
|
|
690
|
+
IsDirectory = (wf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false;
|
|
691
|
+
StringCopy(szDirEntry, cchDirEntry, wf.cFileName);
|
|
692
|
+
return true;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
return false;
|
|
696
|
+
|
|
697
|
+
#endif
|
|
698
|
+
|
|
699
|
+
#if defined(STORMLIB_LINUX) || defined(STORMLIB_MAC)
|
|
700
|
+
|
|
701
|
+
struct dirent * directory_entry;
|
|
702
|
+
|
|
703
|
+
directory_entry = readdir((DIR *)hFind);
|
|
704
|
+
if(directory_entry != NULL)
|
|
705
|
+
{
|
|
706
|
+
IsDirectory = (directory_entry->d_type == DT_DIR) ? true : false;
|
|
707
|
+
strcpy(szDirEntry, directory_entry->d_name);
|
|
708
|
+
return true;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
return false;
|
|
712
|
+
|
|
713
|
+
#endif
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
static void FreeDirectorySearch(HANDLE hFind)
|
|
717
|
+
{
|
|
718
|
+
#ifdef STORMLIB_WINDOWS
|
|
719
|
+
FindClose(hFind);
|
|
720
|
+
#endif
|
|
721
|
+
|
|
722
|
+
#if defined(STORMLIB_LINUX) || defined(STORMLIB_MAC)
|
|
723
|
+
closedir((DIR *)hFind);
|
|
724
|
+
#endif
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
static PFILE_DATA LoadLocalFile(TLogHelper * pLogger, LPCTSTR szFileName, bool bMustSucceed)
|
|
728
|
+
{
|
|
729
|
+
TFileStream * pStream;
|
|
730
|
+
PFILE_DATA pFileData = NULL;
|
|
731
|
+
ULONGLONG FileSize = 0;
|
|
732
|
+
size_t nAllocateBytes;
|
|
733
|
+
|
|
734
|
+
// Notify the user
|
|
735
|
+
if(pLogger != NULL)
|
|
736
|
+
pLogger->PrintProgress(_T("Loading %s ..."), GetPlainFileName(szFileName));
|
|
737
|
+
|
|
738
|
+
// Attempt to open the file
|
|
739
|
+
if((pStream = FileStream_OpenFile(szFileName, STREAM_FLAG_READ_ONLY)) != NULL)
|
|
740
|
+
{
|
|
741
|
+
// Get the file size
|
|
742
|
+
FileStream_GetSize(pStream, &FileSize);
|
|
743
|
+
|
|
744
|
+
// Check for too big files
|
|
745
|
+
if((FileSize >> 0x20) == 0)
|
|
746
|
+
{
|
|
747
|
+
// Allocate space for the file
|
|
748
|
+
nAllocateBytes = sizeof(FILE_DATA) + (size_t)FileSize;
|
|
749
|
+
pFileData = (PFILE_DATA)STORM_ALLOC(BYTE, nAllocateBytes);
|
|
750
|
+
if(pFileData != NULL)
|
|
751
|
+
{
|
|
752
|
+
// Make sure it;s properly zeroed
|
|
753
|
+
memset(pFileData, 0, nAllocateBytes);
|
|
754
|
+
pFileData->dwFileSize = (DWORD)FileSize;
|
|
755
|
+
|
|
756
|
+
// Load to memory
|
|
757
|
+
if(!FileStream_Read(pStream, NULL, pFileData->FileData, pFileData->dwFileSize))
|
|
758
|
+
{
|
|
759
|
+
STORM_FREE(pFileData);
|
|
760
|
+
pFileData = NULL;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// Close the stream
|
|
766
|
+
FileStream_Close(pStream);
|
|
767
|
+
}
|
|
768
|
+
else
|
|
769
|
+
{
|
|
770
|
+
if(pLogger != NULL && bMustSucceed == true)
|
|
771
|
+
pLogger->PrintError(_T("Open failed: %s"), szFileName);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// Return the loaded file data or NULL
|
|
775
|
+
return pFileData;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
static DWORD FindFilesInternal(FS_SEARCH_CALLBACK PfnFolderCallback, FS_SEARCH_CALLBACK PfnFileCallback, LPTSTR szDirectory, void * lpContext = NULL)
|
|
779
|
+
{
|
|
780
|
+
LPTSTR szPlainName;
|
|
781
|
+
HANDLE hFind;
|
|
782
|
+
size_t nLength;
|
|
783
|
+
TCHAR szDirEntry[MAX_PATH];
|
|
784
|
+
bool IsDirectory = false;
|
|
785
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
786
|
+
|
|
787
|
+
if(szDirectory != NULL)
|
|
788
|
+
{
|
|
789
|
+
// Initiate directory search
|
|
790
|
+
hFind = InitDirectorySearch(szDirectory);
|
|
791
|
+
if(hFind != NULL)
|
|
792
|
+
{
|
|
793
|
+
// Append slash at the end of the directory name
|
|
794
|
+
nLength = _tcslen(szDirectory);
|
|
795
|
+
szDirectory[nLength++] = PATH_SEPARATOR;
|
|
796
|
+
szPlainName = szDirectory + nLength;
|
|
797
|
+
|
|
798
|
+
// Skip the first entry, since it's always "." or ".."
|
|
799
|
+
while(SearchDirectory(hFind, szDirEntry, _countof(szDirEntry), IsDirectory) && dwErrCode == ERROR_SUCCESS)
|
|
800
|
+
{
|
|
801
|
+
// Copy the directory entry name to both names
|
|
802
|
+
_tcscpy(szPlainName, szDirEntry);
|
|
803
|
+
|
|
804
|
+
// Found a directory?
|
|
805
|
+
if(IsDirectory)
|
|
806
|
+
{
|
|
807
|
+
if(szDirEntry[0] != '.')
|
|
808
|
+
{
|
|
809
|
+
if(PfnFolderCallback != NULL)
|
|
810
|
+
PfnFolderCallback(szDirectory, lpContext);
|
|
811
|
+
dwErrCode = FindFilesInternal(PfnFolderCallback, PfnFileCallback, szDirectory, lpContext);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
else
|
|
815
|
+
{
|
|
816
|
+
if(PfnFileCallback != NULL)
|
|
817
|
+
{
|
|
818
|
+
dwErrCode = PfnFileCallback(szDirectory, lpContext);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
FreeDirectorySearch(hFind);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// Free the path buffer, if any
|
|
828
|
+
return dwErrCode;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
static DWORD ForEachFile_VerifyFileHash(LPCTSTR szFullPath, void * lpContext)
|
|
832
|
+
{
|
|
833
|
+
TLogHelper * pLogger = (TLogHelper *)(lpContext);
|
|
834
|
+
PFILE_DATA pFileData;
|
|
835
|
+
LPCTSTR szHashExtension = _T(".sha256");
|
|
836
|
+
LPTSTR szExtension;
|
|
837
|
+
TCHAR szShaFileName[MAX_PATH + 1];
|
|
838
|
+
TCHAR szHashText[0x80];
|
|
839
|
+
char szHashTextA[0x80];
|
|
840
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
841
|
+
|
|
842
|
+
// Try to load the file with the SHA extension
|
|
843
|
+
StringCopy(szShaFileName, _countof(szShaFileName), szFullPath);
|
|
844
|
+
szExtension = _tcsrchr(szShaFileName, '.');
|
|
845
|
+
if(szExtension == NULL)
|
|
846
|
+
return ERROR_SUCCESS;
|
|
847
|
+
|
|
848
|
+
// Skip .sha and .sha256 files
|
|
849
|
+
if(!_tcsicmp(szExtension, _T(".txt")) || !_tcsicmp(szExtension, _T(".sha")) || !_tcsicmp(szExtension, szHashExtension))
|
|
850
|
+
return ERROR_SUCCESS;
|
|
851
|
+
|
|
852
|
+
// Load the local file to memory
|
|
853
|
+
_tcscpy(szExtension, szHashExtension);
|
|
854
|
+
pFileData = LoadLocalFile(pLogger, szShaFileName, false);
|
|
855
|
+
if(pFileData != NULL)
|
|
856
|
+
{
|
|
857
|
+
// Calculate SHA256 of the entire file
|
|
858
|
+
dwErrCode = CalculateFileHash(pLogger, szFullPath, szHashText);
|
|
859
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
860
|
+
{
|
|
861
|
+
// Compare with what we loaded from the file
|
|
862
|
+
if(pFileData->dwFileSize >= (SHA256_DIGEST_SIZE * 2))
|
|
863
|
+
{
|
|
864
|
+
// Compare the SHA256
|
|
865
|
+
StringCopy(szHashTextA, _countof(szHashTextA), szHashText);
|
|
866
|
+
if(_strnicmp(szHashTextA, GetFileText(pFileData), (SHA256_DIGEST_SIZE * 2)))
|
|
867
|
+
{
|
|
868
|
+
SetLastError(dwErrCode = ERROR_FILE_CORRUPT);
|
|
869
|
+
pLogger->PrintError(_T("File hash check failed: %s"), szFullPath);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// Clear the line
|
|
875
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
876
|
+
pLogger->PrintProgress("OK");
|
|
877
|
+
STORM_FREE(pFileData);
|
|
878
|
+
}
|
|
879
|
+
return dwErrCode;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// Verify SHA256 of each MPQ that we have in the collection
|
|
883
|
+
static DWORD VerifyFileHashes(LPCTSTR szSubDirectory)
|
|
884
|
+
{
|
|
885
|
+
TLogHelper Logger("TestVerifyHash");
|
|
886
|
+
TCHAR szWorkBuff[MAX_PATH];
|
|
887
|
+
|
|
888
|
+
// Construct the full directory name
|
|
889
|
+
CreateFullPathName(szWorkBuff, _countof(szWorkBuff), szSubDirectory, NULL);
|
|
890
|
+
|
|
891
|
+
// Find each file and check its hash
|
|
892
|
+
return FindFilesInternal(NULL, ForEachFile_VerifyFileHash, szWorkBuff, &Logger);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
static DWORD FindListFileFolder(LPCTSTR szFullPath, void * /* lpContext */)
|
|
896
|
+
{
|
|
897
|
+
LPCTSTR szPlainName = GetPlainFileName(szFullPath);
|
|
898
|
+
|
|
899
|
+
// Check data file dir
|
|
900
|
+
if(szDataFileDir[0] == 0)
|
|
901
|
+
{
|
|
902
|
+
if(!_tcsnicmp(szPlainName, _T("addfiles-"), 9))
|
|
903
|
+
{
|
|
904
|
+
StringCopy(szDataFileDir, _countof(szDataFileDir), GetRelativePath(szFullPath));
|
|
905
|
+
return ERROR_SUCCESS;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// Check listfile directory
|
|
910
|
+
if(szListFileDir[0] == 0)
|
|
911
|
+
{
|
|
912
|
+
if(!_tcsnicmp(szPlainName, _T("listfiles-"), 10))
|
|
913
|
+
{
|
|
914
|
+
StringCopy(szListFileDir, _countof(szListFileDir), GetRelativePath(szFullPath));
|
|
915
|
+
return ERROR_SUCCESS;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
if(szMpqPatchDir[0] == 0)
|
|
920
|
+
{
|
|
921
|
+
if(!_tcsnicmp(szPlainName, _T("patches-"), 8))
|
|
922
|
+
{
|
|
923
|
+
StringCopy(szMpqPatchDir, _countof(szMpqPatchDir), GetRelativePath(szFullPath));
|
|
924
|
+
return ERROR_SUCCESS;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
// Check patch directory
|
|
929
|
+
return ERROR_SUCCESS;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
static DWORD InitializeMpqDirectory(TCHAR * argv[], int argc)
|
|
933
|
+
{
|
|
934
|
+
TLogHelper Logger("InitWorkFolder");
|
|
935
|
+
TFileStream * pStream;
|
|
936
|
+
TCHAR szFullPath[MAX_PATH] = {0};
|
|
937
|
+
LPCTSTR szWhereFrom = _T("default");
|
|
938
|
+
LPCTSTR szDirName = WORK_PATH_ROOT;
|
|
939
|
+
|
|
940
|
+
// Make sure SHA256 works in test program
|
|
941
|
+
register_hash(&sha256_desc);
|
|
942
|
+
|
|
943
|
+
// Retrieve the first argument
|
|
944
|
+
if(argc > 1 && argv[1] != NULL)
|
|
945
|
+
{
|
|
946
|
+
// Check if it's a directory
|
|
947
|
+
pStream = FileStream_OpenFile(argv[1], STREAM_FLAG_READ_ONLY);
|
|
948
|
+
if(pStream == NULL)
|
|
949
|
+
{
|
|
950
|
+
szWhereFrom = _T("command line");
|
|
951
|
+
szDirName = argv[1];
|
|
952
|
+
}
|
|
953
|
+
else
|
|
954
|
+
{
|
|
955
|
+
FileStream_Close(pStream);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// Copy the name of the MPQ directory.
|
|
960
|
+
StringCopy(szMpqDirectory, _countof(szMpqDirectory), szDirName);
|
|
961
|
+
cchMpqDirectory = _tcslen(szMpqDirectory);
|
|
962
|
+
|
|
963
|
+
// Cut trailing slashes and/or backslashes
|
|
964
|
+
while((cchMpqDirectory > 0) && (szMpqDirectory[cchMpqDirectory - 1] == '/' || szMpqDirectory[cchMpqDirectory - 1] == '\\'))
|
|
965
|
+
cchMpqDirectory--;
|
|
966
|
+
szMpqDirectory[cchMpqDirectory] = 0;
|
|
967
|
+
|
|
968
|
+
// Print the work directory info
|
|
969
|
+
Logger.PrintMessage(_T("Work directory %s (%s)"), szMpqDirectory, szWhereFrom);
|
|
970
|
+
|
|
971
|
+
// Find the listfile directory within the MPQ directory
|
|
972
|
+
CreateFullPathName(szFullPath, _countof(szFullPath), NULL, szMpqSubDir);
|
|
973
|
+
FindFilesInternal(FindListFileFolder, NULL, szFullPath, NULL);
|
|
974
|
+
if(szDataFileDir[0] == 0)
|
|
975
|
+
return Logger.PrintError(_T("Data files folder was not found in the MPQ directory"));
|
|
976
|
+
if(szListFileDir[0] == 0)
|
|
977
|
+
return Logger.PrintError(_T("Listfile folder was not found in the MPQ directory"));
|
|
978
|
+
if(szMpqPatchDir[0] == 0)
|
|
979
|
+
return Logger.PrintError(_T("Patches folder was not found in the MPQ directory"));
|
|
980
|
+
|
|
981
|
+
// Verify if the work MPQ directory is writable
|
|
982
|
+
CreateFullPathName(szFullPath, _countof(szFullPath), szMpqSubDir, _T("new-file.bin"));
|
|
983
|
+
pStream = FileStream_CreateFile(szFullPath, 0);
|
|
984
|
+
if(pStream == NULL)
|
|
985
|
+
return Logger.PrintError(_T("MPQ subdirectory doesn't exist or is not writable"));
|
|
986
|
+
|
|
987
|
+
// Close the stream
|
|
988
|
+
FileStream_Close(pStream);
|
|
989
|
+
_tremove(szFullPath);
|
|
990
|
+
|
|
991
|
+
// Verify if the working directory exists and if there is a subdirectory with the file name
|
|
992
|
+
CreateFullPathName(szFullPath, _countof(szFullPath), szListFileDir, _T("ListFile_Blizzard.txt"));
|
|
993
|
+
pStream = FileStream_OpenFile(szFullPath, STREAM_FLAG_READ_ONLY);
|
|
994
|
+
if(pStream == NULL)
|
|
995
|
+
return Logger.PrintError(_T("The main listfile (%s) was not found. Check your paths"), GetShortPlainName(szFullPath));
|
|
996
|
+
|
|
997
|
+
// Close the stream
|
|
998
|
+
FileStream_Close(pStream);
|
|
999
|
+
return ERROR_SUCCESS;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
static DWORD GetFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName)
|
|
1003
|
+
{
|
|
1004
|
+
TCHAR * szPatchName;
|
|
1005
|
+
HANDLE hFile;
|
|
1006
|
+
TCHAR szPatchChain[0x400];
|
|
1007
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1008
|
+
int nPatchCount = 0;
|
|
1009
|
+
|
|
1010
|
+
// Open the MPQ file
|
|
1011
|
+
if(SFileOpenFileEx(hMpq, szFileName, 0, &hFile))
|
|
1012
|
+
{
|
|
1013
|
+
// Notify the user
|
|
1014
|
+
pLogger->PrintProgress("Verifying patch chain for %s ...", GetShortPlainName(szFileName));
|
|
1015
|
+
|
|
1016
|
+
// Query the patch chain
|
|
1017
|
+
if(!SFileGetFileInfo(hFile, SFileInfoPatchChain, szPatchChain, sizeof(szPatchChain), NULL))
|
|
1018
|
+
dwErrCode = pLogger->PrintError("Failed to retrieve the patch chain on %s", szFileName);
|
|
1019
|
+
|
|
1020
|
+
// Is there anything at all in the patch chain?
|
|
1021
|
+
if(dwErrCode == ERROR_SUCCESS && szPatchChain[0] == 0)
|
|
1022
|
+
{
|
|
1023
|
+
pLogger->PrintError("The patch chain for %s is empty", szFileName);
|
|
1024
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
// Now calculate the number of patches
|
|
1028
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
1029
|
+
{
|
|
1030
|
+
// Get the pointer to the patch
|
|
1031
|
+
szPatchName = szPatchChain;
|
|
1032
|
+
|
|
1033
|
+
// Skip the base name
|
|
1034
|
+
for(;;)
|
|
1035
|
+
{
|
|
1036
|
+
// Skip the current name
|
|
1037
|
+
szPatchName = szPatchName + _tcslen(szPatchName) + 1;
|
|
1038
|
+
if(szPatchName[0] == 0)
|
|
1039
|
+
break;
|
|
1040
|
+
|
|
1041
|
+
// Increment number of patches
|
|
1042
|
+
nPatchCount++;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
SFileCloseFile(hFile);
|
|
1047
|
+
}
|
|
1048
|
+
else
|
|
1049
|
+
{
|
|
1050
|
+
pLogger->PrintError("Open failed: %s", szFileName);
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
return nPatchCount;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
static DWORD VerifyFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, DWORD dwExpectedPatchCount)
|
|
1057
|
+
{
|
|
1058
|
+
DWORD dwPatchCount = 0;
|
|
1059
|
+
|
|
1060
|
+
// Retrieve the patch count
|
|
1061
|
+
pLogger->PrintProgress(_T("Verifying patch count for %s ..."), szFileName);
|
|
1062
|
+
dwPatchCount = GetFilePatchCount(pLogger, hMpq, szFileName);
|
|
1063
|
+
|
|
1064
|
+
// Check if there are any patches at all
|
|
1065
|
+
if(dwExpectedPatchCount != 0 && dwPatchCount == 0)
|
|
1066
|
+
{
|
|
1067
|
+
pLogger->PrintMessage("There are no patches for %s", szFileName);
|
|
1068
|
+
return ERROR_FILE_CORRUPT;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// Check if the number of patches fits
|
|
1072
|
+
if(dwPatchCount != dwExpectedPatchCount)
|
|
1073
|
+
{
|
|
1074
|
+
pLogger->PrintMessage("Unexpected number of patches for %s", szFileName);
|
|
1075
|
+
return ERROR_FILE_CORRUPT;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
return ERROR_SUCCESS;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
static DWORD CreateEmptyFile(TLogHelper * pLogger, LPCTSTR szPlainName, ULONGLONG FileSize, TCHAR * szBuffer)
|
|
1082
|
+
{
|
|
1083
|
+
TFileStream * pStream;
|
|
1084
|
+
TCHAR szFullPath[MAX_PATH];
|
|
1085
|
+
|
|
1086
|
+
// Notify the user
|
|
1087
|
+
pLogger->PrintProgress(_T("Creating empty file %s ..."), szPlainName);
|
|
1088
|
+
|
|
1089
|
+
// Construct the full path and crete the file
|
|
1090
|
+
CreateFullPathName(szFullPath, _countof(szFullPath), NULL, szPlainName);
|
|
1091
|
+
pStream = FileStream_CreateFile(szFullPath, STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE);
|
|
1092
|
+
if(pStream == NULL)
|
|
1093
|
+
return pLogger->PrintError(_T("Failed to create file %s"), szBuffer);
|
|
1094
|
+
|
|
1095
|
+
// Write the required size
|
|
1096
|
+
FileStream_SetSize(pStream, FileSize);
|
|
1097
|
+
FileStream_Close(pStream);
|
|
1098
|
+
|
|
1099
|
+
// Give the caller the full file name
|
|
1100
|
+
if(szBuffer != NULL)
|
|
1101
|
+
_tcscpy(szBuffer, szFullPath);
|
|
1102
|
+
return ERROR_SUCCESS;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
static DWORD VerifyFilePosition(
|
|
1106
|
+
TLogHelper * pLogger,
|
|
1107
|
+
TFileStream * pStream,
|
|
1108
|
+
ULONGLONG ExpectedPosition)
|
|
1109
|
+
{
|
|
1110
|
+
ULONGLONG ByteOffset = 0;
|
|
1111
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1112
|
+
|
|
1113
|
+
// Retrieve the file position
|
|
1114
|
+
if(FileStream_GetPos(pStream, &ByteOffset))
|
|
1115
|
+
{
|
|
1116
|
+
if(ByteOffset != ExpectedPosition)
|
|
1117
|
+
{
|
|
1118
|
+
pLogger->PrintMessage(_T("The file position is different than expected (expected: ") fmt_I64u_t _T(", current: ") fmt_I64u_t, ExpectedPosition, ByteOffset);
|
|
1119
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
else
|
|
1123
|
+
{
|
|
1124
|
+
dwErrCode = pLogger->PrintError(_T("Failed to retrieve the file offset"));
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
return dwErrCode;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
static DWORD VerifyFileMpqHeader(TLogHelper * pLogger, TFileStream * pStream, ULONGLONG * pByteOffset)
|
|
1131
|
+
{
|
|
1132
|
+
TMPQHeader Header;
|
|
1133
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1134
|
+
|
|
1135
|
+
memset(&Header, 0xFE, sizeof(TMPQHeader));
|
|
1136
|
+
if(FileStream_Read(pStream, pByteOffset, &Header, sizeof(TMPQHeader)))
|
|
1137
|
+
{
|
|
1138
|
+
if(Header.dwID != g_dwMpqSignature)
|
|
1139
|
+
{
|
|
1140
|
+
pLogger->PrintMessage(_T("Read error - the data is not a MPQ header"));
|
|
1141
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
else
|
|
1145
|
+
{
|
|
1146
|
+
dwErrCode = pLogger->PrintError(_T("Failed to read the MPQ header"));
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
return dwErrCode;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
static DWORD WriteMpqUserDataHeader(
|
|
1153
|
+
TLogHelper * pLogger,
|
|
1154
|
+
TFileStream * pStream,
|
|
1155
|
+
ULONGLONG ByteOffset,
|
|
1156
|
+
DWORD dwByteCount)
|
|
1157
|
+
{
|
|
1158
|
+
TMPQUserData UserData;
|
|
1159
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1160
|
+
|
|
1161
|
+
// Notify the user
|
|
1162
|
+
pLogger->PrintProgress("Writing user data header...");
|
|
1163
|
+
|
|
1164
|
+
// Fill the user data header
|
|
1165
|
+
UserData.dwID = ID_MPQ_USERDATA;
|
|
1166
|
+
UserData.cbUserDataSize = dwByteCount;
|
|
1167
|
+
UserData.dwHeaderOffs = (dwByteCount + sizeof(TMPQUserData));
|
|
1168
|
+
UserData.cbUserDataHeader = dwByteCount / 2;
|
|
1169
|
+
if(!FileStream_Write(pStream, &ByteOffset, &UserData, sizeof(TMPQUserData)))
|
|
1170
|
+
dwErrCode = GetLastError();
|
|
1171
|
+
return dwErrCode;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
static DWORD WriteFileData(
|
|
1175
|
+
TLogHelper * pLogger,
|
|
1176
|
+
TFileStream * pStream,
|
|
1177
|
+
ULONGLONG ByteOffset,
|
|
1178
|
+
ULONGLONG ByteCount)
|
|
1179
|
+
{
|
|
1180
|
+
ULONGLONG SaveByteCount = ByteCount;
|
|
1181
|
+
ULONGLONG BytesWritten = 0;
|
|
1182
|
+
LPBYTE pbDataBuffer;
|
|
1183
|
+
DWORD cbDataBuffer = 0x10000;
|
|
1184
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1185
|
+
|
|
1186
|
+
// Write some data
|
|
1187
|
+
pbDataBuffer = new BYTE[cbDataBuffer];
|
|
1188
|
+
if(pbDataBuffer != NULL)
|
|
1189
|
+
{
|
|
1190
|
+
memset(pbDataBuffer, 0, cbDataBuffer);
|
|
1191
|
+
strcpy((char *)pbDataBuffer, "This is a test data written to a file.");
|
|
1192
|
+
|
|
1193
|
+
// Perform the write
|
|
1194
|
+
while(ByteCount > 0)
|
|
1195
|
+
{
|
|
1196
|
+
DWORD cbToWrite = (ByteCount > cbDataBuffer) ? cbDataBuffer : (DWORD)ByteCount;
|
|
1197
|
+
|
|
1198
|
+
// Notify the user
|
|
1199
|
+
pLogger->PrintProgress("Writing file data " fmt_X_of_Y_a " ...", BytesWritten, SaveByteCount);
|
|
1200
|
+
|
|
1201
|
+
// Write the data
|
|
1202
|
+
if(!FileStream_Write(pStream, &ByteOffset, pbDataBuffer, cbToWrite))
|
|
1203
|
+
{
|
|
1204
|
+
dwErrCode = GetLastError();
|
|
1205
|
+
break;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
BytesWritten += cbToWrite;
|
|
1209
|
+
ByteOffset += cbToWrite;
|
|
1210
|
+
ByteCount -= cbToWrite;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
delete [] pbDataBuffer;
|
|
1214
|
+
}
|
|
1215
|
+
return dwErrCode;
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
static DWORD CopyFileData(
|
|
1219
|
+
TLogHelper * pLogger,
|
|
1220
|
+
TFileStream * pStream1,
|
|
1221
|
+
TFileStream * pStream2,
|
|
1222
|
+
ULONGLONG ByteOffset,
|
|
1223
|
+
ULONGLONG ByteCount)
|
|
1224
|
+
{
|
|
1225
|
+
ULONGLONG BytesCopied = 0;
|
|
1226
|
+
ULONGLONG EndOffset = ByteOffset + ByteCount;
|
|
1227
|
+
LPBYTE pbCopyBuffer;
|
|
1228
|
+
DWORD BytesToRead;
|
|
1229
|
+
DWORD BlockLength = 0x100000;
|
|
1230
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1231
|
+
|
|
1232
|
+
// Allocate copy buffer
|
|
1233
|
+
pbCopyBuffer = STORM_ALLOC(BYTE, BlockLength);
|
|
1234
|
+
if(pbCopyBuffer != NULL)
|
|
1235
|
+
{
|
|
1236
|
+
while(ByteOffset < EndOffset)
|
|
1237
|
+
{
|
|
1238
|
+
// Read source
|
|
1239
|
+
BytesToRead = ((EndOffset - ByteOffset) > BlockLength) ? BlockLength : (DWORD)(EndOffset - ByteOffset);
|
|
1240
|
+
if(!FileStream_Read(pStream1, &ByteOffset, pbCopyBuffer, BytesToRead))
|
|
1241
|
+
{
|
|
1242
|
+
dwErrCode = GetLastError();
|
|
1243
|
+
break;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// Write to the destination file
|
|
1247
|
+
if(!FileStream_Write(pStream2, NULL, pbCopyBuffer, BytesToRead))
|
|
1248
|
+
{
|
|
1249
|
+
dwErrCode = GetLastError();
|
|
1250
|
+
break;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// Increment the byte counts
|
|
1254
|
+
BytesCopied += BytesToRead;
|
|
1255
|
+
ByteOffset += BytesToRead;
|
|
1256
|
+
|
|
1257
|
+
// Notify the user
|
|
1258
|
+
pLogger->PrintProgress("Copying " fmt_X_of_Y_a " ...", BytesCopied, ByteCount);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
STORM_FREE(pbCopyBuffer);
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
return dwErrCode;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
// Support function for copying file
|
|
1268
|
+
static DWORD CreateFileCopy(
|
|
1269
|
+
TLogHelper * pLogger,
|
|
1270
|
+
LPCTSTR szPlainName,
|
|
1271
|
+
LPCTSTR szFileCopy,
|
|
1272
|
+
TCHAR * szBuffer = NULL,
|
|
1273
|
+
size_t cchBuffer = 0,
|
|
1274
|
+
ULONGLONG PreMpqDataSize = 0,
|
|
1275
|
+
ULONGLONG UserDataSize = 0)
|
|
1276
|
+
{
|
|
1277
|
+
TFileStream * pStream1; // Source file
|
|
1278
|
+
TFileStream * pStream2; // Target file
|
|
1279
|
+
ULONGLONG ByteOffset = 0;
|
|
1280
|
+
ULONGLONG FileSize = 0;
|
|
1281
|
+
TCHAR szFileName1[MAX_PATH];
|
|
1282
|
+
TCHAR szFileName2[MAX_PATH];
|
|
1283
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1284
|
+
|
|
1285
|
+
// Notify the user
|
|
1286
|
+
szPlainName += FileStream_Prefix(szPlainName, NULL);
|
|
1287
|
+
pLogger->PrintProgress(_T("Creating copy of %s ..."), szPlainName);
|
|
1288
|
+
|
|
1289
|
+
// Construct both file names. Check if they are not the same
|
|
1290
|
+
CreateFullPathName(szFileName1, _countof(szFileName1), szMpqSubDir, szPlainName);
|
|
1291
|
+
CreateFullPathName(szFileName2, _countof(szFileName2), NULL, szFileCopy + FileStream_Prefix(szFileCopy, NULL));
|
|
1292
|
+
if(!_tcsicmp(szFileName1, szFileName2))
|
|
1293
|
+
{
|
|
1294
|
+
pLogger->PrintError("Failed to create copy of MPQ (the copy name is the same like the original name)");
|
|
1295
|
+
return ERROR_CAN_NOT_COMPLETE;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// Open the source file
|
|
1299
|
+
pStream1 = FileStream_OpenFile(szFileName1, STREAM_FLAG_READ_ONLY);
|
|
1300
|
+
if(pStream1 == NULL)
|
|
1301
|
+
{
|
|
1302
|
+
pLogger->PrintError(_T("Failed to open the source file %s"), szFileName1);
|
|
1303
|
+
return ERROR_CAN_NOT_COMPLETE;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
// Create the destination file
|
|
1307
|
+
pStream2 = FileStream_CreateFile(szFileName2, 0);
|
|
1308
|
+
if(pStream2 != NULL)
|
|
1309
|
+
{
|
|
1310
|
+
// If we should write some pre-MPQ data to the target file, do it
|
|
1311
|
+
if(PreMpqDataSize != 0)
|
|
1312
|
+
{
|
|
1313
|
+
dwErrCode = WriteFileData(pLogger, pStream2, ByteOffset, PreMpqDataSize);
|
|
1314
|
+
ByteOffset += PreMpqDataSize;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
// If we should write some MPQ user data, write the header first
|
|
1318
|
+
if(UserDataSize != 0)
|
|
1319
|
+
{
|
|
1320
|
+
dwErrCode = WriteMpqUserDataHeader(pLogger, pStream2, ByteOffset, (DWORD)UserDataSize);
|
|
1321
|
+
ByteOffset += sizeof(TMPQUserData);
|
|
1322
|
+
|
|
1323
|
+
dwErrCode = WriteFileData(pLogger, pStream2, ByteOffset, UserDataSize);
|
|
1324
|
+
ByteOffset += UserDataSize;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
// Copy the file data from the source file to the destination file
|
|
1328
|
+
FileStream_GetSize(pStream1, &FileSize);
|
|
1329
|
+
if(FileSize != 0)
|
|
1330
|
+
{
|
|
1331
|
+
dwErrCode = CopyFileData(pLogger, pStream1, pStream2, 0, FileSize);
|
|
1332
|
+
ByteOffset += FileSize;
|
|
1333
|
+
}
|
|
1334
|
+
FileStream_Close(pStream2);
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
// Close the source file
|
|
1338
|
+
FileStream_Close(pStream1);
|
|
1339
|
+
|
|
1340
|
+
// Create the full file name of the target file, including prefix
|
|
1341
|
+
if(szBuffer && cchBuffer)
|
|
1342
|
+
CreateFullPathName(szBuffer, cchBuffer, NULL, szFileCopy);
|
|
1343
|
+
|
|
1344
|
+
// Report error, if any
|
|
1345
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
1346
|
+
pLogger->PrintError("Failed to create copy of MPQ");
|
|
1347
|
+
return dwErrCode;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
static DWORD CreateMasterAndMirrorPaths(
|
|
1351
|
+
TLogHelper * pLogger,
|
|
1352
|
+
TCHAR * szMirrorPath,
|
|
1353
|
+
TCHAR * szMasterPath,
|
|
1354
|
+
LPCTSTR szMirrorName,
|
|
1355
|
+
LPCTSTR szMasterName,
|
|
1356
|
+
bool bCopyMirrorFile)
|
|
1357
|
+
{
|
|
1358
|
+
TCHAR szCopyPath[MAX_PATH];
|
|
1359
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1360
|
+
|
|
1361
|
+
// Always delete the mirror file
|
|
1362
|
+
CreateFullPathName(szMasterPath, MAX_PATH, szMpqSubDir, szMasterName);
|
|
1363
|
+
CreateFullPathName(szCopyPath, _countof(szCopyPath), NULL, szMirrorName);
|
|
1364
|
+
_tremove(szCopyPath + FileStream_Prefix(szCopyPath, NULL));
|
|
1365
|
+
|
|
1366
|
+
// Copy the mirrored file from the source to the work directory
|
|
1367
|
+
if(bCopyMirrorFile)
|
|
1368
|
+
dwErrCode = CreateFileCopy(pLogger, szMirrorName, szMirrorName);
|
|
1369
|
+
|
|
1370
|
+
// Create the mirror*master path
|
|
1371
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
1372
|
+
_stprintf(szMirrorPath, _T("%s*%s"), szCopyPath, szMasterPath);
|
|
1373
|
+
|
|
1374
|
+
return dwErrCode;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
static void WINAPI AddFileCallback(void * pvUserData, DWORD dwBytesWritten, DWORD dwTotalBytes, bool bFinalCall)
|
|
1378
|
+
{
|
|
1379
|
+
TLogHelper * pLogger = (TLogHelper *)pvUserData;
|
|
1380
|
+
|
|
1381
|
+
// Keep compilers happy
|
|
1382
|
+
STORMLIB_UNUSED(bFinalCall);
|
|
1383
|
+
|
|
1384
|
+
pLogger->PrintProgress("Adding file (%s) (%u of %u) (%u of %u) ...", pLogger->UserString,
|
|
1385
|
+
pLogger->UserCount,
|
|
1386
|
+
pLogger->UserTotal,
|
|
1387
|
+
dwBytesWritten,
|
|
1388
|
+
dwTotalBytes);
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
//-----------------------------------------------------------------------------
|
|
1392
|
+
// MPQ file utilities
|
|
1393
|
+
|
|
1394
|
+
#define SEARCH_FLAG_LOAD_FILES 0x00000001 // Test function should load all files in the MPQ
|
|
1395
|
+
#define SEARCH_FLAG_HASH_FILES 0x00000002 // Test function should load all files in the MPQ
|
|
1396
|
+
#define SEARCH_FLAG_PLAY_WAVES 0x00000004 // Play extracted WAVE files
|
|
1397
|
+
#define SEARCH_FLAG_IGNORE_ERRORS 0x00000008 // Ignore files that failed to open
|
|
1398
|
+
|
|
1399
|
+
static bool CheckIfFileIsPresent(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, DWORD bShouldExist)
|
|
1400
|
+
{
|
|
1401
|
+
HANDLE hFile = NULL;
|
|
1402
|
+
|
|
1403
|
+
if(SFileOpenFileEx(hMpq, szFileName, 0, &hFile))
|
|
1404
|
+
{
|
|
1405
|
+
if(!bShouldExist)
|
|
1406
|
+
pLogger->PrintMessage("The file \"%s\" is present, but it should not be", szFileName);
|
|
1407
|
+
SFileCloseFile(hFile);
|
|
1408
|
+
return true;
|
|
1409
|
+
}
|
|
1410
|
+
else
|
|
1411
|
+
{
|
|
1412
|
+
if(bShouldExist)
|
|
1413
|
+
pLogger->PrintMessage("The file \"%s\" is not present, but it should be", szFileName);
|
|
1414
|
+
return false;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
static DWORD LoadLocalFileMD5(TLogHelper * pLogger, LPCTSTR szFileFullName, LPBYTE md5_file_local)
|
|
1419
|
+
{
|
|
1420
|
+
PFILE_DATA pFileData;
|
|
1421
|
+
|
|
1422
|
+
// Load the local file to memory
|
|
1423
|
+
if((pFileData = LoadLocalFile(pLogger, szFileFullName, true)) == NULL)
|
|
1424
|
+
{
|
|
1425
|
+
return pLogger->PrintError(_T("The file \"%s\" could not be loaded"), szFileFullName);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
// Calculate the hash
|
|
1429
|
+
CalculateDataBlockHash(pFileData->FileData, pFileData->dwFileSize, md5_file_local);
|
|
1430
|
+
STORM_FREE(pFileData);
|
|
1431
|
+
return ERROR_SUCCESS;
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
static DWORD LoadMpqFile(TLogHelper & Logger, HANDLE hMpq, LPCSTR szFileName, LCID lcFileLocale, DWORD dwSearchFlags, PFILE_DATA * ppFileData)
|
|
1435
|
+
{
|
|
1436
|
+
PFILE_DATA pFileData = NULL;
|
|
1437
|
+
HANDLE hFile;
|
|
1438
|
+
DWORD dwFileSizeHi = 0xCCCCCCCC;
|
|
1439
|
+
DWORD dwFileSizeLo = 0;
|
|
1440
|
+
DWORD dwBytesRead;
|
|
1441
|
+
DWORD dwCrc32 = 0;
|
|
1442
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1443
|
+
|
|
1444
|
+
// Do nothing if the file name is invalid
|
|
1445
|
+
Logger.PrintProgress("Loading file %s ...", GetShortPlainName(szFileName));
|
|
1446
|
+
|
|
1447
|
+
#if defined(_MSC_VER) && defined(_DEBUG)
|
|
1448
|
+
//if(!_stricmp(szFileName, "(signature)"))
|
|
1449
|
+
// __debugbreak();
|
|
1450
|
+
#endif
|
|
1451
|
+
|
|
1452
|
+
// Make sure that we open the proper locale file
|
|
1453
|
+
SFileSetLocale(lcFileLocale);
|
|
1454
|
+
|
|
1455
|
+
// Open the file from MPQ
|
|
1456
|
+
if(SFileOpenFileEx(hMpq, szFileName, 0, &hFile))
|
|
1457
|
+
{
|
|
1458
|
+
// Get the CRC32 of the file
|
|
1459
|
+
SFileGetFileInfo(hFile, SFileInfoCRC32, &dwCrc32, sizeof(dwCrc32), NULL);
|
|
1460
|
+
|
|
1461
|
+
// Get the size of the file
|
|
1462
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
1463
|
+
{
|
|
1464
|
+
dwFileSizeLo = SFileGetFileSize(hFile, &dwFileSizeHi);
|
|
1465
|
+
if(dwFileSizeLo == SFILE_INVALID_SIZE || dwFileSizeHi != 0)
|
|
1466
|
+
dwErrCode = Logger.PrintError("Failed to query the file size");
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
// Spazzler protector: Creates fake files with size of 0x7FFFE7CA
|
|
1470
|
+
if(dwErrCode == ERROR_SUCCESS && dwFileSizeLo > 0x1FFFFFFF)
|
|
1471
|
+
{
|
|
1472
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
// Allocate buffer for the file content
|
|
1476
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
1477
|
+
{
|
|
1478
|
+
pFileData = (PFILE_DATA)STORM_ALLOC(BYTE, sizeof(FILE_DATA) + dwFileSizeLo);
|
|
1479
|
+
if(pFileData == NULL)
|
|
1480
|
+
{
|
|
1481
|
+
Logger.PrintError("Failed to allocate buffer for the file content");
|
|
1482
|
+
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
// Get the file index of the MPQ file
|
|
1487
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
1488
|
+
{
|
|
1489
|
+
// Store the file size
|
|
1490
|
+
memset(pFileData, 0, sizeof(FILE_DATA) + dwFileSizeLo);
|
|
1491
|
+
pFileData->dwFileSize = dwFileSizeLo;
|
|
1492
|
+
pFileData->dwCrc32 = dwCrc32;
|
|
1493
|
+
|
|
1494
|
+
// Retrieve the block index and file flags
|
|
1495
|
+
if(!SFileGetFileInfo(hFile, SFileInfoFileIndex, &pFileData->dwBlockIndex, sizeof(DWORD), NULL))
|
|
1496
|
+
dwErrCode = Logger.PrintError("Failed retrieve the file index of %s", szFileName);
|
|
1497
|
+
if(!SFileGetFileInfo(hFile, SFileInfoFlags, &pFileData->dwFlags, sizeof(DWORD), NULL))
|
|
1498
|
+
dwErrCode = Logger.PrintError("Failed retrieve the file flags of %s", szFileName);
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
// Load the entire file
|
|
1502
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
1503
|
+
{
|
|
1504
|
+
// Read the file data
|
|
1505
|
+
SFileReadFile(hFile, pFileData->FileData, dwFileSizeLo, &dwBytesRead, NULL);
|
|
1506
|
+
if(dwBytesRead != dwFileSizeLo)
|
|
1507
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
// If succeeded, check the CRC
|
|
1511
|
+
if(dwErrCode == ERROR_SUCCESS && dwCrc32 != 0 && (dwSearchFlags & SEARCH_FLAG_IGNORE_ERRORS) == 0)
|
|
1512
|
+
{
|
|
1513
|
+
dwCrc32 = crc32(0, (Bytef *)pFileData->FileData, (uInt)pFileData->dwFileSize);
|
|
1514
|
+
if(dwCrc32 != pFileData->dwCrc32)
|
|
1515
|
+
Logger.PrintMessage("Warning: CRC32 error on %s", szFileName);
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
SFileCloseFile(hFile);
|
|
1519
|
+
}
|
|
1520
|
+
else
|
|
1521
|
+
{
|
|
1522
|
+
if((dwSearchFlags & SEARCH_FLAG_IGNORE_ERRORS) == 0)
|
|
1523
|
+
{
|
|
1524
|
+
dwErrCode = Logger.PrintError("Open failed: %s", szFileName);
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
// If something failed, free the file data
|
|
1529
|
+
if((dwErrCode != ERROR_SUCCESS) && (pFileData != NULL))
|
|
1530
|
+
{
|
|
1531
|
+
STORM_FREE(pFileData);
|
|
1532
|
+
pFileData = NULL;
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
// Return what we got
|
|
1536
|
+
if(ppFileData != NULL)
|
|
1537
|
+
ppFileData[0] = pFileData;
|
|
1538
|
+
return dwErrCode;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
static DWORD LoadMpqFileMD5(TLogHelper & Logger, HANDLE hMpq, LPCSTR szArchivedName, LPBYTE md5_file_in_mpq1)
|
|
1542
|
+
{
|
|
1543
|
+
PFILE_DATA pFileData = NULL;
|
|
1544
|
+
DWORD dwErrCode;
|
|
1545
|
+
|
|
1546
|
+
// Load the MPQ to memory
|
|
1547
|
+
dwErrCode = LoadMpqFile(Logger, hMpq, szArchivedName, 0, 0, &pFileData);
|
|
1548
|
+
if(dwErrCode == ERROR_SUCCESS && pFileData != NULL)
|
|
1549
|
+
{
|
|
1550
|
+
CalculateDataBlockHash(pFileData->FileData, pFileData->dwFileSize, md5_file_in_mpq1);
|
|
1551
|
+
STORM_FREE(pFileData);
|
|
1552
|
+
return ERROR_SUCCESS;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
Logger.PrintError("The file \"%s\" is not in the archive", szArchivedName);
|
|
1556
|
+
return dwErrCode;
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
static DWORD CompareTwoLocalFilesRR(
|
|
1560
|
+
TLogHelper * pLogger,
|
|
1561
|
+
TFileStream * pStream1, // Master file
|
|
1562
|
+
TFileStream * pStream2, // Mirror file
|
|
1563
|
+
int nIterations) // Number of iterations
|
|
1564
|
+
{
|
|
1565
|
+
ULONGLONG RandomNumber = 0x12345678; // We need pseudo-random number that will repeat each run of the program
|
|
1566
|
+
ULONGLONG RandomSeed;
|
|
1567
|
+
ULONGLONG ByteOffset;
|
|
1568
|
+
ULONGLONG FileSize1 = 1;
|
|
1569
|
+
ULONGLONG FileSize2 = 2;
|
|
1570
|
+
DWORD BytesToRead;
|
|
1571
|
+
DWORD Difference;
|
|
1572
|
+
LPBYTE pbBuffer1;
|
|
1573
|
+
LPBYTE pbBuffer2;
|
|
1574
|
+
DWORD cbBuffer = 0x100000;
|
|
1575
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1576
|
+
|
|
1577
|
+
// Compare file sizes
|
|
1578
|
+
FileStream_GetSize(pStream1, &FileSize1);
|
|
1579
|
+
FileStream_GetSize(pStream2, &FileSize2);
|
|
1580
|
+
if(FileSize1 != FileSize2)
|
|
1581
|
+
{
|
|
1582
|
+
pLogger->PrintMessage("The files have different size");
|
|
1583
|
+
return ERROR_CAN_NOT_COMPLETE;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
// Allocate both buffers
|
|
1587
|
+
pbBuffer1 = STORM_ALLOC(BYTE, cbBuffer);
|
|
1588
|
+
pbBuffer2 = STORM_ALLOC(BYTE, cbBuffer);
|
|
1589
|
+
if(pbBuffer1 && pbBuffer2)
|
|
1590
|
+
{
|
|
1591
|
+
// Perform many random reads
|
|
1592
|
+
for(int i = 0; i < nIterations; i++)
|
|
1593
|
+
{
|
|
1594
|
+
// Generate psudo-random offsrt and data size
|
|
1595
|
+
ByteOffset = (RandomNumber % FileSize1);
|
|
1596
|
+
BytesToRead = (DWORD)(RandomNumber % cbBuffer);
|
|
1597
|
+
|
|
1598
|
+
// Show the progress message
|
|
1599
|
+
pLogger->PrintProgress("Comparing file: Offset: " fmt_I64u_a ", Length: %u", ByteOffset, BytesToRead);
|
|
1600
|
+
|
|
1601
|
+
// Only perform read if the byte offset is below
|
|
1602
|
+
if(ByteOffset < FileSize1)
|
|
1603
|
+
{
|
|
1604
|
+
if((ByteOffset + BytesToRead) > FileSize1)
|
|
1605
|
+
BytesToRead = (DWORD)(FileSize1 - ByteOffset);
|
|
1606
|
+
|
|
1607
|
+
memset(pbBuffer1, 0xEE, cbBuffer);
|
|
1608
|
+
memset(pbBuffer2, 0xAA, cbBuffer);
|
|
1609
|
+
|
|
1610
|
+
FileStream_Read(pStream1, &ByteOffset, pbBuffer1, BytesToRead);
|
|
1611
|
+
FileStream_Read(pStream2, &ByteOffset, pbBuffer2, BytesToRead);
|
|
1612
|
+
|
|
1613
|
+
if(!CompareBlocks(pbBuffer1, pbBuffer2, BytesToRead, &Difference))
|
|
1614
|
+
{
|
|
1615
|
+
pLogger->PrintMessage("Difference at %u (Offset " fmt_I64X_a ", Length %X)", Difference, ByteOffset, BytesToRead);
|
|
1616
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
1617
|
+
break;
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
// Shuffle the random number
|
|
1621
|
+
memcpy(&RandomSeed, pbBuffer1, sizeof(RandomSeed));
|
|
1622
|
+
RandomNumber = ((RandomNumber >> 0x11) | (RandomNumber << 0x29)) ^ (RandomNumber + RandomSeed);
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
// Free both buffers
|
|
1628
|
+
if(pbBuffer2 != NULL)
|
|
1629
|
+
STORM_FREE(pbBuffer2);
|
|
1630
|
+
if(pbBuffer1 != NULL)
|
|
1631
|
+
STORM_FREE(pbBuffer1);
|
|
1632
|
+
return dwErrCode;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
static DWORD SearchArchive(
|
|
1636
|
+
TLogHelper * pLogger,
|
|
1637
|
+
HANDLE hMpq,
|
|
1638
|
+
DWORD dwSearchFlags = 0,
|
|
1639
|
+
DWORD * pdwFileCount = NULL,
|
|
1640
|
+
LPBYTE pbFileHash = NULL)
|
|
1641
|
+
{
|
|
1642
|
+
SFILE_FIND_DATA sf;
|
|
1643
|
+
PFILE_DATA pFileData;
|
|
1644
|
+
HANDLE hFind;
|
|
1645
|
+
FILE * fp = NULL;
|
|
1646
|
+
DWORD dwFileCount = 0;
|
|
1647
|
+
hash_state md5state;
|
|
1648
|
+
TCHAR szListFile[MAX_PATH] = _T("");
|
|
1649
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1650
|
+
bool bFound = true;
|
|
1651
|
+
|
|
1652
|
+
// Construct the full name of the listfile
|
|
1653
|
+
CreateFullPathName(szListFile, _countof(szListFile), szListFileDir, _T("ListFile_Blizzard.txt"));
|
|
1654
|
+
|
|
1655
|
+
// Create the log file with file sizes and CRCs
|
|
1656
|
+
//fp = fopen("C:\\mpq-listing.txt", "wt");
|
|
1657
|
+
|
|
1658
|
+
// Prepare hashing
|
|
1659
|
+
md5_init(&md5state);
|
|
1660
|
+
|
|
1661
|
+
// Initiate the MPQ search
|
|
1662
|
+
pLogger->PrintProgress("Searching the archive (initializing) ...");
|
|
1663
|
+
hFind = SFileFindFirstFile(hMpq, "*", &sf, szListFile);
|
|
1664
|
+
if(hFind == NULL)
|
|
1665
|
+
{
|
|
1666
|
+
dwErrCode = GetLastError();
|
|
1667
|
+
dwErrCode = (dwErrCode == ERROR_NO_MORE_FILES) ? ERROR_SUCCESS : dwErrCode;
|
|
1668
|
+
return dwErrCode;
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
// Perform the search
|
|
1672
|
+
pLogger->PrintProgress("Searching the archive ...");
|
|
1673
|
+
while(bFound == true)
|
|
1674
|
+
{
|
|
1675
|
+
// Increment number of files
|
|
1676
|
+
dwFileCount++;
|
|
1677
|
+
|
|
1678
|
+
// Load the file to memory, if required
|
|
1679
|
+
if(dwSearchFlags & SEARCH_FLAG_LOAD_FILES)
|
|
1680
|
+
{
|
|
1681
|
+
// Load the entire file to the MPQ
|
|
1682
|
+
if(LoadMpqFile(*pLogger, hMpq, sf.cFileName, sf.lcLocale, dwSearchFlags, &pFileData) == ERROR_SUCCESS && pFileData != NULL)
|
|
1683
|
+
{
|
|
1684
|
+
// Hash the file data, if needed
|
|
1685
|
+
if((dwSearchFlags & SEARCH_FLAG_HASH_FILES) && !IsInternalMpqFileName(sf.cFileName))
|
|
1686
|
+
md5_process(&md5state, pFileData->FileData, pFileData->dwFileSize);
|
|
1687
|
+
|
|
1688
|
+
// Play sound files, if required
|
|
1689
|
+
if((dwSearchFlags & SEARCH_FLAG_PLAY_WAVES) && strstr(sf.cFileName, ".wav") != NULL)
|
|
1690
|
+
{
|
|
1691
|
+
pLogger->PrintProgress("Playing sound %s", sf.cFileName);
|
|
1692
|
+
PlayWaveSound(pFileData);
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
// Debug: Show CRC32 of each file in order to debug differences
|
|
1696
|
+
if(fp != NULL)
|
|
1697
|
+
{
|
|
1698
|
+
pFileData->dwCrc32 = crc32(0, pFileData->FileData, pFileData->dwFileSize);
|
|
1699
|
+
fprintf(fp, "%08x:%08x: %s \n", pFileData->dwFileSize, pFileData->dwCrc32, sf.cFileName);
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
// Also write the content of the file to the test directory
|
|
1703
|
+
//if(fp != NULL)
|
|
1704
|
+
//{
|
|
1705
|
+
// FILE * fp2;
|
|
1706
|
+
// char szFullPath[MAX_PATH] = "C:\\test\\";
|
|
1707
|
+
|
|
1708
|
+
// strcat(szFullPath, sf.cFileName);
|
|
1709
|
+
// if((fp2 = fopen(szFullPath, "wb")) != NULL)
|
|
1710
|
+
// {
|
|
1711
|
+
// fwrite(pFileData->FileData, 1, pFileData->dwFileSize, fp2);
|
|
1712
|
+
// fclose(fp2);
|
|
1713
|
+
// }
|
|
1714
|
+
//}
|
|
1715
|
+
|
|
1716
|
+
// Free the loaded file data
|
|
1717
|
+
STORM_FREE(pFileData);
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
// The last file that was OK
|
|
1722
|
+
bFound = SFileFindNextFile(hFind, &sf);
|
|
1723
|
+
}
|
|
1724
|
+
SFileFindClose(hFind);
|
|
1725
|
+
|
|
1726
|
+
// Give the file count, if required
|
|
1727
|
+
if(pdwFileCount != NULL)
|
|
1728
|
+
pdwFileCount[0] = dwFileCount;
|
|
1729
|
+
|
|
1730
|
+
// Give the hash, if required
|
|
1731
|
+
if(pbFileHash != NULL && (dwSearchFlags & SEARCH_FLAG_HASH_FILES))
|
|
1732
|
+
md5_done(&md5state, pbFileHash);
|
|
1733
|
+
|
|
1734
|
+
// Close the log file, if any
|
|
1735
|
+
if(fp != NULL)
|
|
1736
|
+
fclose(fp);
|
|
1737
|
+
return dwErrCode;
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
static DWORD VerifyDataChecksum(TLogHelper & Logger, HANDLE hMpq, DWORD dwSearchFlags, LPCSTR szExpectedHash, DWORD dwExpectedFileCount)
|
|
1741
|
+
{
|
|
1742
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1743
|
+
DWORD dwFileCount = 0;
|
|
1744
|
+
BYTE NameHash[MD5_DIGEST_SIZE] = {0};
|
|
1745
|
+
char szNameHash[0x40];
|
|
1746
|
+
|
|
1747
|
+
// Do nothing if no name hash and no known file count
|
|
1748
|
+
if(IS_VALID_STRING(szExpectedHash) || (dwExpectedFileCount != 0))
|
|
1749
|
+
{
|
|
1750
|
+
// Search the archive, obtain file count and name hash
|
|
1751
|
+
if((dwErrCode = SearchArchive(&Logger, hMpq, dwSearchFlags, &dwFileCount, NameHash)) != ERROR_SUCCESS)
|
|
1752
|
+
{
|
|
1753
|
+
Logger.PrintMessage("Failed to search the archive");
|
|
1754
|
+
return dwErrCode;
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
// Check the file count, if given
|
|
1758
|
+
if((dwExpectedFileCount != 0) && (dwExpectedFileCount != dwFileCount))
|
|
1759
|
+
{
|
|
1760
|
+
Logger.PrintMessage("File count mismatch(expected: %u, found: %u)", dwExpectedFileCount, dwFileCount);
|
|
1761
|
+
dwErrCode = ERROR_CAN_NOT_COMPLETE;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
// Check the MD5 hash, if given
|
|
1765
|
+
if(IS_VALID_STRING(szNameHash))
|
|
1766
|
+
{
|
|
1767
|
+
StringFromBinary(NameHash, MD5_DIGEST_SIZE, szNameHash);
|
|
1768
|
+
if(_stricmp(szNameHash, szExpectedHash))
|
|
1769
|
+
{
|
|
1770
|
+
Logger.PrintMessage("Extracted files MD5 mismatch (expected: %s, obtained: %s)", szExpectedHash, szNameHash);
|
|
1771
|
+
dwErrCode = ERROR_CAN_NOT_COMPLETE;
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
return dwErrCode;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
static DWORD CreateNewArchive(TLogHelper * pLogger, LPCTSTR szPlainName, DWORD dwCreateFlags, DWORD dwMaxFileCount, HANDLE * phMpq)
|
|
1779
|
+
{
|
|
1780
|
+
HANDLE hMpq = NULL;
|
|
1781
|
+
TCHAR szMpqName[MAX_PATH];
|
|
1782
|
+
TCHAR szFullPath[MAX_PATH];
|
|
1783
|
+
|
|
1784
|
+
// Make sure that the MPQ is deleted
|
|
1785
|
+
CreateFullPathName(szFullPath, _countof(szFullPath), NULL, szPlainName);
|
|
1786
|
+
_tremove(szFullPath);
|
|
1787
|
+
|
|
1788
|
+
// Create the new MPQ
|
|
1789
|
+
StringCopy(szMpqName, _countof(szMpqName), szFullPath);
|
|
1790
|
+
if(!SFileCreateArchive(szMpqName, dwCreateFlags, dwMaxFileCount, &hMpq))
|
|
1791
|
+
return pLogger->PrintError(_T("Failed to create archive %s"), szMpqName);
|
|
1792
|
+
|
|
1793
|
+
// Shall we close it right away?
|
|
1794
|
+
if(phMpq == NULL)
|
|
1795
|
+
SFileCloseArchive(hMpq);
|
|
1796
|
+
else
|
|
1797
|
+
*phMpq = hMpq;
|
|
1798
|
+
|
|
1799
|
+
return ERROR_SUCCESS;
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
static DWORD CreateNewArchive_V2(TLogHelper * pLogger, LPCTSTR szPlainName, DWORD dwCreateFlags, DWORD dwMaxFileCount, HANDLE * phMpq)
|
|
1803
|
+
{
|
|
1804
|
+
SFILE_CREATE_MPQ CreateInfo;
|
|
1805
|
+
HANDLE hMpq = NULL;
|
|
1806
|
+
TCHAR szMpqName[MAX_PATH];
|
|
1807
|
+
TCHAR szFullPath[MAX_PATH];
|
|
1808
|
+
|
|
1809
|
+
// Make sure that the MPQ is deleted
|
|
1810
|
+
CreateFullPathName(szFullPath, _countof(szFullPath), NULL, szPlainName);
|
|
1811
|
+
StringCopy(szMpqName, _countof(szMpqName), szFullPath);
|
|
1812
|
+
_tremove(szFullPath);
|
|
1813
|
+
|
|
1814
|
+
// Fill the create structure
|
|
1815
|
+
memset(&CreateInfo, 0, sizeof(SFILE_CREATE_MPQ));
|
|
1816
|
+
CreateInfo.cbSize = sizeof(SFILE_CREATE_MPQ);
|
|
1817
|
+
CreateInfo.dwMpqVersion = (dwCreateFlags & MPQ_CREATE_ARCHIVE_VMASK) >> FLAGS_TO_FORMAT_SHIFT;
|
|
1818
|
+
CreateInfo.dwStreamFlags = STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE;
|
|
1819
|
+
// CreateInfo.dwFileFlags1 = (dwCreateFlags & MPQ_CREATE_LISTFILE) ? MPQ_FILE_EXISTS : 0;
|
|
1820
|
+
// CreateInfo.dwFileFlags2 = (dwCreateFlags & MPQ_CREATE_ATTRIBUTES) ? MPQ_FILE_EXISTS : 0;
|
|
1821
|
+
CreateInfo.dwFileFlags1 = (dwCreateFlags & MPQ_CREATE_LISTFILE) ? MPQ_FILE_DEFAULT_INTERNAL : 0;
|
|
1822
|
+
CreateInfo.dwFileFlags2 = (dwCreateFlags & MPQ_CREATE_ATTRIBUTES) ? MPQ_FILE_DEFAULT_INTERNAL : 0;
|
|
1823
|
+
CreateInfo.dwFileFlags3 = (dwCreateFlags & MPQ_CREATE_SIGNATURE) ? MPQ_FILE_DEFAULT_INTERNAL : 0;
|
|
1824
|
+
CreateInfo.dwAttrFlags = (dwCreateFlags & MPQ_CREATE_ATTRIBUTES) ? (MPQ_ATTRIBUTE_CRC32 | MPQ_ATTRIBUTE_FILETIME | MPQ_ATTRIBUTE_MD5) : 0;
|
|
1825
|
+
CreateInfo.dwSectorSize = (CreateInfo.dwMpqVersion >= MPQ_FORMAT_VERSION_3) ? 0x4000 : 0x1000;
|
|
1826
|
+
CreateInfo.dwRawChunkSize = (CreateInfo.dwMpqVersion >= MPQ_FORMAT_VERSION_4) ? 0x4000 : 0;
|
|
1827
|
+
CreateInfo.dwMaxFileCount = dwMaxFileCount;
|
|
1828
|
+
|
|
1829
|
+
// Create the new MPQ
|
|
1830
|
+
if(!SFileCreateArchive2(szMpqName, &CreateInfo, &hMpq))
|
|
1831
|
+
return pLogger->PrintError(_T("Failed to create archive %s"), szMpqName);
|
|
1832
|
+
|
|
1833
|
+
// Shall we close it right away?
|
|
1834
|
+
if(phMpq == NULL)
|
|
1835
|
+
SFileCloseArchive(hMpq);
|
|
1836
|
+
else
|
|
1837
|
+
*phMpq = hMpq;
|
|
1838
|
+
|
|
1839
|
+
return ERROR_SUCCESS;
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
static DWORD OpenExistingArchive(TLogHelper * pLogger, LPCTSTR szFullPath, DWORD dwOpenFlags, HANDLE * phMpq)
|
|
1843
|
+
{
|
|
1844
|
+
HANDLE hMpq = NULL;
|
|
1845
|
+
size_t nMarkerIndex;
|
|
1846
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1847
|
+
|
|
1848
|
+
// Get the stream provider from the MPQ prefix or MPQ name
|
|
1849
|
+
if(_tcsnicmp(szFullPath, _T("flat-file://"), 11))
|
|
1850
|
+
{
|
|
1851
|
+
if(_tcsstr(szFullPath, _T(".MPQE")) != NULL)
|
|
1852
|
+
dwOpenFlags |= STREAM_PROVIDER_MPQE;
|
|
1853
|
+
if(_tcsstr(szFullPath, _T(".MPQ.part")) != NULL)
|
|
1854
|
+
dwOpenFlags |= STREAM_PROVIDER_PARTIAL;
|
|
1855
|
+
if(_tcsstr(szFullPath, _T(".mpq.part")) != NULL)
|
|
1856
|
+
dwOpenFlags |= STREAM_PROVIDER_PARTIAL;
|
|
1857
|
+
if(_tcsstr(szFullPath, _T(".MPQ.0")) != NULL)
|
|
1858
|
+
dwOpenFlags |= STREAM_PROVIDER_BLOCK4;
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
// Handle ASI files properly
|
|
1862
|
+
nMarkerIndex = (_tcsstr(szFullPath, _T(".asi")) != NULL) ? 1 : 0;
|
|
1863
|
+
SFileSetArchiveMarkers(&MpqMarkers[nMarkerIndex]);
|
|
1864
|
+
|
|
1865
|
+
// Open the copied archive
|
|
1866
|
+
pLogger->PrintProgress(_T("Opening archive %s ..."), GetShortPlainName(szFullPath));
|
|
1867
|
+
if(!SFileOpenArchive(szFullPath, 0, dwOpenFlags, &hMpq))
|
|
1868
|
+
{
|
|
1869
|
+
switch(dwErrCode = GetLastError())
|
|
1870
|
+
{
|
|
1871
|
+
// case ERROR_BAD_FORMAT: // If the error is ERROR_BAD_FORMAT, try to open with MPQ_OPEN_FORCE_MPQ_V1
|
|
1872
|
+
// bReopenResult = SFileOpenArchive(szMpqName, 0, dwFlags | MPQ_OPEN_FORCE_MPQ_V1, &hMpq);
|
|
1873
|
+
// dwErrCode = (bReopenResult == false) ? GetLastError() : ERROR_SUCCESS;
|
|
1874
|
+
// break;
|
|
1875
|
+
|
|
1876
|
+
case ERROR_AVI_FILE: // Ignore the error if it's an AVI file or if the file is incomplete
|
|
1877
|
+
case ERROR_FILE_INCOMPLETE:
|
|
1878
|
+
return dwErrCode;
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
// Show the open error to the user
|
|
1882
|
+
if((dwOpenFlags & MPQ_OPEN_DONT_REPORT_FAILURE) == 0)
|
|
1883
|
+
dwErrCode = pLogger->PrintError(_T("Failed to open archive %s"), szFullPath);
|
|
1884
|
+
return dwErrCode;
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
// Store the archive handle or close the archive
|
|
1888
|
+
if(phMpq == NULL)
|
|
1889
|
+
SFileCloseArchive(hMpq);
|
|
1890
|
+
else
|
|
1891
|
+
*phMpq = hMpq;
|
|
1892
|
+
return dwErrCode;
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
static DWORD OpenExistingArchiveWithCopy(TLogHelper * pLogger, LPCTSTR szFileName, LPCTSTR szCopyName, HANDLE * phMpq, DWORD dwOpenFlags = 0)
|
|
1896
|
+
{
|
|
1897
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1898
|
+
TCHAR szFullPath[MAX_PATH];
|
|
1899
|
+
|
|
1900
|
+
// We expect MPQ directory to be already prepared by InitializeMpqDirectory
|
|
1901
|
+
assert(szMpqDirectory[0] != 0);
|
|
1902
|
+
|
|
1903
|
+
// At least one name must be entered
|
|
1904
|
+
assert(szFileName != NULL || szCopyName != NULL);
|
|
1905
|
+
|
|
1906
|
+
// If both names entered, create a copy
|
|
1907
|
+
if(szFileName != NULL && szCopyName != NULL)
|
|
1908
|
+
{
|
|
1909
|
+
dwErrCode = CreateFileCopy(pLogger, szFileName, szCopyName, szFullPath, _countof(szFullPath));
|
|
1910
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
1911
|
+
return dwErrCode;
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
// If only source name entered, open it for read-only access
|
|
1915
|
+
else if(szFileName != NULL && szCopyName == NULL)
|
|
1916
|
+
{
|
|
1917
|
+
CreateFullPathName(szFullPath, _countof(szFullPath), szMpqSubDir, szFileName);
|
|
1918
|
+
dwOpenFlags |= MPQ_OPEN_READ_ONLY;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
// If only target name entered, open it directly
|
|
1922
|
+
else if(szFileName == NULL && szCopyName != NULL)
|
|
1923
|
+
{
|
|
1924
|
+
CreateFullPathName(szFullPath, _countof(szFullPath), NULL, szCopyName);
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
// Open the archive
|
|
1928
|
+
return OpenExistingArchive(pLogger, szFullPath, dwOpenFlags, phMpq);
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
static DWORD AddFileToMpq(
|
|
1932
|
+
TLogHelper * pLogger,
|
|
1933
|
+
HANDLE hMpq,
|
|
1934
|
+
LPCSTR szFileName,
|
|
1935
|
+
LPCSTR szFileData,
|
|
1936
|
+
DWORD dwFlags = 0,
|
|
1937
|
+
DWORD dwCompression = 0,
|
|
1938
|
+
DWORD dwExpectedError = ERROR_SUCCESS)
|
|
1939
|
+
{
|
|
1940
|
+
HANDLE hFile = NULL;
|
|
1941
|
+
DWORD dwFileSize = (DWORD)strlen(szFileData);
|
|
1942
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
1943
|
+
|
|
1944
|
+
// Notify the user
|
|
1945
|
+
pLogger->PrintProgress("Adding file %s ...", szFileName);
|
|
1946
|
+
|
|
1947
|
+
// Get the default flags
|
|
1948
|
+
if(dwFlags == 0)
|
|
1949
|
+
dwFlags = MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED;
|
|
1950
|
+
if(dwCompression == 0)
|
|
1951
|
+
dwCompression = MPQ_COMPRESSION_ZLIB;
|
|
1952
|
+
|
|
1953
|
+
// Create the file within the MPQ
|
|
1954
|
+
if(SFileCreateFile(hMpq, szFileName, 0, dwFileSize, 0, dwFlags, &hFile))
|
|
1955
|
+
{
|
|
1956
|
+
// Write the file
|
|
1957
|
+
if(!SFileWriteFile(hFile, szFileData, dwFileSize, dwCompression))
|
|
1958
|
+
dwErrCode = pLogger->PrintError("Failed to write data to the MPQ");
|
|
1959
|
+
SFileCloseFile(hFile);
|
|
1960
|
+
}
|
|
1961
|
+
else
|
|
1962
|
+
{
|
|
1963
|
+
dwErrCode = GetLastError();
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
// Check the expected error code
|
|
1967
|
+
if(dwExpectedError != ERROR_UNDETERMINED_RESULT)
|
|
1968
|
+
{
|
|
1969
|
+
if(dwErrCode != dwExpectedError)
|
|
1970
|
+
{
|
|
1971
|
+
pLogger->PrintError("Unexpected result from SFileCreateFile(%s)", szFileName);
|
|
1972
|
+
dwErrCode = ERROR_CAN_NOT_COMPLETE;
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
return dwErrCode;
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
static DWORD AddLocalFileToMpq(
|
|
1979
|
+
TLogHelper * pLogger,
|
|
1980
|
+
HANDLE hMpq,
|
|
1981
|
+
LPCSTR szArchivedName,
|
|
1982
|
+
LPCTSTR szFileFullName,
|
|
1983
|
+
DWORD dwFlags = 0,
|
|
1984
|
+
DWORD dwCompression = 0,
|
|
1985
|
+
bool bMustSucceed = false)
|
|
1986
|
+
{
|
|
1987
|
+
TCHAR szFileName[MAX_PATH];
|
|
1988
|
+
DWORD dwVerifyResult;
|
|
1989
|
+
|
|
1990
|
+
// Notify the user
|
|
1991
|
+
pLogger->PrintProgress("Adding file %s (%u of %u)...", GetShortPlainName(szFileFullName), pLogger->UserCount, pLogger->UserTotal);
|
|
1992
|
+
pLogger->UserString = szArchivedName;
|
|
1993
|
+
|
|
1994
|
+
// Get the default flags
|
|
1995
|
+
if(dwFlags == 0)
|
|
1996
|
+
dwFlags = MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED;
|
|
1997
|
+
if(dwCompression == 0)
|
|
1998
|
+
dwCompression = MPQ_COMPRESSION_ZLIB;
|
|
1999
|
+
|
|
2000
|
+
// Set the notification callback
|
|
2001
|
+
SFileSetAddFileCallback(hMpq, AddFileCallback, pLogger);
|
|
2002
|
+
|
|
2003
|
+
// Add the file to the MPQ
|
|
2004
|
+
StringCopy(szFileName, _countof(szFileName), szFileFullName);
|
|
2005
|
+
if(!SFileAddFileEx(hMpq, szFileName, szArchivedName, dwFlags, dwCompression, MPQ_COMPRESSION_NEXT_SAME))
|
|
2006
|
+
{
|
|
2007
|
+
if(bMustSucceed)
|
|
2008
|
+
return pLogger->PrintError("Failed to add the file %s", szArchivedName);
|
|
2009
|
+
return GetLastError();
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
// Verify the file unless it was lossy compression
|
|
2013
|
+
if((dwCompression & (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO)) == 0)
|
|
2014
|
+
{
|
|
2015
|
+
// Notify the user
|
|
2016
|
+
pLogger->PrintProgress("Verifying file %s (%u of %u) ...", szArchivedName, pLogger->UserCount, pLogger->UserTotal);
|
|
2017
|
+
|
|
2018
|
+
// Perform the verification
|
|
2019
|
+
dwVerifyResult = SFileVerifyFile(hMpq, szArchivedName, MPQ_ATTRIBUTE_CRC32 | MPQ_ATTRIBUTE_MD5);
|
|
2020
|
+
if(dwVerifyResult & (VERIFY_OPEN_ERROR | VERIFY_READ_ERROR | VERIFY_FILE_SECTOR_CRC_ERROR | VERIFY_FILE_CHECKSUM_ERROR | VERIFY_FILE_MD5_ERROR))
|
|
2021
|
+
return pLogger->PrintError("CRC error on %s", szArchivedName);
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
return ERROR_SUCCESS;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
static DWORD RemoveMpqFile(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, DWORD dwExpectedError)
|
|
2028
|
+
{
|
|
2029
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2030
|
+
|
|
2031
|
+
// Notify the user
|
|
2032
|
+
pLogger->PrintProgress("Removing file %s ...", szFileName);
|
|
2033
|
+
|
|
2034
|
+
// Perform the deletion
|
|
2035
|
+
if(!SFileRemoveFile(hMpq, szFileName, 0))
|
|
2036
|
+
dwErrCode = GetLastError();
|
|
2037
|
+
|
|
2038
|
+
if(dwErrCode != dwExpectedError)
|
|
2039
|
+
return pLogger->PrintError("Unexpected result from SFileRemoveFile(%s)", szFileName);
|
|
2040
|
+
return ERROR_SUCCESS;
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
//-----------------------------------------------------------------------------
|
|
2044
|
+
// Tests
|
|
2045
|
+
|
|
2046
|
+
static void TestGetFileInfo(
|
|
2047
|
+
TLogHelper * pLogger,
|
|
2048
|
+
HANDLE hMpqOrFile,
|
|
2049
|
+
SFileInfoClass InfoClass,
|
|
2050
|
+
void * pvFileInfo,
|
|
2051
|
+
DWORD cbFileInfo,
|
|
2052
|
+
DWORD * pcbLengthNeeded,
|
|
2053
|
+
bool bExpectedResult,
|
|
2054
|
+
DWORD dwExpectedErrCode)
|
|
2055
|
+
{
|
|
2056
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2057
|
+
bool bResult;
|
|
2058
|
+
|
|
2059
|
+
// Call the get file info
|
|
2060
|
+
bResult = SFileGetFileInfo(hMpqOrFile, InfoClass, pvFileInfo, cbFileInfo, pcbLengthNeeded);
|
|
2061
|
+
if(!bResult)
|
|
2062
|
+
dwErrCode = GetLastError();
|
|
2063
|
+
|
|
2064
|
+
// Check the expected results
|
|
2065
|
+
if(bResult != bExpectedResult)
|
|
2066
|
+
pLogger->PrintMessage("Different result of SFileGetFileInfo.");
|
|
2067
|
+
if(dwErrCode != dwExpectedErrCode)
|
|
2068
|
+
pLogger->PrintMessage("Different error from SFileGetFileInfo (expected %u, returned %u)", dwExpectedErrCode, dwErrCode);
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
// StormLib is able to open local files (as well as the original Storm.dll)
|
|
2072
|
+
// I want to keep this for occasional use
|
|
2073
|
+
|
|
2074
|
+
static LINE_INFO Lines[] =
|
|
2075
|
+
{
|
|
2076
|
+
{0x000, 18, "accountbilling.url"},
|
|
2077
|
+
{0x013, 45, "alternate/character/goblin/male/goblinmale.m2"},
|
|
2078
|
+
{0x9ab, 54, "alternate/character/goblin/male/goblinmale0186-00.anim"}
|
|
2079
|
+
};
|
|
2080
|
+
|
|
2081
|
+
static DWORD TestOnLocalListFile_Read(TLogHelper & Logger, HANDLE hFile)
|
|
2082
|
+
{
|
|
2083
|
+
for(size_t i = 0; i < _countof(Lines); i++)
|
|
2084
|
+
{
|
|
2085
|
+
DWORD dwBytesRead = 0;
|
|
2086
|
+
char szFileLine[0x100] = {0};
|
|
2087
|
+
|
|
2088
|
+
SFileSetFilePointer(hFile, Lines[i].nLinePos, NULL, FILE_BEGIN);
|
|
2089
|
+
SFileReadFile(hFile, szFileLine, Lines[i].nLineLen, &dwBytesRead, NULL);
|
|
2090
|
+
|
|
2091
|
+
if(dwBytesRead != Lines[i].nLineLen)
|
|
2092
|
+
{
|
|
2093
|
+
Logger.PrintMessage("Line %u length mismatch", i);
|
|
2094
|
+
return false;
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
if(strcmp(szFileLine, Lines[i].szLine))
|
|
2098
|
+
{
|
|
2099
|
+
Logger.PrintMessage("Line %u content mismatch", i);
|
|
2100
|
+
return false;
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
return true;
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
static DWORD TestOnLocalListFile(LPCTSTR szPlainName)
|
|
2108
|
+
{
|
|
2109
|
+
TLogHelper Logger("TestLiFiSearch", szPlainName);
|
|
2110
|
+
SFILE_FIND_DATA sf;
|
|
2111
|
+
HANDLE hFile;
|
|
2112
|
+
HANDLE hFind;
|
|
2113
|
+
DWORD dwFileSizeHi = 0;
|
|
2114
|
+
DWORD dwFileSizeLo = 0;
|
|
2115
|
+
TCHAR szFullPath[MAX_PATH];
|
|
2116
|
+
char szFileName1[MAX_PATH];
|
|
2117
|
+
char szFileName2[MAX_PATH];
|
|
2118
|
+
int nFileCount = 0;
|
|
2119
|
+
|
|
2120
|
+
// Get the full name of the local file
|
|
2121
|
+
CreateFullPathName(szFileName1, _countof(szFileName1), szDataFileDir, szPlainName);
|
|
2122
|
+
|
|
2123
|
+
// Test opening the local file
|
|
2124
|
+
if(SFileOpenFileEx(NULL, szFileName1, SFILE_OPEN_LOCAL_FILE, &hFile))
|
|
2125
|
+
{
|
|
2126
|
+
// Retrieve the file name. It must match the name under which the file was open
|
|
2127
|
+
if(FileStream_Prefix(szPlainName, NULL) == 0)
|
|
2128
|
+
{
|
|
2129
|
+
SFileGetFileName(hFile, szFileName2);
|
|
2130
|
+
if(strcmp(szFileName2, szFileName1))
|
|
2131
|
+
Logger.PrintMessage("The retrieved name does not match the open name");
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
// Retrieve the file size
|
|
2135
|
+
dwFileSizeLo = SFileGetFileSize(hFile, &dwFileSizeHi);
|
|
2136
|
+
if(dwFileSizeHi != 0 || dwFileSizeLo != 0x04385a4e)
|
|
2137
|
+
Logger.PrintMessage("Local file size mismatch");
|
|
2138
|
+
|
|
2139
|
+
// Read few lines, check their content
|
|
2140
|
+
TestOnLocalListFile_Read(Logger, hFile);
|
|
2141
|
+
SFileCloseFile(hFile);
|
|
2142
|
+
}
|
|
2143
|
+
else
|
|
2144
|
+
return Logger.PrintError("Failed to open local listfile");
|
|
2145
|
+
|
|
2146
|
+
// We need unicode listfile name
|
|
2147
|
+
StringCopy(szFullPath, _countof(szFullPath), szFileName1);
|
|
2148
|
+
|
|
2149
|
+
// Start searching in the listfile
|
|
2150
|
+
hFind = SListFileFindFirstFile(NULL, szFullPath, "*", &sf);
|
|
2151
|
+
if(hFind != NULL)
|
|
2152
|
+
{
|
|
2153
|
+
for(;;)
|
|
2154
|
+
{
|
|
2155
|
+
Logger.PrintProgress("Found file (%04u): %s", nFileCount++, GetShortPlainName(sf.cFileName));
|
|
2156
|
+
if(!SListFileFindNextFile(hFind, &sf))
|
|
2157
|
+
break;
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
SListFileFindClose(hFind);
|
|
2161
|
+
}
|
|
2162
|
+
else
|
|
2163
|
+
return Logger.PrintError("Failed to search local listfile");
|
|
2164
|
+
|
|
2165
|
+
return ERROR_SUCCESS;
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
static void WINAPI TestReadFile_DownloadCallback(
|
|
2169
|
+
void * UserData,
|
|
2170
|
+
ULONGLONG ByteOffset,
|
|
2171
|
+
DWORD DataLength)
|
|
2172
|
+
{
|
|
2173
|
+
TLogHelper * pLogger = (TLogHelper *)UserData;
|
|
2174
|
+
|
|
2175
|
+
if(ByteOffset != 0 && DataLength != 0)
|
|
2176
|
+
pLogger->PrintProgress("Downloading data (offset: " fmt_I64X_a ", length: %X)", ByteOffset, DataLength);
|
|
2177
|
+
else
|
|
2178
|
+
pLogger->PrintProgress("Download complete.");
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2181
|
+
// Open a file stream with mirroring a master file
|
|
2182
|
+
static DWORD TestReadFile_MasterMirror(LPCTSTR szMirrorName, LPCTSTR szMasterName, bool bCopyMirrorFile)
|
|
2183
|
+
{
|
|
2184
|
+
TFileStream * pStream1; // Master file
|
|
2185
|
+
TFileStream * pStream2; // Mirror file
|
|
2186
|
+
TLogHelper Logger("TestFileMirror", szMirrorName);
|
|
2187
|
+
TCHAR szMirrorPath[MAX_PATH + MAX_PATH];
|
|
2188
|
+
TCHAR szMasterPath[MAX_PATH];
|
|
2189
|
+
DWORD dwProvider = 0;
|
|
2190
|
+
int nIterations = 0x10000;
|
|
2191
|
+
DWORD dwErrCode;
|
|
2192
|
+
|
|
2193
|
+
// Retrieve the provider
|
|
2194
|
+
FileStream_Prefix(szMasterName, &dwProvider);
|
|
2195
|
+
|
|
2196
|
+
#ifndef STORMLIB_WINDOWS
|
|
2197
|
+
if((dwProvider & BASE_PROVIDER_MASK) == BASE_PROVIDER_HTTP)
|
|
2198
|
+
return ERROR_SUCCESS;
|
|
2199
|
+
#endif
|
|
2200
|
+
|
|
2201
|
+
// Create copy of the file to serve as mirror, keep master there
|
|
2202
|
+
dwErrCode = CreateMasterAndMirrorPaths(&Logger, szMirrorPath, szMasterPath, szMirrorName, szMasterName, bCopyMirrorFile);
|
|
2203
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2204
|
+
{
|
|
2205
|
+
// Open both master and mirror file
|
|
2206
|
+
pStream1 = FileStream_OpenFile(szMasterPath, STREAM_FLAG_READ_ONLY);
|
|
2207
|
+
pStream2 = FileStream_OpenFile(szMirrorPath, STREAM_FLAG_READ_ONLY | STREAM_FLAG_USE_BITMAP);
|
|
2208
|
+
if(pStream1 && pStream2)
|
|
2209
|
+
{
|
|
2210
|
+
// For internet based files, we limit the number of operations
|
|
2211
|
+
if((dwProvider & BASE_PROVIDER_MASK) == BASE_PROVIDER_HTTP)
|
|
2212
|
+
nIterations = 0x80;
|
|
2213
|
+
|
|
2214
|
+
FileStream_SetCallback(pStream2, TestReadFile_DownloadCallback, &Logger);
|
|
2215
|
+
dwErrCode = CompareTwoLocalFilesRR(&Logger, pStream1, pStream2, nIterations);
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
if(pStream2 != NULL)
|
|
2219
|
+
FileStream_Close(pStream2);
|
|
2220
|
+
if(pStream1 != NULL)
|
|
2221
|
+
FileStream_Close(pStream1);
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
return dwErrCode;
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
// Test of the TFileStream object
|
|
2228
|
+
static DWORD TestFileStreamOperations(LPCTSTR szPlainName, DWORD dwStreamFlags)
|
|
2229
|
+
{
|
|
2230
|
+
TFileStream * pStream = NULL;
|
|
2231
|
+
TLogHelper Logger("TestFileStream", szPlainName);
|
|
2232
|
+
ULONGLONG ByteOffset;
|
|
2233
|
+
ULONGLONG FileSize = 0;
|
|
2234
|
+
TCHAR szFullPath[MAX_PATH];
|
|
2235
|
+
DWORD dwRequiredFlags = 0;
|
|
2236
|
+
BYTE Buffer[0x10];
|
|
2237
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2238
|
+
|
|
2239
|
+
// Copy the file so we won't screw up
|
|
2240
|
+
if((dwStreamFlags & STREAM_PROVIDER_MASK) == STREAM_PROVIDER_BLOCK4)
|
|
2241
|
+
CreateFullPathName(szFullPath, _countof(szFullPath), szMpqSubDir, szPlainName);
|
|
2242
|
+
else
|
|
2243
|
+
dwErrCode = CreateFileCopy(&Logger, szPlainName, szPlainName, szFullPath, _countof(szFullPath));
|
|
2244
|
+
|
|
2245
|
+
// Open the file stream
|
|
2246
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2247
|
+
{
|
|
2248
|
+
pStream = FileStream_OpenFile(szFullPath, dwStreamFlags);
|
|
2249
|
+
if(pStream == NULL)
|
|
2250
|
+
return Logger.PrintError(_T("Open failed: %s"), szFullPath);
|
|
2251
|
+
}
|
|
2252
|
+
|
|
2253
|
+
// Get the size of the file stream
|
|
2254
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2255
|
+
{
|
|
2256
|
+
if(!FileStream_GetFlags(pStream, &dwStreamFlags))
|
|
2257
|
+
dwErrCode = Logger.PrintError("Failed to retrieve the stream flags");
|
|
2258
|
+
|
|
2259
|
+
if(!FileStream_GetSize(pStream, &FileSize))
|
|
2260
|
+
dwErrCode = Logger.PrintError("Failed to retrieve the file size");
|
|
2261
|
+
|
|
2262
|
+
// Any other stream except STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE should be read-only
|
|
2263
|
+
if((dwStreamFlags & STREAM_PROVIDERS_MASK) != (STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE))
|
|
2264
|
+
dwRequiredFlags |= STREAM_FLAG_READ_ONLY;
|
|
2265
|
+
// if(pStream->BlockPresent)
|
|
2266
|
+
// dwRequiredFlags |= STREAM_FLAG_READ_ONLY;
|
|
2267
|
+
|
|
2268
|
+
// Check the flags there
|
|
2269
|
+
if((dwStreamFlags & dwRequiredFlags) != dwRequiredFlags)
|
|
2270
|
+
{
|
|
2271
|
+
Logger.PrintMessage("The stream should be read-only but it isn't");
|
|
2272
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
// After successful open, the stream position must be zero
|
|
2277
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2278
|
+
dwErrCode = VerifyFilePosition(&Logger, pStream, 0);
|
|
2279
|
+
|
|
2280
|
+
// Read the MPQ header from the current file offset.
|
|
2281
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2282
|
+
dwErrCode = VerifyFileMpqHeader(&Logger, pStream, NULL);
|
|
2283
|
+
|
|
2284
|
+
// After successful open, the stream position must sizeof(TMPQHeader)
|
|
2285
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2286
|
+
dwErrCode = VerifyFilePosition(&Logger, pStream, sizeof(TMPQHeader));
|
|
2287
|
+
|
|
2288
|
+
// Now try to read the MPQ header from the offset 0
|
|
2289
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2290
|
+
{
|
|
2291
|
+
ByteOffset = 0;
|
|
2292
|
+
dwErrCode = VerifyFileMpqHeader(&Logger, pStream, &ByteOffset);
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
// After successful open, the stream position must sizeof(TMPQHeader)
|
|
2296
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2297
|
+
dwErrCode = VerifyFilePosition(&Logger, pStream, sizeof(TMPQHeader));
|
|
2298
|
+
|
|
2299
|
+
// Try a write operation
|
|
2300
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2301
|
+
{
|
|
2302
|
+
bool bExpectedResult = (dwStreamFlags & STREAM_FLAG_READ_ONLY) ? false : true;
|
|
2303
|
+
bool bResult;
|
|
2304
|
+
|
|
2305
|
+
// Attempt to write to the file
|
|
2306
|
+
ByteOffset = 0;
|
|
2307
|
+
bResult = FileStream_Write(pStream, &ByteOffset, Buffer, sizeof(Buffer));
|
|
2308
|
+
|
|
2309
|
+
// If the result is not expected
|
|
2310
|
+
if(bResult != bExpectedResult)
|
|
2311
|
+
{
|
|
2312
|
+
Logger.PrintMessage("FileStream_Write result is different than expected");
|
|
2313
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
|
|
2317
|
+
// Move the position 9 bytes from the end and try to read 10 bytes.
|
|
2318
|
+
// This must fail, because stream reading functions are "all or nothing"
|
|
2319
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2320
|
+
{
|
|
2321
|
+
ByteOffset = FileSize - 9;
|
|
2322
|
+
if(FileStream_Read(pStream, &ByteOffset, Buffer, 10))
|
|
2323
|
+
{
|
|
2324
|
+
Logger.PrintMessage("FileStream_Read succeeded, but it shouldn't");
|
|
2325
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
|
|
2329
|
+
// Try again with 9 bytes. This must succeed, unless the file block is not available
|
|
2330
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2331
|
+
{
|
|
2332
|
+
ByteOffset = FileSize - 9;
|
|
2333
|
+
if(!FileStream_Read(pStream, &ByteOffset, Buffer, 9))
|
|
2334
|
+
{
|
|
2335
|
+
Logger.PrintMessage("FileStream_Read from the end of the file failed");
|
|
2336
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
|
|
2340
|
+
// Verify file position - it must be at the end of the file
|
|
2341
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2342
|
+
dwErrCode = VerifyFilePosition(&Logger, pStream, FileSize);
|
|
2343
|
+
|
|
2344
|
+
// Close the stream
|
|
2345
|
+
if(pStream != NULL)
|
|
2346
|
+
FileStream_Close(pStream);
|
|
2347
|
+
return dwErrCode;
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
static DWORD TestArchive_LoadFiles(TLogHelper * pLogger, HANDLE hMpq, DWORD bIgnoreOpenErrors, ...)
|
|
2351
|
+
{
|
|
2352
|
+
PFILE_DATA pFileData;
|
|
2353
|
+
const char * szFileName;
|
|
2354
|
+
va_list argList;
|
|
2355
|
+
DWORD dwSearchFlags = (bIgnoreOpenErrors) ? SEARCH_FLAG_IGNORE_ERRORS : 0;
|
|
2356
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2357
|
+
|
|
2358
|
+
va_start(argList, bIgnoreOpenErrors);
|
|
2359
|
+
while((szFileName = va_arg(argList, const char *)) != NULL)
|
|
2360
|
+
{
|
|
2361
|
+
if(SFileHasFile(hMpq, szFileName))
|
|
2362
|
+
{
|
|
2363
|
+
dwErrCode = LoadMpqFile(*pLogger, hMpq, szFileName, 0, dwSearchFlags, &pFileData);
|
|
2364
|
+
if(dwErrCode != ERROR_SUCCESS && bIgnoreOpenErrors == 0)
|
|
2365
|
+
{
|
|
2366
|
+
pLogger->PrintError("Error loading the file %s", szFileName);
|
|
2367
|
+
break;
|
|
2368
|
+
}
|
|
2369
|
+
else
|
|
2370
|
+
{
|
|
2371
|
+
dwErrCode = ERROR_SUCCESS;
|
|
2372
|
+
STORM_FREE(pFileData);
|
|
2373
|
+
pFileData = NULL;
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
va_end(argList);
|
|
2378
|
+
|
|
2379
|
+
return dwErrCode;
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
//-----------------------------------------------------------------------------
|
|
2383
|
+
// Testing archive operations: Single archive
|
|
2384
|
+
|
|
2385
|
+
static DWORD TestOpenArchive_VerifySignature(TLogHelper & Logger, HANDLE hMpq, DWORD dwDoItIfNonZero)
|
|
2386
|
+
{
|
|
2387
|
+
DWORD dwSignatures = 0;
|
|
2388
|
+
DWORD dwVerifyError;
|
|
2389
|
+
|
|
2390
|
+
// Only do it if we asked to
|
|
2391
|
+
if(dwDoItIfNonZero)
|
|
2392
|
+
{
|
|
2393
|
+
// Query the signature types
|
|
2394
|
+
Logger.PrintProgress("Retrieving signatures ...");
|
|
2395
|
+
TestGetFileInfo(&Logger, hMpq, SFileMpqSignatures, &dwSignatures, sizeof(DWORD), NULL, true, ERROR_SUCCESS);
|
|
2396
|
+
|
|
2397
|
+
// Are there some signatures at all?
|
|
2398
|
+
if(dwSignatures == 0)
|
|
2399
|
+
{
|
|
2400
|
+
Logger.PrintMessage("No signatures present in the file");
|
|
2401
|
+
return ERROR_FILE_CORRUPT;
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
// Verify any of the present signatures
|
|
2405
|
+
Logger.PrintProgress("Verifying archive signature ...");
|
|
2406
|
+
dwVerifyError = SFileVerifyArchive(hMpq);
|
|
2407
|
+
|
|
2408
|
+
// Verify the result
|
|
2409
|
+
if((dwSignatures & SIGNATURE_TYPE_STRONG) && (dwVerifyError != ERROR_STRONG_SIGNATURE_OK))
|
|
2410
|
+
{
|
|
2411
|
+
Logger.PrintMessage("Strong signature verification error");
|
|
2412
|
+
return ERROR_FILE_CORRUPT;
|
|
2413
|
+
}
|
|
2414
|
+
|
|
2415
|
+
// Verify the result
|
|
2416
|
+
if((dwSignatures & SIGNATURE_TYPE_WEAK) && (dwVerifyError != ERROR_WEAK_SIGNATURE_OK))
|
|
2417
|
+
{
|
|
2418
|
+
Logger.PrintMessage("Weak signature verification error");
|
|
2419
|
+
return ERROR_FILE_CORRUPT;
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
return ERROR_SUCCESS;
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2425
|
+
static DWORD TestOpenArchive_Extra_ListFile(TLogHelper & Logger, HANDLE hMpq, PTEST_EXTRA_ONEFILE pExtra)
|
|
2426
|
+
{
|
|
2427
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2428
|
+
TCHAR szFullName[MAX_PATH];
|
|
2429
|
+
|
|
2430
|
+
if(IS_VALID_STRING(pExtra->szFile))
|
|
2431
|
+
{
|
|
2432
|
+
Logger.PrintProgress(_T("Adding listfile %s ..."), pExtra->szFile);
|
|
2433
|
+
CreateFullPathName(szFullName, _countof(szFullName), szListFileDir, pExtra->szFile);
|
|
2434
|
+
if((dwErrCode = SFileAddListFile(hMpq, szFullName)) != ERROR_SUCCESS)
|
|
2435
|
+
Logger.PrintMessage("Failed to add the listfile to the MPQ");
|
|
2436
|
+
}
|
|
2437
|
+
return dwErrCode;
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
static DWORD TestOpenArchive_Extra_Utf8File(TLogHelper & Logger, HANDLE hMpq, PTEST_EXTRA_UTF8 pExtra)
|
|
2441
|
+
{
|
|
2442
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2443
|
+
TCHAR szFullName[MAX_PATH];
|
|
2444
|
+
TCHAR szListName[MAX_PATH];
|
|
2445
|
+
|
|
2446
|
+
if(IS_VALID_STRING(pExtra->szListFile))
|
|
2447
|
+
{
|
|
2448
|
+
StringCopy(szListName, _countof(szListName), (const char *)pExtra->szListFile);
|
|
2449
|
+
Logger.PrintProgress(_T("Adding listfile %s ..."), szListName);
|
|
2450
|
+
CreateFullPathName(szFullName, _countof(szFullName), szListFileDir, szListName);
|
|
2451
|
+
if((dwErrCode = SFileAddListFile(hMpq, szFullName)) != ERROR_SUCCESS)
|
|
2452
|
+
Logger.PrintMessage("Failed to add the listfile to the MPQ");
|
|
2453
|
+
}
|
|
2454
|
+
return dwErrCode;
|
|
2455
|
+
}
|
|
2456
|
+
|
|
2457
|
+
static DWORD TestOpenArchive_Extra_TwoFiles(TLogHelper & Logger, HANDLE hMpq, DWORD dwSearchFlags, PTEST_EXTRA_TWOFILES pExtra)
|
|
2458
|
+
{
|
|
2459
|
+
PFILE_DATA pFileData1 = NULL;
|
|
2460
|
+
PFILE_DATA pFileData2 = NULL;
|
|
2461
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2462
|
+
|
|
2463
|
+
// Perform actions
|
|
2464
|
+
for(;;)
|
|
2465
|
+
{
|
|
2466
|
+
// Load and verify the first file, if any
|
|
2467
|
+
if(IS_VALID_STRING(pExtra->szFile1))
|
|
2468
|
+
{
|
|
2469
|
+
if((dwErrCode = LoadMpqFile(Logger, hMpq, pExtra->szFile1, 0, dwSearchFlags, &pFileData1)) != ERROR_SUCCESS)
|
|
2470
|
+
break;
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
// Load and verify the second file, if any
|
|
2474
|
+
if(IS_VALID_STRING(pExtra->szFile2))
|
|
2475
|
+
{
|
|
2476
|
+
if((dwErrCode = LoadMpqFile(Logger, hMpq, pExtra->szFile2, 0, dwSearchFlags, &pFileData2)) != ERROR_SUCCESS)
|
|
2477
|
+
break;
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
// If two files were given, they must be equal
|
|
2481
|
+
if(pFileData1 && pFileData2)
|
|
2482
|
+
{
|
|
2483
|
+
dwErrCode = CompareTwoFiles(Logger, pFileData1, pFileData2);
|
|
2484
|
+
}
|
|
2485
|
+
break;
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
// Free buffers and exit
|
|
2489
|
+
if(pFileData2 != NULL)
|
|
2490
|
+
STORM_FREE(pFileData2);
|
|
2491
|
+
if(pFileData1 != NULL)
|
|
2492
|
+
STORM_FREE(pFileData1);
|
|
2493
|
+
return dwErrCode;
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
static DWORD TestOpenArchive_Extra_Patches(TLogHelper & Logger, HANDLE hMpq, PTEST_EXTRA_PATCHES pExtra)
|
|
2497
|
+
{
|
|
2498
|
+
LPCTSTR szPatch;
|
|
2499
|
+
TCHAR szFullPath[MAX_PATH];
|
|
2500
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2501
|
+
|
|
2502
|
+
// Open all patches that are in the multi-SZ list
|
|
2503
|
+
if(IS_VALID_STRING(pExtra->szPatchList))
|
|
2504
|
+
{
|
|
2505
|
+
for(szPatch = pExtra->szPatchList; szPatch[0] != 0; szPatch = szPatch + _tcslen(szPatch) + 1)
|
|
2506
|
+
{
|
|
2507
|
+
Logger.PrintProgress(_T("Adding patch %s ..."), GetShortPlainName(szPatch));
|
|
2508
|
+
CreateFullPathName(szFullPath, _countof(szFullPath), szMpqPatchDir, szPatch);
|
|
2509
|
+
if(!SFileOpenPatchArchive(hMpq, szFullPath, NULL, 0))
|
|
2510
|
+
return Logger.PrintError(_T("Failed to add patch %s ..."), szFullPath);
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
|
|
2514
|
+
// Verify the patch count of the given file
|
|
2515
|
+
if(IS_VALID_STRING(pExtra->szFileName))
|
|
2516
|
+
dwErrCode = VerifyFilePatchCount(&Logger, hMpq, pExtra->szFileName, pExtra->dwPatchCount);
|
|
2517
|
+
return dwErrCode;
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
static DWORD TestOpenArchive_Extra_HashValues(TLogHelper & Logger, HANDLE hMpq, PTEST_EXTRA_HASHVALS pExtra)
|
|
2521
|
+
{
|
|
2522
|
+
HANDLE hFile = NULL;
|
|
2523
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2524
|
+
DWORD dwHash1 = 0;
|
|
2525
|
+
DWORD dwHash2 = 0;
|
|
2526
|
+
DWORD cbHash = 0;
|
|
2527
|
+
|
|
2528
|
+
for(size_t i = 0; i < _countof(pExtra->Items); i++)
|
|
2529
|
+
{
|
|
2530
|
+
PTEST_EXTRA_HASHVAL pItem = &pExtra->Items[i];
|
|
2531
|
+
|
|
2532
|
+
if(SFileOpenFileEx(hMpq, pItem->szFileName, 0, &hFile))
|
|
2533
|
+
{
|
|
2534
|
+
if(SFileGetFileInfo(hFile, SFileInfoNameHash1, &dwHash1, sizeof(dwHash1), &cbHash))
|
|
2535
|
+
{
|
|
2536
|
+
assert(cbHash == sizeof(DWORD));
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
if(SFileGetFileInfo(hFile, SFileInfoNameHash2, &dwHash2, sizeof(dwHash2), &cbHash))
|
|
2540
|
+
{
|
|
2541
|
+
assert(cbHash == sizeof(DWORD));
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
if(dwHash1 != pItem->dwHash1 || dwHash2 != pItem->dwHash2)
|
|
2545
|
+
{
|
|
2546
|
+
dwErrCode = Logger.PrintError("Name hash values mismatch on %s", pItem->szFileName);
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
SFileCloseFile(hFile);
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
return dwErrCode;
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
static DWORD TestOpenArchive_ExtraType(TLogHelper & Logger, HANDLE hMpq, DWORD dwSearchFlags, const void * pExtra)
|
|
2556
|
+
{
|
|
2557
|
+
switch(GetExtraType(pExtra))
|
|
2558
|
+
{
|
|
2559
|
+
case ListFile:
|
|
2560
|
+
return TestOpenArchive_Extra_ListFile(Logger, hMpq, (PTEST_EXTRA_ONEFILE)(pExtra));
|
|
2561
|
+
|
|
2562
|
+
case Utf8File:
|
|
2563
|
+
return TestOpenArchive_Extra_Utf8File(Logger, hMpq, (PTEST_EXTRA_UTF8)(pExtra));
|
|
2564
|
+
|
|
2565
|
+
case TwoFiles:
|
|
2566
|
+
return TestOpenArchive_Extra_TwoFiles(Logger, hMpq, dwSearchFlags, (PTEST_EXTRA_TWOFILES)(pExtra));
|
|
2567
|
+
|
|
2568
|
+
case PatchList:
|
|
2569
|
+
return TestOpenArchive_Extra_Patches(Logger, hMpq, (PTEST_EXTRA_PATCHES)(pExtra));
|
|
2570
|
+
|
|
2571
|
+
case HashValues:
|
|
2572
|
+
return TestOpenArchive_Extra_HashValues(Logger, hMpq, (PTEST_EXTRA_HASHVALS)(pExtra));
|
|
2573
|
+
|
|
2574
|
+
default:
|
|
2575
|
+
return ERROR_SUCCESS;
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
static DWORD TestOpenArchive_ModifyArchive(TLogHelper & Logger, HANDLE hMpq, DWORD dwFlags)
|
|
2580
|
+
{
|
|
2581
|
+
DWORD dwExpectedError;
|
|
2582
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2583
|
+
TCHAR szFullPath[MAX_PATH];
|
|
2584
|
+
|
|
2585
|
+
// Modify the archive, if required
|
|
2586
|
+
if(dwFlags & TFLG_MODIFY)
|
|
2587
|
+
{
|
|
2588
|
+
Logger.PrintProgress("Modifying archive ...");
|
|
2589
|
+
|
|
2590
|
+
if(dwFlags & TFLG_BIGFILE)
|
|
2591
|
+
{
|
|
2592
|
+
dwExpectedError = (dwFlags & TFLG_WILL_FAIL) ? ERROR_DISK_FULL : ERROR_SUCCESS;
|
|
2593
|
+
|
|
2594
|
+
CreateFullPathName(szFullPath, _countof(szFullPath), szDataFileDir, _T("new-file-big.mp4"));
|
|
2595
|
+
dwErrCode = AddLocalFileToMpq(&Logger, hMpq, "added-extra-file.mp4", szFullPath);
|
|
2596
|
+
dwErrCode = (dwErrCode == dwExpectedError) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT;
|
|
2597
|
+
}
|
|
2598
|
+
else
|
|
2599
|
+
{
|
|
2600
|
+
dwExpectedError = (dwFlags & TFLG_READ_ONLY) ? ERROR_ACCESS_DENIED : ERROR_SUCCESS;
|
|
2601
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, "AddedFile01.txt", "This is a file added to signed MPQ", MPQ_FILE_COMPRESS, 0, dwExpectedError);
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
return dwErrCode;
|
|
2605
|
+
}
|
|
2606
|
+
|
|
2607
|
+
static DWORD TestOpenArchive_SignArchive(TLogHelper & Logger, HANDLE hMpq, DWORD dwDoItIfNonZero)
|
|
2608
|
+
{
|
|
2609
|
+
// Sign the MPQ archive, if required
|
|
2610
|
+
if(dwDoItIfNonZero)
|
|
2611
|
+
{
|
|
2612
|
+
Logger.PrintProgress("Signing the MPQ ...");
|
|
2613
|
+
if(!SFileSignArchive(hMpq, SIGNATURE_TYPE_WEAK))
|
|
2614
|
+
{
|
|
2615
|
+
Logger.PrintMessage("Failed to create archive signature");
|
|
2616
|
+
return ERROR_FILE_CORRUPT;
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
return ERROR_SUCCESS;
|
|
2620
|
+
}
|
|
2621
|
+
|
|
2622
|
+
static DWORD TestOpenArchive_GetFileInfo(TLogHelper & Logger, HANDLE hMpq, DWORD dwFlags)
|
|
2623
|
+
{
|
|
2624
|
+
if(dwFlags & TFLG_GET_FILE_INFO)
|
|
2625
|
+
{
|
|
2626
|
+
TMPQHeader Header = {0};
|
|
2627
|
+
HANDLE hFile = NULL;
|
|
2628
|
+
DWORD dwExpectedError;
|
|
2629
|
+
DWORD cbLength;
|
|
2630
|
+
BYTE DataBuff[0x400];
|
|
2631
|
+
|
|
2632
|
+
// Retrieve the version of the MPQ
|
|
2633
|
+
Logger.PrintProgress("Checking SFileGetFileInfo");
|
|
2634
|
+
SFileGetFileInfo(hMpq, SFileMpqHeader, &Header, sizeof(TMPQHeader), NULL);
|
|
2635
|
+
|
|
2636
|
+
// Test on invalid archive/file handle
|
|
2637
|
+
TestGetFileInfo(&Logger, NULL, SFileMpqBetHeader, NULL, 0, NULL, false, ERROR_INVALID_HANDLE);
|
|
2638
|
+
TestGetFileInfo(&Logger, NULL, SFileInfoInvalid, NULL, 0, NULL, false, ERROR_INVALID_HANDLE);
|
|
2639
|
+
TestGetFileInfo(&Logger, NULL, SFileInfoNameHash1, NULL, 0, NULL, false, ERROR_INVALID_HANDLE);
|
|
2640
|
+
|
|
2641
|
+
// Valid handle but all parameters NULL
|
|
2642
|
+
dwExpectedError = (Header.wFormatVersion == MPQ_FORMAT_VERSION_4) ? ERROR_INSUFFICIENT_BUFFER : ERROR_FILE_NOT_FOUND;
|
|
2643
|
+
TestGetFileInfo(&Logger, hMpq, SFileMpqBetHeader, NULL, 0, NULL, false, dwExpectedError);
|
|
2644
|
+
TestGetFileInfo(&Logger, hMpq, SFileMpqBetHeader, NULL, 0, &cbLength, false, dwExpectedError);
|
|
2645
|
+
|
|
2646
|
+
// When we call SFileInfo with buffer = NULL and nonzero buffer size, it is ignored
|
|
2647
|
+
TestGetFileInfo(&Logger, hMpq, SFileMpqBetHeader, NULL, 3, &cbLength, false, dwExpectedError);
|
|
2648
|
+
|
|
2649
|
+
// When we call SFileInfo with buffer != NULL and nonzero buffer size, it should return error
|
|
2650
|
+
TestGetFileInfo(&Logger, hMpq, SFileMpqBetHeader, DataBuff, 3, &cbLength, false, dwExpectedError);
|
|
2651
|
+
|
|
2652
|
+
// Request for bet table header should also succeed if we want header only
|
|
2653
|
+
dwExpectedError = (Header.wFormatVersion == MPQ_FORMAT_VERSION_4) ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND;
|
|
2654
|
+
TestGetFileInfo(&Logger, hMpq, SFileMpqBetHeader, DataBuff, sizeof(TMPQBetHeader), &cbLength, (dwExpectedError == ERROR_SUCCESS), dwExpectedError);
|
|
2655
|
+
TestGetFileInfo(&Logger, hMpq, SFileMpqBetHeader, DataBuff, sizeof(DataBuff), &cbLength, (dwExpectedError == ERROR_SUCCESS), dwExpectedError);
|
|
2656
|
+
|
|
2657
|
+
// Try to retrieve strong signature from the MPQ
|
|
2658
|
+
dwExpectedError = (Header.wFormatVersion == MPQ_FORMAT_VERSION_4) ? ERROR_FILE_NOT_FOUND : ERROR_INSUFFICIENT_BUFFER;
|
|
2659
|
+
TestGetFileInfo(&Logger, hMpq, SFileMpqStrongSignature, NULL, 0, NULL, false, dwExpectedError);
|
|
2660
|
+
TestGetFileInfo(&Logger, hMpq, SFileMpqStrongSignature, NULL, 0, &cbLength, false, dwExpectedError);
|
|
2661
|
+
if(Header.wFormatVersion == MPQ_FORMAT_VERSION_1)
|
|
2662
|
+
assert(cbLength == MPQ_STRONG_SIGNATURE_SIZE + 4);
|
|
2663
|
+
|
|
2664
|
+
// Retrieve the signature
|
|
2665
|
+
dwExpectedError = (Header.wFormatVersion == MPQ_FORMAT_VERSION_4) ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS;
|
|
2666
|
+
TestGetFileInfo(&Logger, hMpq, SFileMpqStrongSignature, DataBuff, sizeof(DataBuff), &cbLength, (dwExpectedError == ERROR_SUCCESS), dwExpectedError);
|
|
2667
|
+
if(Header.wFormatVersion == MPQ_FORMAT_VERSION_1)
|
|
2668
|
+
assert(memcmp(DataBuff, "NGIS", 4) == 0);
|
|
2669
|
+
|
|
2670
|
+
// Check SFileGetFileInfo on a listfile
|
|
2671
|
+
if(SFileOpenFileEx(hMpq, LISTFILE_NAME, 0, &hFile))
|
|
2672
|
+
{
|
|
2673
|
+
TestGetFileInfo(&Logger, hMpq, SFileInfoFileTime, DataBuff, sizeof(DataBuff), &cbLength, false, ERROR_INVALID_HANDLE);
|
|
2674
|
+
TestGetFileInfo(&Logger, hFile, SFileInfoFileTime, DataBuff, sizeof(DataBuff), &cbLength, true, ERROR_SUCCESS);
|
|
2675
|
+
SFileCloseFile(hFile);
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
return ERROR_SUCCESS;
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
static DWORD TestOpenArchive(
|
|
2682
|
+
LPCTSTR szMpqName1, // (UTF-8) Name of the MPQ
|
|
2683
|
+
LPCTSTR szMpqName2, // (UTF-8) Name of the MPQ (original name or name of a copy)
|
|
2684
|
+
LPCSTR szExpectedHash, // Expected name+data hash
|
|
2685
|
+
DWORD dwFlags, // Test flags. Lower bits contains the number of files
|
|
2686
|
+
const void * pExtra) // Extra parameter
|
|
2687
|
+
{
|
|
2688
|
+
TLogHelper Logger("TestReadingMpq", szMpqName1);
|
|
2689
|
+
HANDLE hMpq = NULL;
|
|
2690
|
+
DWORD dwExpectedFileCount = 0;
|
|
2691
|
+
DWORD dwSearchFlags = 0;
|
|
2692
|
+
DWORD dwOpenFlags = 0;
|
|
2693
|
+
DWORD dwMpqFlags = 0;
|
|
2694
|
+
DWORD dwErrCode;
|
|
2695
|
+
TCHAR szMpqNameBuff[MAX_PATH];
|
|
2696
|
+
|
|
2697
|
+
// Propagate the open MPQ flags from the input
|
|
2698
|
+
dwOpenFlags |= (dwFlags & TFLG_WILL_FAIL) ? MPQ_OPEN_DONT_REPORT_FAILURE : 0;
|
|
2699
|
+
dwOpenFlags |= (dwFlags & TFLG_READ_ONLY) ? STREAM_FLAG_READ_ONLY : 0;
|
|
2700
|
+
|
|
2701
|
+
// Shall we switch the name of the MPQ?
|
|
2702
|
+
szMpqName1 = SwapMpqName(szMpqNameBuff, _countof(szMpqNameBuff), szMpqName1, (PTEST_EXTRA_UTF8)(pExtra));
|
|
2703
|
+
|
|
2704
|
+
// If the file is a partial MPQ, don't load all files
|
|
2705
|
+
if(_tcsstr(szMpqName1, _T(".MPQ.part")) == NULL)
|
|
2706
|
+
dwSearchFlags |= SEARCH_FLAG_LOAD_FILES;
|
|
2707
|
+
|
|
2708
|
+
// If we shall hash the files, do it
|
|
2709
|
+
if(IS_VALID_STRING(szExpectedHash))
|
|
2710
|
+
{
|
|
2711
|
+
dwExpectedFileCount = (dwFlags & TFLG_VALUE_MASK);
|
|
2712
|
+
dwSearchFlags |= SEARCH_FLAG_HASH_FILES;
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2715
|
+
// Copy the archive so we won't fuck up the original one
|
|
2716
|
+
dwErrCode = OpenExistingArchiveWithCopy(&Logger, szMpqName1, szMpqName2, &hMpq, dwOpenFlags);
|
|
2717
|
+
while(dwErrCode == ERROR_SUCCESS)
|
|
2718
|
+
{
|
|
2719
|
+
// Check for malformed MPQs
|
|
2720
|
+
SFileGetFileInfo(hMpq, SFileMpqFlags, &dwMpqFlags, sizeof(dwMpqFlags), NULL);
|
|
2721
|
+
dwSearchFlags |= (dwMpqFlags & MPQ_FLAG_MALFORMED) ? SEARCH_FLAG_IGNORE_ERRORS : 0;
|
|
2722
|
+
dwSearchFlags |= (GetExtraType(pExtra) == PatchList) ? SEARCH_FLAG_IGNORE_ERRORS : 0;
|
|
2723
|
+
|
|
2724
|
+
// Verify signature before any changes
|
|
2725
|
+
if((dwErrCode = TestOpenArchive_VerifySignature(Logger, hMpq, (dwFlags & TFLG_SIGCHECK_BEFORE))) != ERROR_SUCCESS)
|
|
2726
|
+
break;
|
|
2727
|
+
|
|
2728
|
+
// Perform extra action, dependent on the data passed
|
|
2729
|
+
if((dwErrCode = TestOpenArchive_ExtraType(Logger, hMpq, dwSearchFlags, pExtra)) != ERROR_SUCCESS)
|
|
2730
|
+
break;
|
|
2731
|
+
|
|
2732
|
+
// Modify the archive, if required
|
|
2733
|
+
if((dwErrCode = TestOpenArchive_ModifyArchive(Logger, hMpq, dwFlags)) != ERROR_SUCCESS)
|
|
2734
|
+
break;
|
|
2735
|
+
|
|
2736
|
+
// Sign the archive, if needed
|
|
2737
|
+
if((dwErrCode = TestOpenArchive_SignArchive(Logger, hMpq, (dwFlags & TFLG_SIGN_ARCHIVE))) != ERROR_SUCCESS)
|
|
2738
|
+
break;
|
|
2739
|
+
|
|
2740
|
+
// Test the SFileGetFileInfo, if required
|
|
2741
|
+
if((dwErrCode = TestOpenArchive_GetFileInfo(Logger, hMpq, dwFlags)) != ERROR_SUCCESS)
|
|
2742
|
+
break;
|
|
2743
|
+
|
|
2744
|
+
// Verify signature after any changes
|
|
2745
|
+
if((dwErrCode = TestOpenArchive_VerifySignature(Logger, hMpq, (dwFlags & TFLG_SIGCHECK_AFTER))) != ERROR_SUCCESS)
|
|
2746
|
+
break;
|
|
2747
|
+
|
|
2748
|
+
// Attempt to open the (listfile), (attributes), (signature)
|
|
2749
|
+
if((TestArchive_LoadFiles(&Logger, hMpq, (dwMpqFlags & MPQ_FLAG_MALFORMED), LISTFILE_NAME, ATTRIBUTES_NAME, SIGNATURE_NAME, NULL)) != ERROR_SUCCESS)
|
|
2750
|
+
break;
|
|
2751
|
+
|
|
2752
|
+
// If required, we search the archive and compare file cound and name hash
|
|
2753
|
+
if((dwErrCode = VerifyDataChecksum(Logger, hMpq, dwSearchFlags, szExpectedHash, dwExpectedFileCount)) != ERROR_SUCCESS)
|
|
2754
|
+
break;
|
|
2755
|
+
|
|
2756
|
+
break;
|
|
2757
|
+
}
|
|
2758
|
+
|
|
2759
|
+
// Reset error code, if the failure is expected
|
|
2760
|
+
if((dwErrCode != ERROR_SUCCESS || hMpq == NULL) && (dwFlags & TFLG_WILL_FAIL))
|
|
2761
|
+
SetLastError(dwErrCode = ERROR_SUCCESS);
|
|
2762
|
+
|
|
2763
|
+
// Cleanup and exit
|
|
2764
|
+
if(hMpq != NULL)
|
|
2765
|
+
SFileCloseArchive(hMpq);
|
|
2766
|
+
return Logger.PrintVerdict(dwErrCode);
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
static DWORD TestOpenArchive(const TEST_INFO1 & TestInfo)
|
|
2770
|
+
{
|
|
2771
|
+
return TestOpenArchive(TestInfo.szName1, // Name of the MPQ
|
|
2772
|
+
TestInfo.szName2, // Name of the listfile or NULL
|
|
2773
|
+
TestInfo.szDataHash, // Compound name+data hash
|
|
2774
|
+
TestInfo.dwFlags, // Test flags
|
|
2775
|
+
TestInfo.pExtra); // Extra parameter
|
|
2776
|
+
}
|
|
2777
|
+
|
|
2778
|
+
//-----------------------------------------------------------------------------
|
|
2779
|
+
// Reopening archives
|
|
2780
|
+
|
|
2781
|
+
static void WINAPI CompactCallback(void * pvUserData, DWORD dwWork, ULONGLONG BytesDone, ULONGLONG TotalBytes)
|
|
2782
|
+
{
|
|
2783
|
+
TLogHelper * pLogger = (TLogHelper *)pvUserData;
|
|
2784
|
+
LPCSTR szWork = NULL;
|
|
2785
|
+
|
|
2786
|
+
switch(dwWork)
|
|
2787
|
+
{
|
|
2788
|
+
case CCB_CHECKING_FILES:
|
|
2789
|
+
szWork = "Checking files in archive";
|
|
2790
|
+
break;
|
|
2791
|
+
|
|
2792
|
+
case CCB_CHECKING_HASH_TABLE:
|
|
2793
|
+
szWork = "Checking hash table";
|
|
2794
|
+
break;
|
|
2795
|
+
|
|
2796
|
+
case CCB_COPYING_NON_MPQ_DATA:
|
|
2797
|
+
szWork = "Copying non-MPQ data";
|
|
2798
|
+
break;
|
|
2799
|
+
|
|
2800
|
+
case CCB_COMPACTING_FILES:
|
|
2801
|
+
szWork = "Compacting files";
|
|
2802
|
+
break;
|
|
2803
|
+
|
|
2804
|
+
case CCB_CLOSING_ARCHIVE:
|
|
2805
|
+
szWork = "Closing archive";
|
|
2806
|
+
break;
|
|
2807
|
+
}
|
|
2808
|
+
|
|
2809
|
+
if(szWork != NULL)
|
|
2810
|
+
{
|
|
2811
|
+
if(pLogger != NULL)
|
|
2812
|
+
pLogger->PrintProgress("%s " fmt_X_of_Y_a " ...", szWork, BytesDone, TotalBytes);
|
|
2813
|
+
else
|
|
2814
|
+
printf("%s " fmt_X_of_Y_a " ... \r", szWork, BytesDone, TotalBytes);
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2818
|
+
static DWORD TestReopenArchive_CompactArchive(TLogHelper & Logger, HANDLE hMpq, DWORD dwFlags)
|
|
2819
|
+
{
|
|
2820
|
+
if(dwFlags & TFLG_COMPACT)
|
|
2821
|
+
{
|
|
2822
|
+
// Set the compact callback
|
|
2823
|
+
Logger.PrintProgress("Compacting archive ...");
|
|
2824
|
+
if(!SFileSetCompactCallback(hMpq, CompactCallback, &Logger))
|
|
2825
|
+
return Logger.PrintError("Failed to set the compact callback");
|
|
2826
|
+
|
|
2827
|
+
// Compact the archive
|
|
2828
|
+
if(!SFileCompactArchive(hMpq, NULL, false))
|
|
2829
|
+
return Logger.PrintError("Failed to compact archive");
|
|
2830
|
+
}
|
|
2831
|
+
return ERROR_SUCCESS;
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
static DWORD TestReopenArchive(
|
|
2835
|
+
LPCTSTR szMpqName1, // Name of the MPQ
|
|
2836
|
+
LPCSTR szExpectedHash, // Expected name+data hash
|
|
2837
|
+
DWORD dwFlags) // Test flags. Lower bits contains the number of files
|
|
2838
|
+
{
|
|
2839
|
+
TLogHelper Logger("Test_ReopenMpq", szMpqName1);
|
|
2840
|
+
ULONGLONG PreMpqDataSize = (dwFlags & TFLG_ADD_USER_DATA) ? 0x400 : 0;
|
|
2841
|
+
ULONGLONG UserDataSize = (dwFlags & TFLG_ADD_USER_DATA) ? 0x531 : 0;
|
|
2842
|
+
LPCTSTR szCopyName = _T("StormLibTest_Reopened.mpq");
|
|
2843
|
+
HANDLE hMpq;
|
|
2844
|
+
DWORD dwExpectedFileCount = 0;
|
|
2845
|
+
DWORD dwSearchFlags = SEARCH_FLAG_LOAD_FILES;
|
|
2846
|
+
TCHAR szFullPath[MAX_PATH];
|
|
2847
|
+
DWORD dwErrCode;
|
|
2848
|
+
|
|
2849
|
+
// If we shall hash the files, do it
|
|
2850
|
+
if(IS_VALID_STRING(szExpectedHash))
|
|
2851
|
+
{
|
|
2852
|
+
dwExpectedFileCount = (dwFlags & TFLG_VALUE_MASK);
|
|
2853
|
+
dwSearchFlags |= SEARCH_FLAG_HASH_FILES;
|
|
2854
|
+
}
|
|
2855
|
+
|
|
2856
|
+
// Create copy of the archive, with interleaving some user data
|
|
2857
|
+
dwErrCode = CreateFileCopy(&Logger, szMpqName1, szCopyName, szFullPath, _countof(szFullPath), PreMpqDataSize, UserDataSize);
|
|
2858
|
+
|
|
2859
|
+
// Open the archive and read the hash of the files
|
|
2860
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2861
|
+
{
|
|
2862
|
+
if((dwErrCode = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq)) == ERROR_SUCCESS)
|
|
2863
|
+
{
|
|
2864
|
+
// Verify presence of (listfile) and (attributes)
|
|
2865
|
+
CheckIfFileIsPresent(&Logger, hMpq, LISTFILE_NAME, (dwFlags & TFLG_HAS_LISTFILE));
|
|
2866
|
+
CheckIfFileIsPresent(&Logger, hMpq, ATTRIBUTES_NAME, (dwFlags & TFLG_HAS_ATTRIBUTES));
|
|
2867
|
+
|
|
2868
|
+
// If required, we search the archive and compare file cound and name hash
|
|
2869
|
+
dwErrCode = VerifyDataChecksum(Logger, hMpq, dwSearchFlags, szExpectedHash, dwExpectedFileCount);
|
|
2870
|
+
SFileCloseArchive(hMpq);
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
|
|
2874
|
+
// Try to modify and/or compact the MPQ
|
|
2875
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2876
|
+
{
|
|
2877
|
+
// Open the archive again
|
|
2878
|
+
if((dwErrCode = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq)) == ERROR_SUCCESS)
|
|
2879
|
+
{
|
|
2880
|
+
// Modify the archive, if required
|
|
2881
|
+
if((dwErrCode = TestOpenArchive_ModifyArchive(Logger, hMpq, dwFlags)) == ERROR_SUCCESS)
|
|
2882
|
+
{
|
|
2883
|
+
dwErrCode = TestReopenArchive_CompactArchive(Logger, hMpq, dwFlags);
|
|
2884
|
+
}
|
|
2885
|
+
SFileCloseArchive(hMpq);
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2888
|
+
|
|
2889
|
+
// Open the archive and load some files
|
|
2890
|
+
if((dwErrCode == ERROR_SUCCESS) && STORMLIB_TEST_FLAGS(dwFlags, TFLG_COMPACT | TFLG_MODIFY | TFLG_BIGFILE, TFLG_COMPACT))
|
|
2891
|
+
{
|
|
2892
|
+
// Open the archive
|
|
2893
|
+
if((dwErrCode = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq)) == ERROR_SUCCESS)
|
|
2894
|
+
{
|
|
2895
|
+
// Verify presence of (listfile) and (attributes)
|
|
2896
|
+
CheckIfFileIsPresent(&Logger, hMpq, LISTFILE_NAME, (dwFlags & TFLG_HAS_LISTFILE));
|
|
2897
|
+
CheckIfFileIsPresent(&Logger, hMpq, ATTRIBUTES_NAME, (dwFlags & TFLG_HAS_ATTRIBUTES));
|
|
2898
|
+
|
|
2899
|
+
// Search the archive and load every file
|
|
2900
|
+
dwErrCode = VerifyDataChecksum(Logger, hMpq, dwSearchFlags, szExpectedHash, dwExpectedFileCount);
|
|
2901
|
+
}
|
|
2902
|
+
SFileCloseArchive(hMpq);
|
|
2903
|
+
}
|
|
2904
|
+
return dwErrCode;
|
|
2905
|
+
}
|
|
2906
|
+
|
|
2907
|
+
static DWORD TestOpenArchive_SignatureTest(LPCTSTR szPlainName, LPCTSTR szOriginalName, DWORD dwFlags)
|
|
2908
|
+
{
|
|
2909
|
+
TLogHelper Logger("Test_Signature", szPlainName);
|
|
2910
|
+
HANDLE hMpq;
|
|
2911
|
+
DWORD dwCreateFlags = MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES | MPQ_FORMAT_VERSION_1;
|
|
2912
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
2913
|
+
|
|
2914
|
+
// Create a new archive or copy existing
|
|
2915
|
+
if(dwFlags & SFLAG_CREATE_ARCHIVE)
|
|
2916
|
+
{
|
|
2917
|
+
dwCreateFlags |= (dwFlags & SFLAG_SIGN_AT_CREATE) ? MPQ_CREATE_SIGNATURE : 0;
|
|
2918
|
+
dwErrCode = CreateNewArchive_V2(&Logger, szPlainName, dwCreateFlags, 4000, &hMpq);
|
|
2919
|
+
}
|
|
2920
|
+
else
|
|
2921
|
+
{
|
|
2922
|
+
szOriginalName = (szOriginalName) ? szOriginalName : szPlainName;
|
|
2923
|
+
dwErrCode = OpenExistingArchiveWithCopy(&Logger, szPlainName, szOriginalName, &hMpq);
|
|
2924
|
+
}
|
|
2925
|
+
|
|
2926
|
+
// Continue with archive signature tests
|
|
2927
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2928
|
+
{
|
|
2929
|
+
// Shall we check the signatures before modifications?
|
|
2930
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2931
|
+
{
|
|
2932
|
+
dwErrCode = TestOpenArchive_VerifySignature(Logger, hMpq, (dwFlags & SFLAG_VERIFY_BEFORE));
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2935
|
+
// Shall we modify the archive?
|
|
2936
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2937
|
+
{
|
|
2938
|
+
dwErrCode = TestOpenArchive_ModifyArchive(Logger, hMpq, (dwFlags & SFLAG_MODIFY_ARCHIVE));
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
// Shall we sign the archive?
|
|
2942
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2943
|
+
{
|
|
2944
|
+
dwErrCode = TestOpenArchive_SignArchive(Logger, hMpq, (dwFlags & SFLAG_SIGN_ARCHIVE));
|
|
2945
|
+
}
|
|
2946
|
+
|
|
2947
|
+
// Shall we check the signatures after modifications?
|
|
2948
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2949
|
+
{
|
|
2950
|
+
dwErrCode = TestOpenArchive_VerifySignature(Logger, hMpq, (dwFlags & SFLAG_VERIFY_AFTER));
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2953
|
+
SFileCloseArchive(hMpq);
|
|
2954
|
+
}
|
|
2955
|
+
return dwErrCode;
|
|
2956
|
+
}
|
|
2957
|
+
|
|
2958
|
+
static DWORD TestCreateArchive(LPCTSTR szPlainName, LPCSTR szFileName, DWORD dwFlags)
|
|
2959
|
+
{
|
|
2960
|
+
TLogHelper Logger("CreateNewMpq", szPlainName);
|
|
2961
|
+
HANDLE hMpq = NULL;
|
|
2962
|
+
DWORD dwMaxFileCount = dwFlags & 0x0000FFFF;
|
|
2963
|
+
DWORD dwCreateFlags = 0;
|
|
2964
|
+
DWORD dwFileCount = 0;
|
|
2965
|
+
DWORD dwErrCode;
|
|
2966
|
+
|
|
2967
|
+
// Fixup the MPQ format
|
|
2968
|
+
dwCreateFlags |= (dwFlags & CFLG_EMPTY) ? 0 : MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES;
|
|
2969
|
+
dwCreateFlags |= (dwFlags & CFLG_V2) ? MPQ_CREATE_ARCHIVE_V2 : 0;
|
|
2970
|
+
dwCreateFlags |= (dwFlags & CFLG_V4) ? MPQ_CREATE_ARCHIVE_V4 : 0;
|
|
2971
|
+
|
|
2972
|
+
// Create the full path name
|
|
2973
|
+
dwErrCode = CreateNewArchive(&Logger, szPlainName, dwCreateFlags, dwMaxFileCount, &hMpq);
|
|
2974
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
2975
|
+
{
|
|
2976
|
+
// Add non-standard names, if needed
|
|
2977
|
+
if(dwFlags & CFLG_NONSTD_NAMES)
|
|
2978
|
+
{
|
|
2979
|
+
// Add few files and close the archive
|
|
2980
|
+
AddFileToMpq(&Logger, hMpq, "AddedFile000.txt", "This is the file data 000.", MPQ_FILE_COMPRESS);
|
|
2981
|
+
AddFileToMpq(&Logger, hMpq, "\\/\\/\\/\\AddedFile001.txt", "This is the file data 001.", MPQ_FILE_COMPRESS);
|
|
2982
|
+
AddFileToMpq(&Logger, hMpq, "\\\\\\\\\\\\\\\\", "This is the file data 002.", MPQ_FILE_COMPRESS);
|
|
2983
|
+
AddFileToMpq(&Logger, hMpq, "////////////////", "This is the file data 003.", MPQ_FILE_COMPRESS);
|
|
2984
|
+
AddFileToMpq(&Logger, hMpq, "//\\//\\//\\//\\", "This is the file data 004.", MPQ_FILE_COMPRESS);
|
|
2985
|
+
AddFileToMpq(&Logger, hMpq, "................", "This is the file data 005.", MPQ_FILE_COMPRESS);
|
|
2986
|
+
AddFileToMpq(&Logger, hMpq, "//****//****//****//****.***", "This is the file data 006.", MPQ_FILE_COMPRESS);
|
|
2987
|
+
AddFileToMpq(&Logger, hMpq, "//*??*//*??*//*??*//?**?.?*?", "This is the file data 007.", MPQ_FILE_COMPRESS);
|
|
2988
|
+
AddFileToMpq(&Logger, hMpq, "\\/\\/File.txt", "This is the file data 008.", MPQ_FILE_COMPRESS);
|
|
2989
|
+
AddFileToMpq(&Logger, hMpq, "\\/\\/File.txt..", "This is the file data 009.", MPQ_FILE_COMPRESS);
|
|
2990
|
+
AddFileToMpq(&Logger, hMpq, "Dir1\\Dir2\\Dir3\\File.txt..", "This is the file data 010.", MPQ_FILE_COMPRESS);
|
|
2991
|
+
AddFileToMpq(&Logger, hMpq, "\\Dir1\\Dir2\\Dir3\\File.txt..", "This is the file data 011.", MPQ_FILE_COMPRESS);
|
|
2992
|
+
AddFileToMpq(&Logger, hMpq, "\\\\Dir1\\\\Dir2\\\\Dir3\\\\File.txt..", "This is the file data 012.", MPQ_FILE_COMPRESS);
|
|
2993
|
+
AddFileToMpq(&Logger, hMpq, "/Dir1/Dir2/Dir3/File.txt..", "This is the file data 013.", MPQ_FILE_COMPRESS);
|
|
2994
|
+
AddFileToMpq(&Logger, hMpq, "////Dir1////Dir2////Dir3////File.txt..", "This is the file data 014.", MPQ_FILE_COMPRESS);
|
|
2995
|
+
AddFileToMpq(&Logger, hMpq, "\\//\\Dir1\\//\\Dir2\\//\\File.txt..", "This is the file data 015.", MPQ_FILE_COMPRESS);
|
|
2996
|
+
AddFileToMpq(&Logger, hMpq, "\x10\x11\x12\x13\\\x14\x15\x16\x17\\\x18\x19\x1a\x1b\\\x1c\x1D\x1E\x1F.txt", "This is the file data 016.", MPQ_FILE_COMPRESS);
|
|
2997
|
+
AddFileToMpq(&Logger, hMpq, "\x09\x20\x09\x20\\\x20\x09\x20\x09\\\x09\x20\x09\x20\\\x20\x09\x20\x09.txt", "This is the file data 017.", MPQ_FILE_COMPRESS);
|
|
2998
|
+
AddFileToMpq(&Logger, hMpq, "\x80\x91\xA2\xB3\\\xC4\xD5\xE6\xF7\\\x80\x91\xA2\xB3.txt", "This is the file data 018.", MPQ_FILE_COMPRESS);
|
|
2999
|
+
AddFileToMpq(&Logger, hMpq, "Dir1\x20\x09\x20\\Dir2\x20\x09\x20\\File.txt\x09\x09\x20\x2e", "This is the file data 019.", MPQ_FILE_COMPRESS);
|
|
3000
|
+
AddFileToMpq(&Logger, hMpq, "Dir1\x20\x09\x20\\Dir2\x20\x09\x20\\\x09\x20\x2e\x09\x20\x2e", "This is the file data 020.", MPQ_FILE_COMPRESS);
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
// Like MPQEditor: Flush archive, add one file, flush again
|
|
3004
|
+
if(dwFlags & CFLG_MPQEDITOR)
|
|
3005
|
+
{
|
|
3006
|
+
SFileFlushArchive(hMpq);
|
|
3007
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, szFileName, "This is the file data.", MPQ_FILE_COMPRESS);
|
|
3008
|
+
SFileFlushArchive(hMpq);
|
|
3009
|
+
}
|
|
3010
|
+
|
|
3011
|
+
// Search the archive
|
|
3012
|
+
SearchArchive(&Logger, hMpq);
|
|
3013
|
+
SFileCloseArchive(hMpq);
|
|
3014
|
+
}
|
|
3015
|
+
|
|
3016
|
+
// Reopen the empty MPQ
|
|
3017
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3018
|
+
{
|
|
3019
|
+
dwErrCode = OpenExistingArchiveWithCopy(&Logger, NULL, szPlainName, &hMpq);
|
|
3020
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3021
|
+
{
|
|
3022
|
+
// Retrieve the number of files
|
|
3023
|
+
SFileGetFileInfo(hMpq, SFileMpqNumberOfFiles, &dwFileCount, sizeof(dwFileCount), NULL);
|
|
3024
|
+
|
|
3025
|
+
// Special check for empty MPQs
|
|
3026
|
+
if(dwFlags & CFLG_EMPTY)
|
|
3027
|
+
{
|
|
3028
|
+
if(dwFileCount != 0)
|
|
3029
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
3030
|
+
CheckIfFileIsPresent(&Logger, hMpq, "File00000000.xxx", false);
|
|
3031
|
+
CheckIfFileIsPresent(&Logger, hMpq, LISTFILE_NAME, false);
|
|
3032
|
+
SearchArchive(&Logger, hMpq);
|
|
3033
|
+
}
|
|
3034
|
+
else
|
|
3035
|
+
{
|
|
3036
|
+
if(dwFileCount == 0)
|
|
3037
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
3038
|
+
}
|
|
3039
|
+
|
|
3040
|
+
// Close the MPQ
|
|
3041
|
+
SFileCloseArchive(hMpq);
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
|
|
3045
|
+
return dwErrCode;
|
|
3046
|
+
}
|
|
3047
|
+
|
|
3048
|
+
static DWORD TestCreateArchive(const TEST_INFO2 & TestInfo)
|
|
3049
|
+
{
|
|
3050
|
+
TCHAR szPlainNameT[MAX_PATH];
|
|
3051
|
+
|
|
3052
|
+
// Always prefix the archive name with "StormLibTest_"
|
|
3053
|
+
StringCopy(szPlainNameT, _countof(szPlainNameT), "StormLibTest_");
|
|
3054
|
+
StringCat(szPlainNameT, _countof(szPlainNameT), TestInfo.szName1);
|
|
3055
|
+
|
|
3056
|
+
// Perform creation of the archive
|
|
3057
|
+
return TestCreateArchive(szPlainNameT, TestInfo.szName2, TestInfo.dwFlags);
|
|
3058
|
+
}
|
|
3059
|
+
|
|
3060
|
+
static DWORD TestCreateArchive_TestGaps(LPCTSTR szPlainName)
|
|
3061
|
+
{
|
|
3062
|
+
TLogHelper Logger("TestCreateGaps", szPlainName);
|
|
3063
|
+
ULONGLONG ByteOffset1 = 0xFFFFFFFF;
|
|
3064
|
+
ULONGLONG ByteOffset2 = 0xEEEEEEEE;
|
|
3065
|
+
HANDLE hMpq = NULL;
|
|
3066
|
+
HANDLE hFile = NULL;
|
|
3067
|
+
TCHAR szFullPath[MAX_PATH];
|
|
3068
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
3069
|
+
|
|
3070
|
+
// Create new MPQ
|
|
3071
|
+
dwErrCode = CreateNewArchive_V2(&Logger, szPlainName, MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES | MPQ_FORMAT_VERSION_4, 4000, &hMpq);
|
|
3072
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3073
|
+
{
|
|
3074
|
+
// Add one file and flush the archive
|
|
3075
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, "AddedFile01.txt", "This is the file data.", MPQ_FILE_COMPRESS);
|
|
3076
|
+
SFileCloseArchive(hMpq);
|
|
3077
|
+
hMpq = NULL;
|
|
3078
|
+
}
|
|
3079
|
+
|
|
3080
|
+
// Reopen the MPQ and add another file.
|
|
3081
|
+
// The new file must be added to the position of the (listfile)
|
|
3082
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3083
|
+
{
|
|
3084
|
+
CreateFullPathName(szFullPath, _countof(szFullPath), NULL, szPlainName);
|
|
3085
|
+
dwErrCode = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq);
|
|
3086
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3087
|
+
{
|
|
3088
|
+
// Retrieve the position of the (listfile)
|
|
3089
|
+
if(SFileOpenFileEx(hMpq, LISTFILE_NAME, 0, &hFile))
|
|
3090
|
+
{
|
|
3091
|
+
SFileGetFileInfo(hFile, SFileInfoByteOffset, &ByteOffset1, sizeof(ULONGLONG), NULL);
|
|
3092
|
+
SFileCloseFile(hFile);
|
|
3093
|
+
}
|
|
3094
|
+
else
|
|
3095
|
+
dwErrCode = GetLastError();
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
|
|
3099
|
+
// Add another file and check its position. It must be at the position of the former listfile
|
|
3100
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3101
|
+
{
|
|
3102
|
+
LPCSTR szAddedFile = "AddedFile02.txt";
|
|
3103
|
+
|
|
3104
|
+
// Add another file
|
|
3105
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, szAddedFile, "This is the second added file.", MPQ_FILE_COMPRESS);
|
|
3106
|
+
|
|
3107
|
+
// Retrieve the position of the (listfile)
|
|
3108
|
+
if(SFileOpenFileEx(hMpq, szAddedFile, 0, &hFile))
|
|
3109
|
+
{
|
|
3110
|
+
SFileGetFileInfo(hFile, SFileInfoByteOffset, &ByteOffset2, sizeof(ULONGLONG), NULL);
|
|
3111
|
+
SFileCloseFile(hFile);
|
|
3112
|
+
}
|
|
3113
|
+
else
|
|
3114
|
+
dwErrCode = GetLastError();
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3117
|
+
// Now check the positions
|
|
3118
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3119
|
+
{
|
|
3120
|
+
if(ByteOffset1 != ByteOffset2)
|
|
3121
|
+
{
|
|
3122
|
+
Logger.PrintError("The added file was not written to the position of (listfile)");
|
|
3123
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
|
|
3127
|
+
// Close the archive if needed
|
|
3128
|
+
if(hMpq != NULL)
|
|
3129
|
+
SFileCloseArchive(hMpq);
|
|
3130
|
+
return dwErrCode;
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3133
|
+
static DWORD TestCreateArchive_FillArchive(LPCTSTR szPlainName, DWORD dwCreateFlags)
|
|
3134
|
+
{
|
|
3135
|
+
TLogHelper Logger("TestCreateFull", szPlainName);
|
|
3136
|
+
LPCSTR szFileData = "TestCreateArchive_FillArchive: Testing file data";
|
|
3137
|
+
char szFileName[MAX_PATH];
|
|
3138
|
+
HANDLE hMpq = NULL;
|
|
3139
|
+
DWORD dwMaxFileCount = 6;
|
|
3140
|
+
DWORD dwCompression = MPQ_COMPRESSION_ZLIB;
|
|
3141
|
+
DWORD dwFlags = MPQ_FILE_ENCRYPTED | MPQ_FILE_COMPRESS;
|
|
3142
|
+
DWORD dwErrCode;
|
|
3143
|
+
|
|
3144
|
+
//
|
|
3145
|
+
// Note that StormLib will round the maxfile count
|
|
3146
|
+
// up to hash table size (nearest power of two)
|
|
3147
|
+
//
|
|
3148
|
+
if((dwCreateFlags & MPQ_CREATE_LISTFILE) == 0)
|
|
3149
|
+
dwMaxFileCount++;
|
|
3150
|
+
if((dwCreateFlags & MPQ_CREATE_ATTRIBUTES) == 0)
|
|
3151
|
+
dwMaxFileCount++;
|
|
3152
|
+
|
|
3153
|
+
// Create the new MPQ archive
|
|
3154
|
+
dwErrCode = CreateNewArchive_V2(&Logger, szPlainName, dwCreateFlags, dwMaxFileCount, &hMpq);
|
|
3155
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3156
|
+
{
|
|
3157
|
+
// Flush the archive first
|
|
3158
|
+
SFileFlushArchive(hMpq);
|
|
3159
|
+
|
|
3160
|
+
// Add all files
|
|
3161
|
+
for(unsigned int i = 0; i < dwMaxFileCount; i++)
|
|
3162
|
+
{
|
|
3163
|
+
sprintf(szFileName, "AddedFile%03u.txt", i);
|
|
3164
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, szFileName, szFileData, dwFlags, dwCompression);
|
|
3165
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
3166
|
+
break;
|
|
3167
|
+
}
|
|
3168
|
+
|
|
3169
|
+
// Flush the archive again
|
|
3170
|
+
SFileFlushArchive(hMpq);
|
|
3171
|
+
}
|
|
3172
|
+
|
|
3173
|
+
// Now the MPQ should be full. It must not be possible to add another file
|
|
3174
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3175
|
+
{
|
|
3176
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, "ShouldNotBeHere.txt", szFileData, MPQ_FILE_COMPRESS, MPQ_COMPRESSION_ZLIB, ERROR_DISK_FULL);
|
|
3177
|
+
assert(dwErrCode != ERROR_SUCCESS);
|
|
3178
|
+
dwErrCode = ERROR_SUCCESS;
|
|
3179
|
+
}
|
|
3180
|
+
|
|
3181
|
+
// Close the archive to enforce saving all tables
|
|
3182
|
+
if(hMpq != NULL)
|
|
3183
|
+
SFileCloseArchive(hMpq);
|
|
3184
|
+
hMpq = NULL;
|
|
3185
|
+
|
|
3186
|
+
// Reopen the archive again
|
|
3187
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3188
|
+
dwErrCode = OpenExistingArchiveWithCopy(&Logger, NULL, szPlainName, &hMpq);
|
|
3189
|
+
|
|
3190
|
+
// The archive should still be full
|
|
3191
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3192
|
+
{
|
|
3193
|
+
CheckIfFileIsPresent(&Logger, hMpq, LISTFILE_NAME, (dwCreateFlags & MPQ_CREATE_LISTFILE) ? true : false);
|
|
3194
|
+
CheckIfFileIsPresent(&Logger, hMpq, ATTRIBUTES_NAME, (dwCreateFlags & MPQ_CREATE_ATTRIBUTES) ? true : false);
|
|
3195
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, "ShouldNotBeHere.txt", szFileData, MPQ_FILE_COMPRESS, MPQ_COMPRESSION_ZLIB, ERROR_DISK_FULL);
|
|
3196
|
+
assert(dwErrCode != ERROR_SUCCESS);
|
|
3197
|
+
dwErrCode = ERROR_SUCCESS;
|
|
3198
|
+
}
|
|
3199
|
+
|
|
3200
|
+
// The (listfile) and (attributes) must be present
|
|
3201
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3202
|
+
{
|
|
3203
|
+
CheckIfFileIsPresent(&Logger, hMpq, LISTFILE_NAME, (dwCreateFlags & MPQ_CREATE_LISTFILE) ? true : false);
|
|
3204
|
+
CheckIfFileIsPresent(&Logger, hMpq, ATTRIBUTES_NAME, (dwCreateFlags & MPQ_CREATE_ATTRIBUTES) ? true : false);
|
|
3205
|
+
dwErrCode = RemoveMpqFile(&Logger, hMpq, szFileName, ERROR_SUCCESS);
|
|
3206
|
+
}
|
|
3207
|
+
|
|
3208
|
+
// Now add the file again. This time, it should be possible OK
|
|
3209
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3210
|
+
{
|
|
3211
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, szFileName, szFileData, dwFlags, dwCompression, ERROR_SUCCESS);
|
|
3212
|
+
assert(dwErrCode == ERROR_SUCCESS);
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3215
|
+
// Now add the file again. This time, it should fail
|
|
3216
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3217
|
+
{
|
|
3218
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, szFileName, szFileData, dwFlags, dwCompression, ERROR_ALREADY_EXISTS);
|
|
3219
|
+
assert(dwErrCode != ERROR_SUCCESS);
|
|
3220
|
+
dwErrCode = ERROR_SUCCESS;
|
|
3221
|
+
}
|
|
3222
|
+
|
|
3223
|
+
// Now add the file again. This time, it should fail
|
|
3224
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3225
|
+
{
|
|
3226
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, "ShouldNotBeHere.txt", szFileData, dwFlags, dwCompression, ERROR_DISK_FULL);
|
|
3227
|
+
assert(dwErrCode != ERROR_SUCCESS);
|
|
3228
|
+
dwErrCode = ERROR_SUCCESS;
|
|
3229
|
+
}
|
|
3230
|
+
|
|
3231
|
+
// Close the archive and return
|
|
3232
|
+
if(hMpq != NULL)
|
|
3233
|
+
SFileCloseArchive(hMpq);
|
|
3234
|
+
hMpq = NULL;
|
|
3235
|
+
|
|
3236
|
+
// Reopen the archive for the third time to verify that both internal files are there
|
|
3237
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3238
|
+
{
|
|
3239
|
+
dwErrCode = OpenExistingArchiveWithCopy(&Logger, NULL, szPlainName, &hMpq);
|
|
3240
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3241
|
+
{
|
|
3242
|
+
CheckIfFileIsPresent(&Logger, hMpq, LISTFILE_NAME, (dwCreateFlags & MPQ_CREATE_LISTFILE) ? true : false);
|
|
3243
|
+
CheckIfFileIsPresent(&Logger, hMpq, ATTRIBUTES_NAME, (dwCreateFlags & MPQ_CREATE_ATTRIBUTES) ? true : false);
|
|
3244
|
+
SFileCloseArchive(hMpq);
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
|
|
3248
|
+
return dwErrCode;
|
|
3249
|
+
}
|
|
3250
|
+
|
|
3251
|
+
static DWORD TestCreateArchive_IncMaxFileCount(LPCTSTR szPlainName)
|
|
3252
|
+
{
|
|
3253
|
+
TLogHelper Logger("IncMaxFileCount", szPlainName);
|
|
3254
|
+
LPCSTR szFileData = "TestCreateArchive_IncMaxFileCount: Testing file data";
|
|
3255
|
+
char szFileName[MAX_PATH];
|
|
3256
|
+
HANDLE hMpq = NULL;
|
|
3257
|
+
DWORD dwMaxFileCount = 1;
|
|
3258
|
+
DWORD dwErrCode;
|
|
3259
|
+
|
|
3260
|
+
// Create the new MPQ
|
|
3261
|
+
dwErrCode = CreateNewArchive(&Logger, szPlainName, MPQ_CREATE_ARCHIVE_V4 | MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES, dwMaxFileCount, &hMpq);
|
|
3262
|
+
|
|
3263
|
+
// Now add exactly one file
|
|
3264
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3265
|
+
{
|
|
3266
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, "AddFile_base.txt", szFileData);
|
|
3267
|
+
SFileFlushArchive(hMpq);
|
|
3268
|
+
SFileCloseArchive(hMpq);
|
|
3269
|
+
}
|
|
3270
|
+
|
|
3271
|
+
// Now add 10 files. Each time we cannot add the file due to archive being full,
|
|
3272
|
+
// we increment the max file count
|
|
3273
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3274
|
+
{
|
|
3275
|
+
for(unsigned int i = 0; i < 10; i++)
|
|
3276
|
+
{
|
|
3277
|
+
// Open the archive again
|
|
3278
|
+
dwErrCode = OpenExistingArchiveWithCopy(&Logger, NULL, szPlainName, &hMpq);
|
|
3279
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
3280
|
+
break;
|
|
3281
|
+
|
|
3282
|
+
// Add one file
|
|
3283
|
+
sprintf(szFileName, "AddFile_%04u.txt", i);
|
|
3284
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, szFileName, szFileData, 0, 0, ERROR_UNDETERMINED_RESULT);
|
|
3285
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
3286
|
+
{
|
|
3287
|
+
// Increment the max file count by one
|
|
3288
|
+
dwMaxFileCount = SFileGetMaxFileCount(hMpq) + 1;
|
|
3289
|
+
Logger.PrintProgress("Increasing max file count to %u ...", dwMaxFileCount);
|
|
3290
|
+
SFileSetMaxFileCount(hMpq, dwMaxFileCount);
|
|
3291
|
+
|
|
3292
|
+
// Attempt to create the file again
|
|
3293
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, szFileName, szFileData, 0, 0, ERROR_SUCCESS);
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3296
|
+
// Compact the archive and close it
|
|
3297
|
+
SFileSetCompactCallback(hMpq, CompactCallback, &Logger);
|
|
3298
|
+
SFileCompactArchive(hMpq, NULL, false);
|
|
3299
|
+
SFileCloseArchive(hMpq);
|
|
3300
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
3301
|
+
break;
|
|
3302
|
+
}
|
|
3303
|
+
}
|
|
3304
|
+
|
|
3305
|
+
return dwErrCode;
|
|
3306
|
+
}
|
|
3307
|
+
|
|
3308
|
+
static DWORD TestCreateArchive_FileFlagTest(LPCTSTR szPlainName)
|
|
3309
|
+
{
|
|
3310
|
+
TLogHelper Logger("TestFileFlag", szPlainName);
|
|
3311
|
+
HANDLE hMpq = NULL; // Handle of created archive
|
|
3312
|
+
TCHAR szFileName1[MAX_PATH];
|
|
3313
|
+
TCHAR szFileName2[MAX_PATH];
|
|
3314
|
+
TCHAR szFullPath[MAX_PATH];
|
|
3315
|
+
LPCSTR szMiddleFile = "FileTest_10.exe";
|
|
3316
|
+
LCID LocaleIDs[] = {0x000, 0x405, 0x406, 0x407};
|
|
3317
|
+
char szArchivedName[MAX_PATH];
|
|
3318
|
+
DWORD dwMaxFileCount = 0;
|
|
3319
|
+
DWORD dwFileCount = 0;
|
|
3320
|
+
DWORD dwErrCode;
|
|
3321
|
+
|
|
3322
|
+
// Create paths for local file to be added
|
|
3323
|
+
CreateFullPathName(szFileName1, _countof(szFileName1), szDataFileDir, _T("new-file.exe"));
|
|
3324
|
+
CreateFullPathName(szFileName2, _countof(szFileName2), szDataFileDir, _T("new-file.bin"));
|
|
3325
|
+
|
|
3326
|
+
// Create an empty file that will serve as holder for the MPQ
|
|
3327
|
+
dwErrCode = CreateEmptyFile(&Logger, szPlainName, 0x100000, szFullPath);
|
|
3328
|
+
|
|
3329
|
+
// Create new MPQ archive over that file
|
|
3330
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3331
|
+
dwErrCode = CreateNewArchive(&Logger, szPlainName, MPQ_CREATE_ARCHIVE_V1 | MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES, 17, &hMpq);
|
|
3332
|
+
|
|
3333
|
+
// Add the same file multiple times
|
|
3334
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3335
|
+
{
|
|
3336
|
+
dwMaxFileCount = SFileGetMaxFileCount(hMpq);
|
|
3337
|
+
for(size_t i = 0; AddFlags[i] != 0xFFFFFFFF; i++)
|
|
3338
|
+
{
|
|
3339
|
+
sprintf(szArchivedName, "FileTest_%02u.exe", (unsigned int)i);
|
|
3340
|
+
dwErrCode = AddLocalFileToMpq(&Logger, hMpq, szArchivedName, szFileName1, AddFlags[i], 0);
|
|
3341
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
3342
|
+
break;
|
|
3343
|
+
|
|
3344
|
+
dwFileCount++;
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
// Delete a file in the middle of the file table
|
|
3349
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3350
|
+
{
|
|
3351
|
+
Logger.PrintProgress("Removing file %s ...", szMiddleFile);
|
|
3352
|
+
dwErrCode = RemoveMpqFile(&Logger, hMpq, szMiddleFile, ERROR_SUCCESS);
|
|
3353
|
+
dwFileCount--;
|
|
3354
|
+
}
|
|
3355
|
+
|
|
3356
|
+
// Add one more file
|
|
3357
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3358
|
+
{
|
|
3359
|
+
dwErrCode = AddLocalFileToMpq(&Logger, hMpq, "FileTest_xx.exe", szFileName1);
|
|
3360
|
+
dwFileCount++;
|
|
3361
|
+
}
|
|
3362
|
+
|
|
3363
|
+
// Try to decrement max file count. This must succeed
|
|
3364
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3365
|
+
{
|
|
3366
|
+
Logger.PrintProgress("Attempting to decrement max file count ...");
|
|
3367
|
+
if(SFileSetMaxFileCount(hMpq, 5))
|
|
3368
|
+
dwErrCode = Logger.PrintError("Max file count decremented, even if it should fail");
|
|
3369
|
+
}
|
|
3370
|
+
|
|
3371
|
+
// Add ZeroSize.txt several times under a different locale
|
|
3372
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3373
|
+
{
|
|
3374
|
+
for(size_t i = 0; i < _countof(LocaleIDs); i++)
|
|
3375
|
+
{
|
|
3376
|
+
bool bMustSucceed = ((dwFileCount + 2) < dwMaxFileCount);
|
|
3377
|
+
|
|
3378
|
+
SFileSetLocale(LocaleIDs[i]);
|
|
3379
|
+
dwErrCode = AddLocalFileToMpq(&Logger, hMpq, "ZeroSize_1.txt", szFileName2);
|
|
3380
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
3381
|
+
{
|
|
3382
|
+
if(bMustSucceed == false)
|
|
3383
|
+
dwErrCode = ERROR_SUCCESS;
|
|
3384
|
+
break;
|
|
3385
|
+
}
|
|
3386
|
+
|
|
3387
|
+
dwFileCount++;
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
|
|
3391
|
+
// Add ZeroSize.txt again several times under a different locale
|
|
3392
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3393
|
+
{
|
|
3394
|
+
for(size_t i = 0; LocaleIDs[i] != 0xFFFF; i++)
|
|
3395
|
+
{
|
|
3396
|
+
bool bMustSucceed = ((dwFileCount + 2) < dwMaxFileCount);
|
|
3397
|
+
|
|
3398
|
+
SFileSetLocale(LocaleIDs[i]);
|
|
3399
|
+
dwErrCode = AddLocalFileToMpq(&Logger, hMpq, "ZeroSize_2.txt", szFileName2, 0, 0, bMustSucceed);
|
|
3400
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
3401
|
+
{
|
|
3402
|
+
if(bMustSucceed == false)
|
|
3403
|
+
dwErrCode = ERROR_SUCCESS;
|
|
3404
|
+
break;
|
|
3405
|
+
}
|
|
3406
|
+
|
|
3407
|
+
dwFileCount++;
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
|
|
3411
|
+
// Verify how many files did we add to the MPQ
|
|
3412
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3413
|
+
{
|
|
3414
|
+
if(dwFileCount + 2 != dwMaxFileCount)
|
|
3415
|
+
{
|
|
3416
|
+
Logger.PrintErrorVa("Number of files added to MPQ was unexpected (expected %u, added %u)", dwFileCount, dwMaxFileCount - 2);
|
|
3417
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
3418
|
+
}
|
|
3419
|
+
}
|
|
3420
|
+
|
|
3421
|
+
// Test rename function
|
|
3422
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3423
|
+
{
|
|
3424
|
+
Logger.PrintProgress("Testing rename files ...");
|
|
3425
|
+
SFileSetLocale(LANG_NEUTRAL);
|
|
3426
|
+
if(!SFileRenameFile(hMpq, "FileTest_08.exe", "FileTest_08a.exe"))
|
|
3427
|
+
dwErrCode = Logger.PrintError("Failed to rename the file");
|
|
3428
|
+
}
|
|
3429
|
+
|
|
3430
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3431
|
+
{
|
|
3432
|
+
if(!SFileRenameFile(hMpq, "FileTest_08a.exe", "FileTest_08.exe"))
|
|
3433
|
+
dwErrCode = Logger.PrintError("Failed to rename the file");
|
|
3434
|
+
}
|
|
3435
|
+
|
|
3436
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3437
|
+
{
|
|
3438
|
+
if(SFileRenameFile(hMpq, "FileTest_10.exe", "FileTest_10a.exe"))
|
|
3439
|
+
{
|
|
3440
|
+
Logger.PrintError("Rename test succeeded even if it shouldn't");
|
|
3441
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
|
|
3445
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3446
|
+
{
|
|
3447
|
+
if(SFileRenameFile(hMpq, "FileTest_10a.exe", "FileTest_10.exe"))
|
|
3448
|
+
{
|
|
3449
|
+
Logger.PrintError("Rename test succeeded even if it shouldn't");
|
|
3450
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
|
|
3454
|
+
// Close the archive
|
|
3455
|
+
if(hMpq != NULL)
|
|
3456
|
+
SFileCloseArchive(hMpq);
|
|
3457
|
+
hMpq = NULL;
|
|
3458
|
+
|
|
3459
|
+
// Try to reopen the archive
|
|
3460
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3461
|
+
dwErrCode = OpenExistingArchive(&Logger, szFullPath, 0, NULL);
|
|
3462
|
+
return dwErrCode;
|
|
3463
|
+
}
|
|
3464
|
+
|
|
3465
|
+
static DWORD TestCreateArchive_WaveCompressionsTest(LPCTSTR szPlainName, LPCTSTR szWaveFile)
|
|
3466
|
+
{
|
|
3467
|
+
TLogHelper Logger("TestCompressions", szPlainName);
|
|
3468
|
+
HANDLE hMpq = NULL; // Handle of created archive
|
|
3469
|
+
TCHAR szFileName[MAX_PATH]; // Source file to be added
|
|
3470
|
+
char szArchivedName[MAX_PATH];
|
|
3471
|
+
DWORD dwCmprCount = sizeof(WaveCompressions) / sizeof(DWORD);
|
|
3472
|
+
DWORD dwAddedFiles = 0;
|
|
3473
|
+
DWORD dwFoundFiles = 0;
|
|
3474
|
+
DWORD dwErrCode;
|
|
3475
|
+
|
|
3476
|
+
// Create paths for local file to be added
|
|
3477
|
+
CreateFullPathName(szFileName, _countof(szFileName), szDataFileDir, szWaveFile);
|
|
3478
|
+
|
|
3479
|
+
// Create new archive
|
|
3480
|
+
dwErrCode = CreateNewArchive(&Logger, szPlainName, MPQ_CREATE_ARCHIVE_V1 | MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES, 0x40, &hMpq);
|
|
3481
|
+
|
|
3482
|
+
// Add the same file multiple times
|
|
3483
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3484
|
+
{
|
|
3485
|
+
Logger.UserTotal = dwCmprCount;
|
|
3486
|
+
for(unsigned int i = 0; i < dwCmprCount; i++)
|
|
3487
|
+
{
|
|
3488
|
+
sprintf(szArchivedName, "WaveFile_%02u.wav", i + 1);
|
|
3489
|
+
dwErrCode = AddLocalFileToMpq(&Logger, hMpq, szArchivedName, szFileName, MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_SECTOR_CRC, WaveCompressions[i]);
|
|
3490
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
3491
|
+
break;
|
|
3492
|
+
|
|
3493
|
+
Logger.UserCount++;
|
|
3494
|
+
dwAddedFiles++;
|
|
3495
|
+
}
|
|
3496
|
+
|
|
3497
|
+
SFileCloseArchive(hMpq);
|
|
3498
|
+
}
|
|
3499
|
+
|
|
3500
|
+
// Reopen the archive extract each WAVE file and try to play it
|
|
3501
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3502
|
+
{
|
|
3503
|
+
dwErrCode = OpenExistingArchiveWithCopy(&Logger, NULL, szPlainName, &hMpq);
|
|
3504
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3505
|
+
{
|
|
3506
|
+
SearchArchive(&Logger, hMpq, SEARCH_FLAG_LOAD_FILES | SEARCH_FLAG_PLAY_WAVES, &dwFoundFiles, NULL);
|
|
3507
|
+
SFileCloseArchive(hMpq);
|
|
3508
|
+
}
|
|
3509
|
+
|
|
3510
|
+
// Check if the number of found files is the same like the number of added files
|
|
3511
|
+
// DOn;t forget that there will be (listfile) and (attributes)
|
|
3512
|
+
if(dwFoundFiles != (dwAddedFiles + 2))
|
|
3513
|
+
{
|
|
3514
|
+
Logger.PrintError("Number of found files does not match number of added files.");
|
|
3515
|
+
dwErrCode = ERROR_FILE_CORRUPT;
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
|
|
3519
|
+
return dwErrCode;
|
|
3520
|
+
}
|
|
3521
|
+
|
|
3522
|
+
static DWORD TestCreateArchive_ListFilePos(LPCTSTR szPlainName)
|
|
3523
|
+
{
|
|
3524
|
+
PFILE_DATA pFileData;
|
|
3525
|
+
LPCSTR szReaddedFile = "AddedFile_##.txt";
|
|
3526
|
+
LPCSTR szFileMask = "AddedFile_%02u.txt";
|
|
3527
|
+
TLogHelper Logger("ListFilePos", szPlainName);
|
|
3528
|
+
HANDLE hMpq = NULL; // Handle of created archive
|
|
3529
|
+
char szArchivedName[MAX_PATH];
|
|
3530
|
+
DWORD dwMaxFileCount = 0x0E;
|
|
3531
|
+
DWORD dwFileCount = 0;
|
|
3532
|
+
size_t i;
|
|
3533
|
+
DWORD dwErrCode;
|
|
3534
|
+
|
|
3535
|
+
// Create a new archive with the limit of 0x20 files
|
|
3536
|
+
dwErrCode = CreateNewArchive(&Logger, szPlainName, MPQ_CREATE_ARCHIVE_V4 | MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES, dwMaxFileCount, &hMpq);
|
|
3537
|
+
|
|
3538
|
+
// Add maximum files files
|
|
3539
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3540
|
+
{
|
|
3541
|
+
for(i = 0; i < dwMaxFileCount; i++)
|
|
3542
|
+
{
|
|
3543
|
+
sprintf(szArchivedName, szFileMask, i);
|
|
3544
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, szArchivedName, "This is a text data.", 0, 0, ERROR_SUCCESS);
|
|
3545
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
3546
|
+
break;
|
|
3547
|
+
|
|
3548
|
+
dwFileCount++;
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
|
|
3552
|
+
// Delete few middle files
|
|
3553
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3554
|
+
{
|
|
3555
|
+
for(i = 0; i < (dwMaxFileCount / 2); i++)
|
|
3556
|
+
{
|
|
3557
|
+
sprintf(szArchivedName, szFileMask, i);
|
|
3558
|
+
dwErrCode = RemoveMpqFile(&Logger, hMpq, szArchivedName, ERROR_SUCCESS);
|
|
3559
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
3560
|
+
break;
|
|
3561
|
+
|
|
3562
|
+
dwFileCount--;
|
|
3563
|
+
}
|
|
3564
|
+
}
|
|
3565
|
+
|
|
3566
|
+
// Close the archive
|
|
3567
|
+
if(hMpq != NULL)
|
|
3568
|
+
SFileCloseArchive(hMpq);
|
|
3569
|
+
hMpq = NULL;
|
|
3570
|
+
|
|
3571
|
+
// Reopen the archive to catch any asserts
|
|
3572
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3573
|
+
dwErrCode = OpenExistingArchiveWithCopy(&Logger, NULL, szPlainName, &hMpq);
|
|
3574
|
+
|
|
3575
|
+
// Check that (listfile) is at the end
|
|
3576
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3577
|
+
{
|
|
3578
|
+
if(LoadMpqFile(Logger, hMpq, LISTFILE_NAME, 0, 0, &pFileData) == ERROR_SUCCESS)
|
|
3579
|
+
{
|
|
3580
|
+
if(pFileData->dwBlockIndex < dwFileCount)
|
|
3581
|
+
Logger.PrintMessage("Unexpected file index of %s", LISTFILE_NAME);
|
|
3582
|
+
STORM_FREE(pFileData);
|
|
3583
|
+
}
|
|
3584
|
+
|
|
3585
|
+
if(LoadMpqFile(Logger, hMpq, ATTRIBUTES_NAME, 0, 0, &pFileData) == ERROR_SUCCESS)
|
|
3586
|
+
{
|
|
3587
|
+
if(pFileData->dwBlockIndex <= dwFileCount)
|
|
3588
|
+
Logger.PrintMessage("Unexpected file index of %s", ATTRIBUTES_NAME);
|
|
3589
|
+
STORM_FREE(pFileData);
|
|
3590
|
+
}
|
|
3591
|
+
|
|
3592
|
+
// Add new file to the archive. It should be added to the last position
|
|
3593
|
+
dwErrCode = AddFileToMpq(&Logger, hMpq, szReaddedFile, "This is a re-added file.", 0, 0, ERROR_SUCCESS);
|
|
3594
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3595
|
+
{
|
|
3596
|
+
// Force update of the tables
|
|
3597
|
+
SFileFlushArchive(hMpq);
|
|
3598
|
+
|
|
3599
|
+
// Load the file
|
|
3600
|
+
if(LoadMpqFile(Logger, hMpq, szReaddedFile, 0, 0, &pFileData) == ERROR_SUCCESS)
|
|
3601
|
+
{
|
|
3602
|
+
if(pFileData->dwBlockIndex != dwFileCount)
|
|
3603
|
+
Logger.PrintMessage("Unexpected file index of %s", szReaddedFile);
|
|
3604
|
+
STORM_FREE(pFileData);
|
|
3605
|
+
}
|
|
3606
|
+
}
|
|
3607
|
+
|
|
3608
|
+
SFileCloseArchive(hMpq);
|
|
3609
|
+
}
|
|
3610
|
+
|
|
3611
|
+
return dwErrCode;
|
|
3612
|
+
}
|
|
3613
|
+
|
|
3614
|
+
static DWORD TestCreateArchive_BigArchive(LPCTSTR szPlainName)
|
|
3615
|
+
{
|
|
3616
|
+
TLogHelper Logger("TestBigArchive", szPlainName);
|
|
3617
|
+
HANDLE hMpq = NULL; // Handle of created archive
|
|
3618
|
+
TCHAR szLocalFileName[MAX_PATH];
|
|
3619
|
+
char szArchivedName[MAX_PATH];
|
|
3620
|
+
DWORD dwMaxFileCount = 0x20;
|
|
3621
|
+
DWORD dwAddedCount = 0;
|
|
3622
|
+
size_t i;
|
|
3623
|
+
DWORD dwErrCode;
|
|
3624
|
+
|
|
3625
|
+
// Create a new archive with the limit of 0x20 files
|
|
3626
|
+
dwErrCode = CreateNewArchive(&Logger, szPlainName, MPQ_CREATE_ARCHIVE_V3 | MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES, dwMaxFileCount, &hMpq);
|
|
3627
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3628
|
+
{
|
|
3629
|
+
LPCSTR szFileMask = "AddedFile_%02u.txt";
|
|
3630
|
+
|
|
3631
|
+
// Now add few really big files
|
|
3632
|
+
CreateFullPathName(szLocalFileName, _countof(szLocalFileName), szMpqSubDir, _T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"));
|
|
3633
|
+
Logger.UserTotal = (dwMaxFileCount / 2);
|
|
3634
|
+
|
|
3635
|
+
for(i = 0; i < dwMaxFileCount / 2; i++)
|
|
3636
|
+
{
|
|
3637
|
+
sprintf(szArchivedName, szFileMask, i + 1);
|
|
3638
|
+
dwErrCode = AddLocalFileToMpq(&Logger, hMpq, szArchivedName, szLocalFileName, 0, 0, true);
|
|
3639
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
3640
|
+
break;
|
|
3641
|
+
|
|
3642
|
+
Logger.UserCount++;
|
|
3643
|
+
dwAddedCount++;
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3646
|
+
|
|
3647
|
+
// Close the archive
|
|
3648
|
+
if(hMpq != NULL)
|
|
3649
|
+
SFileCloseArchive(hMpq);
|
|
3650
|
+
hMpq = NULL;
|
|
3651
|
+
|
|
3652
|
+
// Reopen the archive to catch any asserts
|
|
3653
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3654
|
+
dwErrCode = OpenExistingArchiveWithCopy(&Logger, NULL, szPlainName, &hMpq);
|
|
3655
|
+
|
|
3656
|
+
// Check that (listfile) is at the end
|
|
3657
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3658
|
+
{
|
|
3659
|
+
CheckIfFileIsPresent(&Logger, hMpq, LISTFILE_NAME, true);
|
|
3660
|
+
CheckIfFileIsPresent(&Logger, hMpq, ATTRIBUTES_NAME, true);
|
|
3661
|
+
|
|
3662
|
+
SFileCloseArchive(hMpq);
|
|
3663
|
+
}
|
|
3664
|
+
|
|
3665
|
+
return dwErrCode;
|
|
3666
|
+
}
|
|
3667
|
+
|
|
3668
|
+
// Test replacing a file in an archive
|
|
3669
|
+
static DWORD TestReplaceFile(LPCTSTR szMpqPlainName, LPCTSTR szFilePlainName, LPCSTR szFileFlags, DWORD dwCompression)
|
|
3670
|
+
{
|
|
3671
|
+
TLogHelper Logger("TestModifyMpq", szMpqPlainName);
|
|
3672
|
+
HANDLE hMpq = NULL;
|
|
3673
|
+
TCHAR szFileFullName[MAX_PATH];
|
|
3674
|
+
TCHAR szMpqFullName[MAX_PATH];
|
|
3675
|
+
char szArchivedName[MAX_PATH];
|
|
3676
|
+
DWORD dwErrCode;
|
|
3677
|
+
DWORD dwFileFlags = (DWORD)(DWORD_PTR)(szFileFlags); // szFileFlags is a file flags cast to LPCSTR
|
|
3678
|
+
BYTE md5_file_in_mpq1[MD5_DIGEST_SIZE];
|
|
3679
|
+
BYTE md5_file_in_mpq2[MD5_DIGEST_SIZE];
|
|
3680
|
+
BYTE md5_file_in_mpq3[MD5_DIGEST_SIZE];
|
|
3681
|
+
BYTE md5_file_local[MD5_DIGEST_SIZE];
|
|
3682
|
+
|
|
3683
|
+
// Get the name of archived file as plain text. If the file shall be in a subfolder,
|
|
3684
|
+
// its name must contain a hashtag, e.g. "staredit#scenario.chk"
|
|
3685
|
+
StringCopy(szArchivedName, _countof(szArchivedName), szFilePlainName);
|
|
3686
|
+
for(size_t i = 0; szArchivedName[i] != 0; i++)
|
|
3687
|
+
szArchivedName[i] = (szArchivedName[i] == '#') ? '\\' : szArchivedName[i];
|
|
3688
|
+
|
|
3689
|
+
// Get the full path of the archive and local file
|
|
3690
|
+
CreateFullPathName(szFileFullName, _countof(szFileFullName), szDataFileDir, szFilePlainName);
|
|
3691
|
+
CreateFullPathName(szMpqFullName, _countof(szMpqFullName), NULL, szMpqPlainName);
|
|
3692
|
+
dwFileFlags |= MPQ_FILE_REPLACEEXISTING | MPQ_FILE_COMPRESS;
|
|
3693
|
+
|
|
3694
|
+
// Open an existing archive
|
|
3695
|
+
dwErrCode = OpenExistingArchiveWithCopy(&Logger, szMpqPlainName, szMpqPlainName, &hMpq);
|
|
3696
|
+
|
|
3697
|
+
// Open the file, load to memory, calculate hash
|
|
3698
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3699
|
+
{
|
|
3700
|
+
dwErrCode = LoadMpqFileMD5(Logger, hMpq, szArchivedName, md5_file_in_mpq1);
|
|
3701
|
+
}
|
|
3702
|
+
|
|
3703
|
+
// Open the local file, calculate hash
|
|
3704
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3705
|
+
{
|
|
3706
|
+
dwErrCode = LoadLocalFileMD5(&Logger, szFileFullName, md5_file_local);
|
|
3707
|
+
}
|
|
3708
|
+
|
|
3709
|
+
// Add the given file
|
|
3710
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3711
|
+
{
|
|
3712
|
+
// Add the file to MPQ
|
|
3713
|
+
dwErrCode = AddLocalFileToMpq(&Logger, hMpq,
|
|
3714
|
+
szArchivedName,
|
|
3715
|
+
szFileFullName,
|
|
3716
|
+
dwFileFlags,
|
|
3717
|
+
dwCompression,
|
|
3718
|
+
true);
|
|
3719
|
+
}
|
|
3720
|
+
|
|
3721
|
+
// Load the file from the MPQ again and compare both MD5's
|
|
3722
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3723
|
+
{
|
|
3724
|
+
// Load the file from the MPQ again
|
|
3725
|
+
dwErrCode = LoadMpqFileMD5(Logger, hMpq, szArchivedName, md5_file_in_mpq2);
|
|
3726
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3727
|
+
{
|
|
3728
|
+
// New MPQ file must be different from the old one
|
|
3729
|
+
if(!memcmp(md5_file_in_mpq2, md5_file_in_mpq1, MD5_DIGEST_SIZE))
|
|
3730
|
+
{
|
|
3731
|
+
Logger.PrintError("Data mismatch after adding the file \"%s\"", szArchivedName);
|
|
3732
|
+
dwErrCode = ERROR_CHECKSUM_ERROR;
|
|
3733
|
+
}
|
|
3734
|
+
|
|
3735
|
+
// New MPQ file must be identical to the local one
|
|
3736
|
+
if(memcmp(md5_file_in_mpq2, md5_file_local, MD5_DIGEST_SIZE))
|
|
3737
|
+
{
|
|
3738
|
+
Logger.PrintError("Data mismatch after adding the file \"%s\"", szArchivedName);
|
|
3739
|
+
dwErrCode = ERROR_CHECKSUM_ERROR;
|
|
3740
|
+
}
|
|
3741
|
+
}
|
|
3742
|
+
}
|
|
3743
|
+
|
|
3744
|
+
// Compact the MPQ
|
|
3745
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3746
|
+
{
|
|
3747
|
+
// Compact the archive
|
|
3748
|
+
Logger.PrintProgress("Compacting archive %s ...", szMpqPlainName);
|
|
3749
|
+
if(!SFileSetCompactCallback(hMpq, CompactCallback, &Logger))
|
|
3750
|
+
dwErrCode = Logger.PrintError(_T("Failed to compact archive %s"), szMpqPlainName);
|
|
3751
|
+
|
|
3752
|
+
// Some test archives (like MPQ_2022_v1_v4.329.w3x) can't be compacted.
|
|
3753
|
+
// For that reason, we ignore the result of SFileCompactArchive().
|
|
3754
|
+
SFileCompactArchive(hMpq, NULL, 0);
|
|
3755
|
+
SFileCloseArchive(hMpq);
|
|
3756
|
+
hMpq = NULL;
|
|
3757
|
+
}
|
|
3758
|
+
|
|
3759
|
+
// Try to open the archive again. Ignore the previous errors
|
|
3760
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3761
|
+
{
|
|
3762
|
+
dwErrCode = OpenExistingArchive(&Logger, szMpqFullName, 0, &hMpq);
|
|
3763
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3764
|
+
{
|
|
3765
|
+
// Load the file from the MPQ again
|
|
3766
|
+
dwErrCode = LoadMpqFileMD5(Logger, hMpq, szArchivedName, md5_file_in_mpq3);
|
|
3767
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
3768
|
+
{
|
|
3769
|
+
// New MPQ file must be the same like the local one
|
|
3770
|
+
if(memcmp(md5_file_in_mpq3, md5_file_local, MD5_DIGEST_SIZE))
|
|
3771
|
+
{
|
|
3772
|
+
Logger.PrintError("Data mismatch after adding the file \"%s\"", szArchivedName);
|
|
3773
|
+
dwErrCode = ERROR_CHECKSUM_ERROR;
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
|
|
3777
|
+
SFileCloseArchive(hMpq);
|
|
3778
|
+
hMpq = NULL;
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3781
|
+
|
|
3782
|
+
// Finally, close the archive
|
|
3783
|
+
if(hMpq != NULL)
|
|
3784
|
+
SFileCloseArchive(hMpq);
|
|
3785
|
+
return dwErrCode;
|
|
3786
|
+
}
|
|
3787
|
+
|
|
3788
|
+
static void Test_PlayingSpace()
|
|
3789
|
+
{
|
|
3790
|
+
/*
|
|
3791
|
+
i8 v0_tmp[] = {5, 34, -58, 65, 113, -118, 76, 11, 40, 32, 27, 20, 83, 15, 22, 46, 25, -24, -77, -88, -70, -118, -58, 56, 55, -94, -69, 43, -87, -1, -70, 0,}; // pvFileInfo
|
|
3792
|
+
i8 * v0 = (i8 *)malloc(sizeof v0_tmp);
|
|
3793
|
+
memcpy(v0, v0_tmp, sizeof v0_tmp);
|
|
3794
|
+
i8 * v1 = v0; // pvFileInfo
|
|
3795
|
+
|
|
3796
|
+
enum _SFileInfoClass v2 = (enum _SFileInfoClass)(11); // InfoClass
|
|
3797
|
+
i8 v3 = SFileFreeFileInfo(v1, v2); // $target
|
|
3798
|
+
*/
|
|
3799
|
+
}
|
|
3800
|
+
|
|
3801
|
+
//-----------------------------------------------------------------------------
|
|
3802
|
+
// Tables
|
|
3803
|
+
|
|
3804
|
+
static LPCTSTR szSigned1 = _T("STANDARD.SNP");
|
|
3805
|
+
static LPCTSTR szSigned2 = _T("War2Patch_202.exe");
|
|
3806
|
+
static LPCTSTR szSigned3 = _T("WoW-1.2.3.4211-enUS-patch.exe");
|
|
3807
|
+
static LPCTSTR szSigned4 = _T("(10)DustwallowKeys.w3m");
|
|
3808
|
+
|
|
3809
|
+
static LPCTSTR szDiabdatMPQ = _T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ");
|
|
3810
|
+
|
|
3811
|
+
static const TEST_EXTRA_ONEFILE LfBliz = {ListFile, _T("ListFile_Blizzard.txt")};
|
|
3812
|
+
static const TEST_EXTRA_ONEFILE LfWotI = {ListFile, _T("ListFile_WarOfTheImmortals.txt")};
|
|
3813
|
+
|
|
3814
|
+
static const BYTE szMpqFileNameUTF8[] = {0x4D, 0x50, 0x51, 0x5F, 0x32, 0x30, 0x32, 0x34, 0x5F, 0x76, 0x31, 0x5F, 0xE6, 0x9D, 0x82, 0xE9, 0xB1, 0xBC, 0xE5, 0x9C, 0xB0, 0xE7, 0x89, 0xA2, 0x5F, 0x30, 0x2E, 0x30, 0x38, 0x34, 0x62, 0x65, 0x74, 0x61, 0x34, 0x36, 0x2E, 0x77, 0x33, 0x78, 0x00};
|
|
3815
|
+
static const BYTE szLstFileNameUTF8[] = {0x4C, 0x69, 0x73, 0x74, 0x46, 0x69, 0x6C, 0x65, 0x5F, 0xE6, 0x9D, 0x82, 0xE9, 0xB1, 0xBC, 0xE5, 0x9C, 0xB0, 0xE7, 0x89, 0xA2, 0x5F, 0x30, 0x2E, 0x30, 0x38, 0x34, 0x62, 0x65, 0x74, 0x61, 0x34, 0x36, 0x2E, 0x74, 0x78, 0x74, 0x00};
|
|
3816
|
+
static const TEST_EXTRA_UTF8 MpqUtf8 = {Utf8File, szMpqFileNameUTF8, szLstFileNameUTF8};
|
|
3817
|
+
|
|
3818
|
+
static const TEST_EXTRA_TWOFILES TwoFilesD1 = {TwoFiles, "music\\dintro.wav", "File00000023.xxx"};
|
|
3819
|
+
static const TEST_EXTRA_TWOFILES TwoFilesD2 = {TwoFiles, "waitingroombkgd.dc6"};
|
|
3820
|
+
static const TEST_EXTRA_TWOFILES TwoFilesW3M = {TwoFiles, "file00000002.blp"};
|
|
3821
|
+
static const TEST_EXTRA_TWOFILES TwoFilesW3X = {TwoFiles, "BlueCrystal.mdx"};
|
|
3822
|
+
|
|
3823
|
+
static const TEST_EXTRA_HASHVALS HashVals =
|
|
3824
|
+
{
|
|
3825
|
+
HashValues,
|
|
3826
|
+
{
|
|
3827
|
+
{0x00000000, 0x00000000, "File00024483.blp"},
|
|
3828
|
+
{0x8bd6929a, 0xfd55129b, "ReplaceableTextures\\CommandButtons\\BTNHaboss79.blp"}
|
|
3829
|
+
}
|
|
3830
|
+
};
|
|
3831
|
+
|
|
3832
|
+
static const TEST_EXTRA_PATCHES PatchSC1 =
|
|
3833
|
+
{
|
|
3834
|
+
PatchList,
|
|
3835
|
+
_T("s1-1998-BroodWar.mpq\0"),
|
|
3836
|
+
"music\\terran1.wav",
|
|
3837
|
+
0
|
|
3838
|
+
};
|
|
3839
|
+
|
|
3840
|
+
static const TEST_EXTRA_PATCHES Patch13286 =
|
|
3841
|
+
{
|
|
3842
|
+
PatchList,
|
|
3843
|
+
_T("wow-update-oldworld-13154.MPQ\0")
|
|
3844
|
+
_T("wow-update-oldworld-13286.MPQ\0"),
|
|
3845
|
+
"OldWorld\\World\\Model.blob",
|
|
3846
|
+
2
|
|
3847
|
+
};
|
|
3848
|
+
|
|
3849
|
+
static const TEST_EXTRA_PATCHES Patch15050 =
|
|
3850
|
+
{
|
|
3851
|
+
PatchList,
|
|
3852
|
+
_T("wow-update-13164.MPQ\0")
|
|
3853
|
+
_T("wow-update-13205.MPQ\0")
|
|
3854
|
+
_T("wow-update-13287.MPQ\0")
|
|
3855
|
+
_T("wow-update-13329.MPQ\0")
|
|
3856
|
+
_T("wow-update-13596.MPQ\0")
|
|
3857
|
+
_T("wow-update-13623.MPQ\0")
|
|
3858
|
+
_T("wow-update-base-13914.MPQ\0")
|
|
3859
|
+
_T("wow-update-base-14007.MPQ\0")
|
|
3860
|
+
_T("wow-update-base-14333.MPQ\0")
|
|
3861
|
+
_T("wow-update-base-14480.MPQ\0")
|
|
3862
|
+
_T("wow-update-base-14545.MPQ\0")
|
|
3863
|
+
_T("wow-update-base-14946.MPQ\0")
|
|
3864
|
+
_T("wow-update-base-15005.MPQ\0")
|
|
3865
|
+
_T("wow-update-base-15050.MPQ\0"),
|
|
3866
|
+
"World\\Model.blob",
|
|
3867
|
+
8
|
|
3868
|
+
};
|
|
3869
|
+
|
|
3870
|
+
static const TEST_EXTRA_PATCHES Patch16965 =
|
|
3871
|
+
{
|
|
3872
|
+
PatchList,
|
|
3873
|
+
_T("wow-update-enGB-16016.MPQ\0")
|
|
3874
|
+
_T("wow-update-enGB-16048.MPQ\0")
|
|
3875
|
+
_T("wow-update-enGB-16057.MPQ\0")
|
|
3876
|
+
_T("wow-update-enGB-16309.MPQ\0")
|
|
3877
|
+
_T("wow-update-enGB-16357.MPQ\0")
|
|
3878
|
+
_T("wow-update-enGB-16516.MPQ\0")
|
|
3879
|
+
_T("wow-update-enGB-16650.MPQ\0")
|
|
3880
|
+
_T("wow-update-enGB-16844.MPQ\0")
|
|
3881
|
+
_T("wow-update-enGB-16965.MPQ\0"),
|
|
3882
|
+
"DBFilesClient\\BattlePetNPCTeamMember.db2",
|
|
3883
|
+
0
|
|
3884
|
+
};
|
|
3885
|
+
|
|
3886
|
+
static const TEST_EXTRA_PATCHES Patch32283 =
|
|
3887
|
+
{
|
|
3888
|
+
PatchList,
|
|
3889
|
+
_T("s2-update-base-23258.MPQ\0")
|
|
3890
|
+
_T("s2-update-base-24540.MPQ\0")
|
|
3891
|
+
_T("s2-update-base-26147.MPQ\0")
|
|
3892
|
+
_T("s2-update-base-28522.MPQ\0")
|
|
3893
|
+
_T("s2-update-base-30508.MPQ\0")
|
|
3894
|
+
_T("s2-update-base-32283.MPQ\0"),
|
|
3895
|
+
"TriggerLibs\\natives.galaxy",
|
|
3896
|
+
6
|
|
3897
|
+
};
|
|
3898
|
+
|
|
3899
|
+
static const TEST_EXTRA_PATCHES Patch32283a =
|
|
3900
|
+
{
|
|
3901
|
+
PatchList,
|
|
3902
|
+
_T("s2-update-enGB-23258.MPQ\0")
|
|
3903
|
+
_T("s2-update-enGB-24540.MPQ\0")
|
|
3904
|
+
_T("s2-update-enGB-26147.MPQ\0")
|
|
3905
|
+
_T("s2-update-enGB-28522.MPQ\0")
|
|
3906
|
+
_T("s2-update-enGB-30508.MPQ\0")
|
|
3907
|
+
_T("s2-update-enGB-32283.MPQ\0"),
|
|
3908
|
+
"Assets\\Textures\\startupimage.dds",
|
|
3909
|
+
0
|
|
3910
|
+
};
|
|
3911
|
+
|
|
3912
|
+
static const TEST_EXTRA_PATCHES Patch34644 =
|
|
3913
|
+
{
|
|
3914
|
+
PatchList,
|
|
3915
|
+
_T("s2-update-base-23258.MPQ\0")
|
|
3916
|
+
_T("s2-update-base-24540.MPQ\0")
|
|
3917
|
+
_T("s2-update-base-26147.MPQ\0")
|
|
3918
|
+
_T("s2-update-base-28522.MPQ\0")
|
|
3919
|
+
_T("s2-update-base-32384.MPQ\0")
|
|
3920
|
+
_T("s2-update-base-34644.MPQ\0"),
|
|
3921
|
+
"TriggerLibs\\GameData\\GameData.galaxy",
|
|
3922
|
+
2
|
|
3923
|
+
};
|
|
3924
|
+
|
|
3925
|
+
static const TEST_EXTRA_PATCHES Patch34644m =
|
|
3926
|
+
{
|
|
3927
|
+
PatchList,
|
|
3928
|
+
_T("s2-update-base-23258.MPQ\0")
|
|
3929
|
+
_T("s2-update-base-24540.MPQ\0")
|
|
3930
|
+
_T("s2-update-base-26147.MPQ\0")
|
|
3931
|
+
_T("s2-update-base-28522.MPQ\0")
|
|
3932
|
+
_T("s2-update-base-32384.MPQ\0")
|
|
3933
|
+
_T("s2-update-base-34644.MPQ\0"),
|
|
3934
|
+
"Maps\\Campaign\\THorner03.SC2Map\\BankList.xml",
|
|
3935
|
+
3
|
|
3936
|
+
};
|
|
3937
|
+
|
|
3938
|
+
static const TEST_EXTRA_PATCHES Patch36281 =
|
|
3939
|
+
{
|
|
3940
|
+
PatchList,
|
|
3941
|
+
_T("s2-update-enGB-23258.MPQ\0")
|
|
3942
|
+
_T("s2-update-enGB-24540.MPQ\0")
|
|
3943
|
+
_T("s2-update-enGB-26147.MPQ\0")
|
|
3944
|
+
_T("s2-update-enGB-28522.MPQ\0")
|
|
3945
|
+
_T("s2-update-enGB-32384.MPQ\0")
|
|
3946
|
+
_T("s2-update-enGB-34644.MPQ\0")
|
|
3947
|
+
_T("s2-update-enGB-36281.MPQ\0"),
|
|
3948
|
+
"LocalizedData\\GameHotkeys.txt",
|
|
3949
|
+
6
|
|
3950
|
+
};
|
|
3951
|
+
|
|
3952
|
+
static const TEST_EXTRA_PATCHES PatchH3604 =
|
|
3953
|
+
{
|
|
3954
|
+
PatchList,
|
|
3955
|
+
_T("hs-0-3604-Win-final.MPQ\0"),
|
|
3956
|
+
"Hearthstone.exe",
|
|
3957
|
+
1
|
|
3958
|
+
};
|
|
3959
|
+
|
|
3960
|
+
static const TEST_EXTRA_PATCHES PatchH6898 =
|
|
3961
|
+
{
|
|
3962
|
+
PatchList,
|
|
3963
|
+
_T("hs-0-5314-Win-final.MPQ\0")
|
|
3964
|
+
_T("hs-5314-5435-Win-final.MPQ\0")
|
|
3965
|
+
_T("hs-5435-5506-Win-final.MPQ\0")
|
|
3966
|
+
_T("hs-5506-5834-Win-final.MPQ\0")
|
|
3967
|
+
_T("hs-5834-6024-Win-final.MPQ\0")
|
|
3968
|
+
_T("hs-6024-6141-Win-final.MPQ\0")
|
|
3969
|
+
_T("hs-6141-6187-Win-final.MPQ\0")
|
|
3970
|
+
_T("hs-6187-6284-Win-final.MPQ\0")
|
|
3971
|
+
_T("hs-6284-6485-Win-final.MPQ\0")
|
|
3972
|
+
_T("hs-6485-6898-Win-final.MPQ\0"),
|
|
3973
|
+
"Hearthstone_Data\\Managed\\Assembly-Csharp.dll",
|
|
3974
|
+
10
|
|
3975
|
+
};
|
|
3976
|
+
|
|
3977
|
+
static const TEST_INFO1 TestList_StreamOps[] =
|
|
3978
|
+
{
|
|
3979
|
+
{_T("MPQ_2013_v4_alternate-original.MPQ"), NULL, NULL, 0},
|
|
3980
|
+
{_T("MPQ_2013_v4_alternate-original.MPQ"), NULL, NULL, STREAM_FLAG_READ_ONLY},
|
|
3981
|
+
{_T("MPQ_2013_v4_alternate-complete.MPQ"), NULL, NULL, STREAM_FLAG_USE_BITMAP},
|
|
3982
|
+
{_T("part-file://MPQ_2009_v2_WoW_patch.MPQ.part"), NULL, NULL, 0},
|
|
3983
|
+
{_T("blk4-file://streaming/model.MPQ.0"), NULL, NULL, STREAM_PROVIDER_BLOCK4},
|
|
3984
|
+
{_T("mpqe-file://MPQ_2011_v2_EncryptedMpq.MPQE"), NULL, NULL, STREAM_PROVIDER_MPQE}
|
|
3985
|
+
};
|
|
3986
|
+
|
|
3987
|
+
static const TEST_INFO1 TestList_MasterMirror[] =
|
|
3988
|
+
{
|
|
3989
|
+
{_T("part-file://MPQ_2009_v1_patch-created.MPQ.part"), _T("MPQ_2009_v1_patch-original.MPQ"), NULL, 0},
|
|
3990
|
+
{_T("part-file://MPQ_2009_v1_patch-partial.MPQ.part"), _T("MPQ_2009_v1_patch-original.MPQ"), NULL, 1},
|
|
3991
|
+
{_T("part-file://MPQ_2009_v1_patch-complete.MPQ.part"), _T("MPQ_2009_v1_patch-original.MPQ"), NULL, 1},
|
|
3992
|
+
{_T("MPQ_2013_v4_alternate-created.MPQ"), _T("MPQ_2013_v4_alternate-original.MPQ"), NULL, 0},
|
|
3993
|
+
{_T("MPQ_2013_v4_alternate-incomplete.MPQ"), _T("MPQ_2013_v4_alternate-incomplete.MPQ"), NULL, 1},
|
|
3994
|
+
{_T("MPQ_2013_v4_alternate-complete.MPQ"), _T("MPQ_2013_v4_alternate-original.MPQ"), NULL, 1},
|
|
3995
|
+
|
|
3996
|
+
// Takes hell a lot of time!!!
|
|
3997
|
+
// {_T("MPQ_2013_v4_alternate-downloaded.MPQ"), _T("http://www.zezula.net\\mpqs\\alternate.zip"), NULL, 0}
|
|
3998
|
+
};
|
|
3999
|
+
|
|
4000
|
+
static const TEST_INFO1 Test_OpenMpqs[] =
|
|
4001
|
+
{
|
|
4002
|
+
|
|
4003
|
+
// PoC's by Gabe Sherman from FuturesLab
|
|
4004
|
+
{_T("pocs/MPQ_2024_01_HeapOverrun.mpq"), NULL, "7008f95dcbc4e5d840830c176dec6969", 14},
|
|
4005
|
+
{_T("pocs/MPQ_2024_02_StackOverflow.mpq"), NULL, "7093fcbcc9674b3e152e74e8e8a937bb", 4},
|
|
4006
|
+
{_T("pocs/MPQ_2024_03_TooBigAlloc.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
|
|
4007
|
+
{_T("pocs/MPQ_2024_04_HeapOverflow.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
|
|
4008
|
+
{_T("pocs/MPQ_2024_05_HeapOverflow.mpq"), NULL, "0539ae020719654a0ea6e2627a8195f8", 14},
|
|
4009
|
+
{_T("pocs/MPQ_2024_06_HeapOverflowReadFile.mpq"), NULL, "d41d8cd98f00b204e9800998ecf8427e", 1},
|
|
4010
|
+
{_T("pocs/MPQ_2024_07_InvalidBitmapFooter.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
|
|
4011
|
+
{_T("pocs/MPQ_2024_08_InvalidSectorSize.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
|
|
4012
|
+
{_T("pocs/MPQ_2024_09_InvalidSectorSize.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
|
|
4013
|
+
{_T("pocs/MPQ_2024_10_HuffDecompressError.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
|
|
4014
|
+
{_T("pocs/MPQ_2024_10_SparseDecompressError.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
|
|
4015
|
+
{_T("pocs/MPQ_2024_11_HiBlockTablePosInvalid.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
|
|
4016
|
+
|
|
4017
|
+
// Correct or damaged archives
|
|
4018
|
+
{_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"), NULL, "554b538541e42170ed41cb236483489e", 2910, &TwoFilesD1}, // Base MPQ from Diablo 1
|
|
4019
|
+
{_T("MPQ_1997_v1_patch_rt_SC1B.mpq"), NULL, "43fe7d362955be68a708486e399576a7", 10}, // From Starcraft 1 BETA
|
|
4020
|
+
{_T("MPQ_1997_v1_StarDat_SC1B.mpq"), NULL, "0094b23f28cfff7386071ef3bd19a577", 2468}, // From Starcraft 1 BETA
|
|
4021
|
+
{_T("MPQ_1997_v1_INSTALL_SC1B.EXE_"), NULL, "3248460c89bb6f8e3b8fc3e08de7ffbb", 79}, // From Starcraft 1 BETA
|
|
4022
|
+
{_T("MPQ_2016_v1_D2XP_IX86_1xx_114a.mpq"), NULL, "255d87a62f3c9518f72cf723a1818946", 221, &TwoFilesD2}, // Update MPQ from Diablo II (patch 2016)
|
|
4023
|
+
{_T("MPQ_2018_v1_icon_error.w3m"), NULL, "fcefa25fb50c391e8714f2562d1e10ff", 19, &TwoFilesW3M},
|
|
4024
|
+
{_T("MPQ_1997_v1_Diablo1_STANDARD.SNP"), NULL, "5ef18ef9a26b5704d8d46a344d976c89", 2, &LfBliz}, // File whose archive's (signature) file has flags = 0x90000000
|
|
4025
|
+
{_T("MPQ_2012_v2_EmptyMpq.MPQ"), NULL, "00000000000000000000000000000000", 0}, // Empty archive (found in WoW cache - it's just a header)
|
|
4026
|
+
{_T("MPQ_2013_v4_EmptyMpq.MPQ"), NULL, "00000000000000000000000000000000", 0}, // Empty archive (created artificially - it's just a header)
|
|
4027
|
+
{_T("MPQ_2013_v4_patch-base-16357.MPQ"), NULL, "d41d8cd98f00b204e9800998ecf8427e", 1}, // Empty archive (found in WoW cache - it's just a header)
|
|
4028
|
+
{_T("MPQ_2011_v4_InvalidHetEntryCount.MPQ"), NULL, "be4b49ecc3942d1957249f9da0021659", 6}, // Empty archive (with invalid HET entry count)
|
|
4029
|
+
{_T("MPQ_2002_v1_BlockTableCut.MPQ"), NULL, "a9499ab74d939303d8cda7c397c36275", 287}, // Truncated archive
|
|
4030
|
+
{_T("MPQ_2010_v2_HasUserData.s2ma"), NULL, "feff9e2c86db716b6ff5ffc906181200", 52}, // MPQ that actually has user data
|
|
4031
|
+
{_T("MPQ_2014_v1_AttributesOneEntryLess.w3x"), NULL, "90451b7052eb0f1d6f4bf69b2daff7f5", 116}, // Warcraft III map whose "(attributes)" file has (BlockTableSize-1) entries
|
|
4032
|
+
{_T("MPQ_2020_v1_AHF04patch.mix"), NULL, "d3c6aac48bc12813ef5ce4ad113e58bf", 2891}, // MIX file
|
|
4033
|
+
{_T("MPQ_2010_v3_expansion-locale-frFR.MPQ"), NULL, "0c8fc921466f07421a281a05fad08b01", 53}, // MPQ archive v 3.0 (the only one I know)
|
|
4034
|
+
{_T("mpqe-file://MPQ_2011_v2_EncryptedMpq.MPQE"), NULL, "10e4dcdbe95b7ad731c563ec6b71bc16", 82}, // Encrypted archive from Starcraft II installer
|
|
4035
|
+
{_T("part-file://MPQ_2010_v2_HashTableCompressed.MPQ.part"),NULL, "d41d8cd98f00b204e9800998ecf8427e", 14263}, // Partial MPQ with compressed hash table
|
|
4036
|
+
{_T("blk4-file://streaming/model.MPQ.0"), NULL, "e06b00efb2fc7e7469dd8b3b859ae15d", 39914}, // Archive that is merged with multiple files
|
|
4037
|
+
{_T("MPQ_2023_v2_MemoryCorruption.SC2Replay"), NULL, "4cf5021aa272298e64712a378a50df44", 10}, // MPQ archive v 2.0, archive size is wrong
|
|
4038
|
+
{_T("MPQ_2023_v1_StarcraftMap.scm"), NULL, "7830c51700697dd3c175f086a3157b29", 4}, // StarCraft map from StarCraft: Brood War 1.16
|
|
4039
|
+
{_T("MPQ_2023_v1_BroodWarMap.scx"), NULL, "dd3afa3c2f5e562ce3ca91c0c605a71f", 3}, // Brood War map from StarCraft: Brood War 1.16
|
|
4040
|
+
{_T("MPQ_2023_v1_Volcanis.scm"), NULL, "522c89ca96d6736427b01f7c80dd626f", 3}, // Map modified with unusual file compression: ZLIB+Huffman
|
|
4041
|
+
{_T("MPQ_2023_v4_UTF8.s2ma"), NULL, "97b7a686650f3307d135e1d1b017a36a", 67}, // Map contaning files with Chinese names (UTF8-encoded)
|
|
4042
|
+
{_T("MPQ_2023_v1_GreenTD.w3x"), NULL, "a8d91fc4e52d7c21ff7feb498c74781a", 2004}, // Corrupt sector checksum table in file #A0
|
|
4043
|
+
{_T("MPQ_2023_v4_1F644C5A.SC2Replay"), NULL, "b225828ffbf5037553e6a1290187caab", 17}, // Corrupt patch info of the "(attributes)" file
|
|
4044
|
+
{_T("<Chinese MPQ name>"), NULL, "67faeffd0c0aece205ac8b7282d8ad8e", 4697, &MpqUtf8}, // Chinese name of the MPQ
|
|
4045
|
+
|
|
4046
|
+
// Protected archives
|
|
4047
|
+
{_T("MPQ_2002_v1_ProtectedMap_InvalidUserData.w3x"), NULL, "b900364cc134a51ddeca21a13697c3ca", 79},
|
|
4048
|
+
{_T("MPQ_2002_v1_ProtectedMap_InvalidMpqFormat.w3x"), NULL, "db67e894da9de618a1cdf86d02d315ff", 117},
|
|
4049
|
+
{_T("MPQ_2002_v1_ProtectedMap_Spazzler.w3x"), NULL, "72d7963aa799a7fb4117c55b7beabaf9", 470}, // Warcraft III map locked by the Spazzler protector
|
|
4050
|
+
{_T("MPQ_2014_v1_ProtectedMap_Spazzler2.w3x"), NULL, "72d7963aa799a7fb4117c55b7beabaf9", 470}, // Warcraft III map locked by the Spazzler protector
|
|
4051
|
+
{_T("MPQ_2014_v1_ProtectedMap_Spazzler3.w3x"), NULL, "e55aad2dd33cf68b372ca8e30dcb78a7", 130}, // Warcraft III map locked by the Spazzler protector
|
|
4052
|
+
{_T("MPQ_2002_v1_ProtectedMap_BOBA.w3m"), NULL, "7b725d87e07a2173c42fe2314b95fa6c", 17}, // Warcraft III map locked by the BOBA protector
|
|
4053
|
+
{_T("MPQ_2015_v1_ProtectedMap_KangTooJee.w3x"), NULL, "44111a3edf7645bc44bb1afd3a813576", 1715},
|
|
4054
|
+
{_T("MPQ_2015_v1_ProtectedMap_Somj2hM16.w3x"), NULL, "b411f9a51a6e9a9a509150c8d66ba359", 92},
|
|
4055
|
+
{_T("MPQ_2015_v1_ProtectedMap_Spazy.w3x"), NULL, "6e491bd055511435dcb4d9c8baed0516", 4089}, // Warcraft III map locked by Spazy protector
|
|
4056
|
+
{_T("MPQ_2015_v1_MessListFile.mpq"), NULL, "15e25d5be124d8ad71519f967997efc2", 8},
|
|
4057
|
+
{_T("MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x"), NULL, "ad81b43cbd37bbfa27e4bed4c17e6a81", 176},
|
|
4058
|
+
{_T("MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x"), NULL, "d6e712c275a26dc51f16b3a02f6187df", 228},
|
|
4059
|
+
{_T("MPQ_2016_v1_ProtectedMap_Somj2.w3x"), NULL, "457cdbf97a9ca41cfe8ea130dafaa0bb", 21}, // Something like Somj 2.0
|
|
4060
|
+
{_T("MPQ_2016_v1_WME4_4.w3x"), NULL, "7ec2f4d0f3982d8b12d88bc08ef0c1fb", 640}, // Protector from China (2016-05-27)
|
|
4061
|
+
{_T("MPQ_2016_v1_SP_(4)Adrenaline.w3x"), NULL, "b6f6d56f4f8aaef04c2c4b1f08881a8b", 16},
|
|
4062
|
+
{_T("MPQ_2016_v1_ProtectedMap_1.4.w3x"), NULL, "3c7908b29d3feac9ec952282390a242d", 5027},
|
|
4063
|
+
{_T("MPQ_2016_v1_KoreanFile.w3m"), NULL, "805d1f75712472a81c6df27b2a71f946", 18},
|
|
4064
|
+
{_T("MPQ_2017_v1_Eden_RPG_S2_2.5J.w3x"), NULL, "cbe1fd7ed5ed2fc005fba9beafcefe40", 16334}, // Protected by PG1.11.973
|
|
4065
|
+
{_T("MPQ_2017_v1_BigDummyFiles.w3x"), NULL, "f4d2ee9d85d2c4107e0b2d00ff302dd7", 9086},
|
|
4066
|
+
{_T("MPQ_2017_v1_TildeInFileName.mpq"), NULL, "f203e3979247a4dbf7f3828695ac810c", 5},
|
|
4067
|
+
{_T("MPQ_2018_v1_EWIX_v8_7.w3x"), NULL, "12c0f4e15c7361b7c13acd37a181d83b", 857, &TwoFilesW3X},
|
|
4068
|
+
{_T("MPQ_2020_v4_FakeMpqHeaders.SC2Mod"), NULL, "f45392f6523250c943990a017c230b41", 24}, // Archive that has two fake headers before the real one
|
|
4069
|
+
{_T("MPQ_2020_v4_NP_Protect_1.s2ma"), NULL, "1a1ea40ac1165bcdb4f2e434edfc7636", 21}, // SC2 map that is protected by the NP_Protect
|
|
4070
|
+
{_T("MPQ_2020_v4_NP_Protect_2.s2ma"), NULL, "7d1a379da8bd966da1f4fa6e4646049b", 55}, // SC2 map that is protected by the NP_Protect
|
|
4071
|
+
{_T("MPQ_2015_v1_flem1.w3x"), NULL, "1c4c13e627658c473e84d94371e31f37", 20},
|
|
4072
|
+
{_T("MPQ_2002_v1_ProtectedMap_HashTable_FakeValid.w3x"), NULL, "5250975ed917375fc6540d7be436d4de", 114},
|
|
4073
|
+
{_T("MPQ_2021_v1_CantExtractCHK.scx"), NULL, "055fd548a789c910d9dd37472ecc1e66", 28},
|
|
4074
|
+
{_T("MPQ_2022_v1_Sniper.scx"), NULL, "2e955271b70b79344ad85b698f6ce9d8", 64}, // Multiple items in hash table for staredit\scenario.chk (locale=0, platform=0)
|
|
4075
|
+
{_T("MPQ_2022_v1_OcOc_Bound_2.scx"), NULL, "25cad16a2fb4e883767a1f512fc1dce7", 16},
|
|
4076
|
+
{_T("MPQ_2023_v1_Lusin2Rpg1.28.w3x"), NULL, "9c21352f06cf763fcf05e8a2691e6194", 10305, &HashVals},
|
|
4077
|
+
{_T("MPQ_2024_v1_300TK2.09p.w3x"), NULL, "e442e3d2e7d457b9ba544544013b791f", 32588}, // Fake MPQ User data, fake MPQ header at offset 0x200
|
|
4078
|
+
|
|
4079
|
+
// ASI plugins
|
|
4080
|
+
{_T("MPQ_2020_v1_HS0.1.asi"), NULL, "50cba7460a6e6d270804fb9776a7ec4f", 6022},
|
|
4081
|
+
{_T("MPQ_2022_v1_hs0.8.asi"), NULL, "6a40f733428001805bfe6e107ca9aec1", 11352}, // Items in hash table have platform = 0xFF
|
|
4082
|
+
{_T("MPQ_2022_v1_MoeMoeMod.asi"), NULL, "89b923c7cde06de48815844a5bbb0ec4", 2578},
|
|
4083
|
+
|
|
4084
|
+
// MPQ modifications from Chinese games
|
|
4085
|
+
{_T("MPx_2013_v1_LongwuOnline.mpk"), NULL, "548f7db88284097f7e94c95a08c5bc24", 469}, // MPK archive from Longwu online
|
|
4086
|
+
{_T("MPx_2013_v1_WarOfTheImmortals.sqp"), NULL, "a048f37f7c6162a96253d8081722b6d9", 9396, &LfWotI}, // SQP archive from War of the Immortals
|
|
4087
|
+
{_T("MPx_2022_v1_Music.mpk"), NULL, "fc369cff4ff4b573dd024de963e4cdd5", 650}, // MPK archive from Warriors of the Ghost Valley
|
|
4088
|
+
{_T("MPx_2022_v1_Scp.mpk"), NULL, "9cb453dc159f2e667c14f48957fd9e77", 113}, // MPK archive from Warriors of the Ghost Valley
|
|
4089
|
+
{_T("MPx_2022_v1_UI.mpk"), NULL, "677a36b458d528a3158ced3dfb711e49", 3086}, // MPK archive from Warriors of the Ghost Valley
|
|
4090
|
+
|
|
4091
|
+
// Patched MPQs
|
|
4092
|
+
{_T("MPQ_1998_v1_StarCraft.mpq"), NULL, "5ecef2f41c5fd44c264e269416de9495", 1943, &PatchSC1}, // Patched MPQ from StarCraft I
|
|
4093
|
+
{_T("MPQ_2012_v4_OldWorld.MPQ"), NULL, "07643ec62864b4dd4fc8f8a6a16ce006", 71439, &Patch13286}, // WoW 13286: Patched "OldWorld.MPQ"
|
|
4094
|
+
{_T("MPQ_2013_v4_world.MPQ"), NULL, "af9baeceab20139bbf94d03f99170ae0", 48930, &Patch15050}, // WoW 15050: Patched "world.MPQ"
|
|
4095
|
+
{_T("MPQ_2013_v4_locale-enGB.MPQ"), NULL, "d39e743aaf6dad51d643d65e6e564804", 14349, &Patch16965}, // WoW 16965: Patched "locale-enGB.MPQ"
|
|
4096
|
+
{_T("MPQ_2013_v4_Base1.SC2Data"), NULL, "28a0f3cff1f400feb268ddae0efb2985", 1459, &Patch32283}, // SC2 32283: Patched "Base1.SC2Data"
|
|
4097
|
+
{_T("MPQ_2013_v4_Mods#Core.SC2Mod#enGB.SC2Assets"), NULL, "89df7ddac15700721b3f4c37d2673c1f", 11, &Patch32283a},// SC2 32283: Patched "Mods#Core.SC2Mod#enGB.SC2Assets"
|
|
4098
|
+
{_T("MPQ_2013_v4_Base1.SC2Data"), NULL, "7b65d0a3c3c0e67e4c61f53f277e5ae7", 1459, &Patch34644}, // SC2 34644: Patched "Base1.SC2Data"
|
|
4099
|
+
{_T("MPQ_2013_v4_Base3.SC2Maps"), NULL, "831ed96de221b4018d4bc9e09593c540", 2080, &Patch34644m},// SC2 34644: Patched "Base3.SC2Maps"
|
|
4100
|
+
{_T("MPQ_2013_v4_Mods#Liberty.SC2Mod#enGB.SC2Data"), NULL, "fde3842552c1a9cd5ceee0e571227d18", 17, &Patch36281}, // SC2 36281: Patched "Mods#Liberty.SC2Mod#enGB.SC2Data"
|
|
4101
|
+
{_T("MPQ_2014_v4_base-Win.MPQ"), NULL, "337b609b2469a6732f2837eae8f730a4", 207, &PatchH3604}, // HSTN 3604: Patched "base-Win.MPQ"
|
|
4102
|
+
{_T("MPQ_2014_v4_base-Win.MPQ"), NULL, "28c3447bdc6b221b5cb346123ea03a94", 234, &PatchH6898}, // HSTN 6898: Patched "base-Win.MPQ"
|
|
4103
|
+
|
|
4104
|
+
// Signed archives
|
|
4105
|
+
{_T("MPQ_1997_v1_Diablo1_STANDARD.SNP"), szSigned1, "5ef18ef9a26b5704d8d46a344d976c89", 2 | TFLG_SIGCHECK_BEFORE},
|
|
4106
|
+
{_T("MPQ_1999_v1_WeakSignature.exe"), szSigned2, "c1084033d0bd5f7e2b9b78b600c0bba8", 24 | TFLG_SIGCHECK_BEFORE},
|
|
4107
|
+
{_T("MPQ_2003_v1_WeakSignatureEmpty.exe"), szSigned3, "97580f9f6d98ffc50191c2f07773e818", 12259 | TFLG_SIGCHECK_BEFORE},
|
|
4108
|
+
{_T("MPQ_2002_v1_StrongSignature.w3m"), szSigned4, "7b725d87e07a2173c42fe2314b95fa6c", 17 | TFLG_SIGCHECK_BEFORE},
|
|
4109
|
+
{_T("MPQ_1998_v1_StarDat.mpq"), _T("MPQ_1998_v1_StarDat.mpq"), "2530cb937565fd41b1dc0443697096a2", 2925 | TFLG_SIGN_ARCHIVE | TFLG_SIGCHECK_AFTER},
|
|
4110
|
+
{_T("MPQ_1999_v1_WeakSignature.exe"), szSigned2, "807fe2e4d38eccf5ee6bc88f5ee5940d", 25 | TFLG_SIGCHECK_BEFORE | TFLG_MODIFY | TFLG_SIGCHECK_AFTER},
|
|
4111
|
+
|
|
4112
|
+
// Multi-file archive with wrong prefix to see how StormLib deals with it
|
|
4113
|
+
{_T("flat-file://streaming/model.MPQ.0"), _T("flat-file://model.MPQ.0"), NULL, 0 | TFLG_WILL_FAIL},
|
|
4114
|
+
|
|
4115
|
+
// An archive that has been invalidated by extending an old valid MPQ
|
|
4116
|
+
{_T("MPQ_2013_vX_Battle.net.MPQ"), NULL, NULL, 0 | TFLG_WILL_FAIL},
|
|
4117
|
+
|
|
4118
|
+
// Check whether read-only archive fails with update
|
|
4119
|
+
{_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"), NULL, "554b538541e42170ed41cb236483489e", 2910 | TFLG_READ_ONLY | TFLG_MODIFY | TFLG_WILL_FAIL},
|
|
4120
|
+
{_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"), szDiabdatMPQ, "84fcb4aefbd0deac5b5159ec11922dbf", 2911 | TFLG_MODIFY},
|
|
4121
|
+
|
|
4122
|
+
// Check the GetFileInfo operations
|
|
4123
|
+
{_T("MPQ_2002_v1_StrongSignature.w3m"), NULL, "7b725d87e07a2173c42fe2314b95fa6c", 17 | TFLG_GET_FILE_INFO},
|
|
4124
|
+
{_T("MPQ_2013_v4_SC2_EmptyMap.SC2Map"), NULL, "88e1b9a88d56688c9c24037782b7bb68", 33 | TFLG_GET_FILE_INFO},
|
|
4125
|
+
|
|
4126
|
+
};
|
|
4127
|
+
|
|
4128
|
+
static const TEST_INFO1 Test_ReopenMpqs[] =
|
|
4129
|
+
{
|
|
4130
|
+
// Test the archive compacting feature
|
|
4131
|
+
{_T("MPQ_2010_v3_expansion-locale-frFR.MPQ"), NULL, "0c8fc921466f07421a281a05fad08b01", 53 | TFLG_COMPACT | TFLG_ADD_USER_DATA | TFLG_HAS_LISTFILE | TFLG_HAS_ATTRIBUTES},
|
|
4132
|
+
{_T("MPQ_2016_v1_00000.pak"), NULL, "76c5c4dffee8a9e3568e22216b5f0b94", 2072 | TFLG_COMPACT | TFLG_HAS_LISTFILE},
|
|
4133
|
+
{_T("MPQ_2013_v4_SC2_EmptyMap.SC2Map"), NULL, "88e1b9a88d56688c9c24037782b7bb68", 33 | TFLG_COMPACT | TFLG_ADD_USER_DATA | TFLG_HAS_LISTFILE | TFLG_HAS_ATTRIBUTES},
|
|
4134
|
+
{_T("MPQ_2013_v4_expansion1.MPQ"), NULL, "c97d2b4e2561d3eb3a728d72a74d86c2", 15633 | TFLG_COMPACT | TFLG_ADD_USER_DATA | TFLG_HAS_LISTFILE | TFLG_HAS_ATTRIBUTES},
|
|
4135
|
+
|
|
4136
|
+
// Adding a file to MPQ that had size of the file table equal
|
|
4137
|
+
// or greater than hash table, but has free entries
|
|
4138
|
+
{_T("MPQ_2014_v1_out1.w3x"), NULL, "222e685bd76e1af6d267ea1e0c27371f", 39 | TFLG_MODIFY | TFLG_HAS_LISTFILE},
|
|
4139
|
+
{_T("MPQ_2014_v1_out2.w3x"), NULL, "514ab40dc72fc29965cc30b2e0d63674", 34 | TFLG_MODIFY | TFLG_HAS_LISTFILE},
|
|
4140
|
+
|
|
4141
|
+
// Adding a file to MPQ and testing that (listfile) and (attributes) has the same state like before
|
|
4142
|
+
{_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"), NULL, "554b538541e42170ed41cb236483489e", 2910 | TFLG_MODIFY},
|
|
4143
|
+
{_T("MPQ_2013_v4_SC2_EmptyMap.SC2Map"), NULL, "88e1b9a88d56688c9c24037782b7bb68", 33 | TFLG_MODIFY | TFLG_HAS_LISTFILE | TFLG_HAS_ATTRIBUTES},
|
|
4144
|
+
|
|
4145
|
+
// Adding a large file to archive version 1. This must fail
|
|
4146
|
+
{_T("MPQ_2002_v1_LargeMapFile.w3m"), NULL, "2f302705280f0cf9da50ac10e3d71522", 22 | TFLG_MODIFY | TFLG_HAS_LISTFILE | TFLG_HAS_ATTRIBUTES | TFLG_BIGFILE | TFLG_WILL_FAIL}
|
|
4147
|
+
};
|
|
4148
|
+
|
|
4149
|
+
// Tests for signature file
|
|
4150
|
+
static const TEST_INFO1 Test_Signature[] =
|
|
4151
|
+
{
|
|
4152
|
+
{_T("MPQ_1999_v1_WeakSigned1.mpq"), NULL, NULL, SFLAG_CREATE_ARCHIVE | SFLAG_SIGN_AT_CREATE | SFLAG_MODIFY_ARCHIVE | SFLAG_SIGN_ARCHIVE | SFLAG_VERIFY_AFTER},
|
|
4153
|
+
{_T("MPQ_1999_v1_WeakSigned1.mpq"), NULL, NULL, SFLAG_CREATE_ARCHIVE | SFLAG_MODIFY_ARCHIVE | SFLAG_SIGN_ARCHIVE | SFLAG_VERIFY_AFTER},
|
|
4154
|
+
};
|
|
4155
|
+
|
|
4156
|
+
static const TEST_INFO1 Test_ReplaceFile[] =
|
|
4157
|
+
{
|
|
4158
|
+
{_T("MPQ_2014_v4_Base.StormReplay"), _T("replay.message.events"), (LPCSTR)(MPQ_FILE_SINGLE_UNIT), MPQ_COMPRESSION_ZLIB},
|
|
4159
|
+
{_T("MPQ_2022_v1_v4.329.w3x"), _T("war3map.j"), (LPCSTR)(MPQ_FILE_SINGLE_UNIT), MPQ_COMPRESSION_ZLIB},
|
|
4160
|
+
{_T("MPQ_2023_v1_StarcraftMap.scm"), _T("staredit#scenario.chk"), NULL, MPQ_COMPRESSION_ZLIB | MPQ_COMPRESSION_HUFFMANN},
|
|
4161
|
+
};
|
|
4162
|
+
|
|
4163
|
+
static const TEST_INFO2 Test_CreateMpqs[] =
|
|
4164
|
+
{
|
|
4165
|
+
// Create empty MPQs containing nothing
|
|
4166
|
+
{"EmptyMpq_v2.mpq", NULL, NULL, CFLG_V2 | CFLG_EMPTY},
|
|
4167
|
+
{"EmptyMpq_v4.mpq", NULL, NULL, CFLG_V4 | CFLG_EMPTY},
|
|
4168
|
+
|
|
4169
|
+
// Create empty MPQs with localized names
|
|
4170
|
+
{(LPCSTR)szPlainName_CZE, NULL, NULL, CFLG_V2 | 15}, // (UTF-8) Czech
|
|
4171
|
+
{(LPCSTR)szPlainName_RUS, NULL, NULL, CFLG_V2 | 58}, // (UTF-8) Russian
|
|
4172
|
+
{(LPCSTR)szPlainName_GRC, NULL, NULL, CFLG_V2 | 15874}, // (UTF-8) Greek
|
|
4173
|
+
{(LPCSTR)szPlainName_CHN, NULL, NULL, CFLG_V4 | 87541}, // (UTF-8) Chinese
|
|
4174
|
+
{(LPCSTR)szPlainName_JPN, NULL, NULL, CFLG_V4 | 87541}, // (UTF-8) Japanese
|
|
4175
|
+
{(LPCSTR)szPlainName_SAU, NULL, NULL, CFLG_V4 | 87541}, // (UTF-8) Arabic
|
|
4176
|
+
|
|
4177
|
+
// Create archive containing files with non-std names
|
|
4178
|
+
{"NonStdNames.mpq", NULL, NULL, CFLG_NONSTD_NAMES | 4000},
|
|
4179
|
+
|
|
4180
|
+
// Test creating of an archive the same way like MPQ Editor does
|
|
4181
|
+
{"MpqEditorTest.mpq", "AddedFile.exe", NULL, CFLG_V2 | CFLG_MPQEDITOR | 4000},
|
|
4182
|
+
};
|
|
4183
|
+
|
|
4184
|
+
static const LPCSTR Test_CreateMpq_Localized[] =
|
|
4185
|
+
{
|
|
4186
|
+
(LPCSTR)szPlainName_CZE, // (UTF-8) Czech
|
|
4187
|
+
(LPCSTR)szPlainName_RUS, // (UTF-8) Russian
|
|
4188
|
+
(LPCSTR)szPlainName_GRC, // (UTF-8) Greek
|
|
4189
|
+
(LPCSTR)szPlainName_CHN, // (UTF-8) Chinese
|
|
4190
|
+
(LPCSTR)szPlainName_JPN, // (UTF-8) Japanese
|
|
4191
|
+
(LPCSTR)szPlainName_SAU // (UTF-8) Arabic
|
|
4192
|
+
};
|
|
4193
|
+
|
|
4194
|
+
//-----------------------------------------------------------------------------
|
|
4195
|
+
// Main
|
|
4196
|
+
|
|
4197
|
+
#define TEST_COMMAND_LINE
|
|
4198
|
+
#define TEST_LOCAL_LISTFILE
|
|
4199
|
+
#define TEST_STREAM_OPERATIONS
|
|
4200
|
+
#define TEST_MASTER_MIRROR
|
|
4201
|
+
#define TEST_OPEN_MPQ
|
|
4202
|
+
#define TEST_REOPEN_MPQ
|
|
4203
|
+
#define TEST_VERIFY_SIGNATURE
|
|
4204
|
+
#define TEST_REPLACE_FILE
|
|
4205
|
+
#define TEST_VERIFY_HASHES
|
|
4206
|
+
#define TEST_CREATE_MPQS
|
|
4207
|
+
|
|
4208
|
+
int _tmain(int argc, TCHAR * argv[])
|
|
4209
|
+
{
|
|
4210
|
+
DWORD dwErrCode = ERROR_SUCCESS;
|
|
4211
|
+
|
|
4212
|
+
#if defined(_MSC_VER) && defined(_DEBUG)
|
|
4213
|
+
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
|
4214
|
+
#endif // defined(_MSC_VER) && defined(_DEBUG)
|
|
4215
|
+
|
|
4216
|
+
// Initialize storage and mix the random number generator
|
|
4217
|
+
printf("==== Test Suite for StormLib version %s ====\n", STORMLIB_VERSION_STRING);
|
|
4218
|
+
dwErrCode = InitializeMpqDirectory(argv, argc);
|
|
4219
|
+
|
|
4220
|
+
// Placeholder function for various testing purposes
|
|
4221
|
+
Test_PlayingSpace();
|
|
4222
|
+
|
|
4223
|
+
#ifdef TEST_COMMAND_LINE
|
|
4224
|
+
// Test-open MPQs from the command line. They must be plain name
|
|
4225
|
+
// and must be placed in the Test-MPQs folder
|
|
4226
|
+
for(int i = 2; i < argc; i++)
|
|
4227
|
+
{
|
|
4228
|
+
TestOpenArchive(argv[i], NULL, NULL, 0, &LfBliz);
|
|
4229
|
+
}
|
|
4230
|
+
#endif // TEST_COMMAND_LINE
|
|
4231
|
+
|
|
4232
|
+
#ifdef TEST_LOCAL_LISTFILE // Tests on a local listfile
|
|
4233
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4234
|
+
{
|
|
4235
|
+
TestOnLocalListFile(_T("FLAT-MAP:listfile-test.txt"));
|
|
4236
|
+
dwErrCode = TestOnLocalListFile(_T("listfile-test.txt"));
|
|
4237
|
+
}
|
|
4238
|
+
#endif // TEST_LOCAL_LISTFILE
|
|
4239
|
+
|
|
4240
|
+
#ifdef TEST_STREAM_OPERATIONS // Test file stream operations
|
|
4241
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4242
|
+
{
|
|
4243
|
+
for(size_t i = 0; i < _countof(TestList_StreamOps); i++)
|
|
4244
|
+
{
|
|
4245
|
+
dwErrCode = TestFileStreamOperations(TestList_StreamOps[i].szName1, TestList_StreamOps[i].dwFlags);
|
|
4246
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
4247
|
+
break;
|
|
4248
|
+
}
|
|
4249
|
+
}
|
|
4250
|
+
#endif // TEST_STREAM_OPERATIONS
|
|
4251
|
+
|
|
4252
|
+
#ifdef TEST_MASTER_MIRROR // Test master-mirror reading operations
|
|
4253
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4254
|
+
{
|
|
4255
|
+
for(size_t i = 0; i < _countof(TestList_MasterMirror); i++)
|
|
4256
|
+
{
|
|
4257
|
+
dwErrCode = TestReadFile_MasterMirror(TestList_MasterMirror[i].szName1,
|
|
4258
|
+
TestList_MasterMirror[i].szName2,
|
|
4259
|
+
TestList_MasterMirror[i].dwFlags != 0);
|
|
4260
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
4261
|
+
break;
|
|
4262
|
+
}
|
|
4263
|
+
}
|
|
4264
|
+
#endif // TEST_MASTER_MIRROR
|
|
4265
|
+
|
|
4266
|
+
#ifdef TEST_OPEN_MPQ // Test opening various archives - correct, damaged, protected
|
|
4267
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4268
|
+
{
|
|
4269
|
+
for(size_t i = 0; i < _countof(Test_OpenMpqs); i++)
|
|
4270
|
+
{
|
|
4271
|
+
dwErrCode = TestOpenArchive(Test_OpenMpqs[i]);
|
|
4272
|
+
dwErrCode = ERROR_SUCCESS;
|
|
4273
|
+
}
|
|
4274
|
+
}
|
|
4275
|
+
#endif // TEST_OPEN_MPQ
|
|
4276
|
+
|
|
4277
|
+
#ifdef TEST_REOPEN_MPQ // Test operations involving reopening the archive
|
|
4278
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4279
|
+
{
|
|
4280
|
+
for(size_t i = 0; i < _countof(Test_ReopenMpqs); i++)
|
|
4281
|
+
{
|
|
4282
|
+
// Ignore the error code here; we want to see results of all opens
|
|
4283
|
+
dwErrCode = TestReopenArchive(Test_ReopenMpqs[i].szName1,
|
|
4284
|
+
Test_ReopenMpqs[i].szDataHash,
|
|
4285
|
+
Test_ReopenMpqs[i].dwFlags);
|
|
4286
|
+
dwErrCode = ERROR_SUCCESS;
|
|
4287
|
+
}
|
|
4288
|
+
}
|
|
4289
|
+
#endif
|
|
4290
|
+
|
|
4291
|
+
#ifdef TEST_VERIFY_SIGNATURE // Verify digital signatures of the archives
|
|
4292
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4293
|
+
{
|
|
4294
|
+
for(size_t i = 0; i < _countof(Test_Signature); i++)
|
|
4295
|
+
{
|
|
4296
|
+
// Ignore the error code here; we want to see results of all opens
|
|
4297
|
+
dwErrCode = TestOpenArchive_SignatureTest(Test_Signature[i].szName1,
|
|
4298
|
+
Test_Signature[i].szName1,
|
|
4299
|
+
Test_Signature[i].dwFlags);
|
|
4300
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
4301
|
+
break;
|
|
4302
|
+
}
|
|
4303
|
+
}
|
|
4304
|
+
#endif
|
|
4305
|
+
|
|
4306
|
+
#ifdef TEST_REPLACE_FILE // Replace a file in archives
|
|
4307
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4308
|
+
{
|
|
4309
|
+
for(size_t i = 0; i < _countof(Test_ReplaceFile); i++)
|
|
4310
|
+
{
|
|
4311
|
+
// Ignore the error code here; we want to see results of all opens
|
|
4312
|
+
dwErrCode = TestReplaceFile(Test_ReplaceFile[i].szName1,
|
|
4313
|
+
Test_ReplaceFile[i].szName2,
|
|
4314
|
+
Test_ReplaceFile[i].szDataHash,
|
|
4315
|
+
Test_ReplaceFile[i].dwFlags);
|
|
4316
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
4317
|
+
break;
|
|
4318
|
+
}
|
|
4319
|
+
}
|
|
4320
|
+
#endif
|
|
4321
|
+
|
|
4322
|
+
#ifdef TEST_VERIFY_HASHES
|
|
4323
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4324
|
+
dwErrCode = VerifyFileHashes(szMpqSubDir);
|
|
4325
|
+
#endif
|
|
4326
|
+
|
|
4327
|
+
#ifdef TEST_CREATE_MPQS
|
|
4328
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4329
|
+
{
|
|
4330
|
+
for(size_t i = 0; i < _countof(Test_CreateMpqs); i++)
|
|
4331
|
+
{
|
|
4332
|
+
// Ignore the error code here; we want to see results of all opens
|
|
4333
|
+
dwErrCode = TestCreateArchive(Test_CreateMpqs[i]);
|
|
4334
|
+
if(dwErrCode != ERROR_SUCCESS)
|
|
4335
|
+
break;
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
#endif
|
|
4339
|
+
|
|
4340
|
+
// Test creating of an archive the same way like MPQ Editor does
|
|
4341
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4342
|
+
dwErrCode = TestCreateArchive_TestGaps(_T("StormLibTest_GapsTest.mpq"));
|
|
4343
|
+
|
|
4344
|
+
// Create an archive and fill it with files up to the max file count
|
|
4345
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4346
|
+
dwErrCode = TestCreateArchive_FillArchive(_T("StormLibTest_FileTableFull.mpq"), 0);
|
|
4347
|
+
|
|
4348
|
+
// Create an archive and fill it with files up to the max file count
|
|
4349
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4350
|
+
dwErrCode = TestCreateArchive_FillArchive(_T("StormLibTest_FileTableFull.mpq"), MPQ_CREATE_LISTFILE);
|
|
4351
|
+
|
|
4352
|
+
// Create an archive and fill it with files up to the max file count
|
|
4353
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4354
|
+
dwErrCode = TestCreateArchive_FillArchive(_T("StormLibTest_FileTableFull.mpq"), MPQ_CREATE_ATTRIBUTES);
|
|
4355
|
+
|
|
4356
|
+
// Create an archive and fill it with files up to the max file count
|
|
4357
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4358
|
+
dwErrCode = TestCreateArchive_FillArchive(_T("StormLibTest_FileTableFull.mpq"), MPQ_CREATE_ATTRIBUTES | MPQ_CREATE_LISTFILE);
|
|
4359
|
+
|
|
4360
|
+
// Create an archive, and increment max file count several times
|
|
4361
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4362
|
+
dwErrCode = TestCreateArchive_IncMaxFileCount(_T("StormLibTest_IncMaxFileCount.mpq"));
|
|
4363
|
+
|
|
4364
|
+
// Create a MPQ file, add files with various flags
|
|
4365
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4366
|
+
dwErrCode = TestCreateArchive_FileFlagTest(_T("StormLibTest_FileFlagTest.mpq"));
|
|
4367
|
+
|
|
4368
|
+
// Create a MPQ file, add a mono-WAVE file with various compressions
|
|
4369
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4370
|
+
dwErrCode = TestCreateArchive_WaveCompressionsTest(_T("StormLibTest_AddWaveMonoTest.mpq"), _T("wave-mono.wav"));
|
|
4371
|
+
|
|
4372
|
+
// Create a MPQ file, add a mono-WAVE with 8 bits per sample file with various compressions
|
|
4373
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4374
|
+
dwErrCode = TestCreateArchive_WaveCompressionsTest(_T("StormLibTest_AddWaveMonoBadTest.mpq"), _T("wave-mono-bad.wav"));
|
|
4375
|
+
|
|
4376
|
+
// Create a MPQ file, add a stereo-WAVE file with various compressions
|
|
4377
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4378
|
+
dwErrCode = TestCreateArchive_WaveCompressionsTest(_T("StormLibTest_AddWaveStereoTest.mpq"), _T("wave-stereo.wav"));
|
|
4379
|
+
|
|
4380
|
+
// Check if the listfile is always created at the end of the file table in the archive
|
|
4381
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4382
|
+
dwErrCode = TestCreateArchive_ListFilePos(_T("StormLibTest_ListFilePos.mpq"));
|
|
4383
|
+
|
|
4384
|
+
// Open a MPQ (add custom user data to it)
|
|
4385
|
+
if(dwErrCode == ERROR_SUCCESS)
|
|
4386
|
+
dwErrCode = TestCreateArchive_BigArchive(_T("StormLibTest_BigArchive_v4.mpq"));
|
|
4387
|
+
|
|
4388
|
+
#ifdef _MSC_VER
|
|
4389
|
+
_CrtDumpMemoryLeaks();
|
|
4390
|
+
#endif // _MSC_VER
|
|
4391
|
+
|
|
4392
|
+
return dwErrCode;
|
|
4393
|
+
}
|