aboutsummaryrefslogtreecommitdiff
path: root/dep
diff options
context:
space:
mode:
Diffstat (limited to 'dep')
-rw-r--r--dep/CMakeLists.txt2
-rw-r--r--dep/PackageList.txt8
-rw-r--r--dep/StormLib/CMakeLists.txt272
-rw-r--r--dep/StormLib/doc/History.txt62
-rw-r--r--dep/StormLib/doc/Sector Offset MD5.txt25
-rw-r--r--dep/StormLib/doc/The MoPaQ File Format 0.9.txt318
-rw-r--r--dep/StormLib/doc/The MoPaQ File Format 1.0.txt433
-rw-r--r--dep/StormLib/doc/d3-authenticationcode-deDE.txt1
-rw-r--r--dep/StormLib/doc/d3-authenticationcode-enGB.txt1
-rw-r--r--dep/StormLib/doc/d3-authenticationcode-enSG.txt1
-rw-r--r--dep/StormLib/doc/d3-authenticationcode-enUS.txt1
-rw-r--r--dep/StormLib/doc/d3-authenticationcode-esES.txt1
-rw-r--r--dep/StormLib/doc/d3-authenticationcode-esMX.txt1
-rw-r--r--dep/StormLib/doc/d3-authenticationcode-frFR.txt1
-rw-r--r--dep/StormLib/doc/d3-authenticationcode-itIT.txt1
-rw-r--r--dep/StormLib/doc/d3-authenticationcode-koKR.txt1
-rw-r--r--dep/StormLib/doc/d3-authenticationcode-plPL.txt1
-rw-r--r--dep/StormLib/doc/d3-authenticationcode-ptBR.txt1
-rw-r--r--dep/StormLib/doc/d3-authenticationcode-zhTW.txt1
-rw-r--r--dep/StormLib/doc/diablo3_ruru_disk_encrypted_win.blob49
-rw-r--r--dep/StormLib/doc/diablo3_urls.txt14
-rw-r--r--dep/StormLib/src/FileStream.cpp2294
-rw-r--r--dep/StormLib/src/FileStream.h189
-rw-r--r--dep/StormLib/src/SBaseCommon.cpp1700
-rw-r--r--dep/StormLib/src/SBaseDumpData.cpp144
-rw-r--r--dep/StormLib/src/SBaseFileTable.cpp2550
-rw-r--r--dep/StormLib/src/SCompression.cpp1135
-rw-r--r--dep/StormLib/src/SFileAddFile.cpp1286
-rw-r--r--dep/StormLib/src/SFileAttributes.cpp477
-rw-r--r--dep/StormLib/src/SFileCompactArchive.cpp765
-rw-r--r--dep/StormLib/src/SFileCreateArchive.cpp255
-rw-r--r--dep/StormLib/src/SFileExtractFile.cpp67
-rw-r--r--dep/StormLib/src/SFileFindFile.cpp446
-rw-r--r--dep/StormLib/src/SFileListFile.cpp557
-rw-r--r--dep/StormLib/src/SFileOpenArchive.cpp470
-rw-r--r--dep/StormLib/src/SFileOpenFileEx.cpp469
-rw-r--r--dep/StormLib/src/SFilePatchArchives.cpp587
-rw-r--r--dep/StormLib/src/SFileReadFile.cpp1183
-rw-r--r--dep/StormLib/src/SFileVerify.cpp921
-rw-r--r--dep/StormLib/src/StormCommon.h274
-rw-r--r--dep/StormLib/src/StormLib.h984
-rw-r--r--dep/StormLib/src/StormPort.h235
-rw-r--r--dep/StormLib/src/adpcm/adpcm.cpp358
-rw-r--r--dep/StormLib/src/adpcm/adpcm.h22
-rw-r--r--dep/StormLib/src/bzip2/blocksort.c1094
-rw-r--r--dep/StormLib/src/bzip2/bzlib.c1573
-rw-r--r--dep/StormLib/src/bzip2/bzlib.h282
-rw-r--r--dep/StormLib/src/bzip2/bzlib_private.h509
-rw-r--r--dep/StormLib/src/bzip2/compress.c672
-rw-r--r--dep/StormLib/src/bzip2/crctable.c104
-rw-r--r--dep/StormLib/src/bzip2/decompress.c626
-rw-r--r--dep/StormLib/src/bzip2/huffman.c205
-rw-r--r--dep/StormLib/src/bzip2/randtable.c84
-rw-r--r--dep/StormLib/src/huffman/huff.cpp1303
-rw-r--r--dep/StormLib/src/huffman/huff.h142
-rw-r--r--dep/StormLib/src/huffman/huff_patch.cpp1120
-rw-r--r--dep/StormLib/src/huffman/huff_patch.h145
-rw-r--r--dep/StormLib/src/jenkins/lookup.h24
-rw-r--r--dep/StormLib/src/jenkins/lookup3.c1003
-rw-r--r--dep/StormLib/src/libtomcrypt/src/hashes/hash_memory.c69
-rw-r--r--dep/StormLib/src/libtomcrypt/src/hashes/md5.c368
-rw-r--r--dep/StormLib/src/libtomcrypt/src/hashes/sha1.c288
-rw-r--r--dep/StormLib/src/libtomcrypt/src/headers/tomcrypt.h87
-rw-r--r--dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_argchk.h38
-rw-r--r--dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_cfg.h136
-rw-r--r--dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_cipher.h891
-rw-r--r--dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_custom.h424
-rw-r--r--dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_hash.h378
-rw-r--r--dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_mac.h384
-rw-r--r--dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_macros.h424
-rw-r--r--dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_math.h500
-rw-r--r--dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_misc.h23
-rw-r--r--dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_pk.h558
-rw-r--r--dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_pkcs.h89
-rw-r--r--dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_prng.h199
-rw-r--r--dep/StormLib/src/libtomcrypt/src/math/ltm_desc.c483
-rw-r--r--dep/StormLib/src/libtomcrypt/src/math/multi.c61
-rw-r--r--dep/StormLib/src/libtomcrypt/src/math/rand_prime.c87
-rw-r--r--dep/StormLib/src/libtomcrypt/src/misc/base64_decode.c104
-rw-r--r--dep/StormLib/src/libtomcrypt/src/misc/crypt_argchk.c30
-rw-r--r--dep/StormLib/src/libtomcrypt/src/misc/crypt_find_hash.c40
-rw-r--r--dep/StormLib/src/libtomcrypt/src/misc/crypt_find_prng.c41
-rw-r--r--dep/StormLib/src/libtomcrypt/src/misc/crypt_hash_descriptor.c27
-rw-r--r--dep/StormLib/src/libtomcrypt/src/misc/crypt_hash_is_valid.c36
-rw-r--r--dep/StormLib/src/libtomcrypt/src/misc/crypt_libc.c43
-rw-r--r--dep/StormLib/src/libtomcrypt/src/misc/crypt_ltc_mp_descriptor.c13
-rw-r--r--dep/StormLib/src/libtomcrypt/src/misc/crypt_prng_descriptor.c26
-rw-r--r--dep/StormLib/src/libtomcrypt/src/misc/crypt_prng_is_valid.c36
-rw-r--r--dep/StormLib/src/libtomcrypt/src/misc/crypt_register_hash.c54
-rw-r--r--dep/StormLib/src/libtomcrypt/src/misc/crypt_register_prng.c54
-rw-r--r--dep/StormLib/src/libtomcrypt/src/misc/zeromem.c34
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_bit_string.c102
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_boolean.c47
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_choice.c182
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_ia5_string.c96
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_integer.c110
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_object_identifier.c99
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_octet_string.c91
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_printable_string.c96
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_ex.c287
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_flexi.c386
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_multi.c139
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_short_integer.c68
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_utctime.c127
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_utf8_string.c111
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_bit_string.c54
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_boolean.c35
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_ia5_string.c194
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_integer.c82
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_object_identifier.c89
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_octet_string.c53
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_printable_string.c166
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_sequence.c169
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_short_integer.c70
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_utctime.c46
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_utf8_string.c83
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/asn1/der_sequence_free.c65
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_map.c76
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_mul2add.c207
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod.c222
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_points.c60
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_projective_add_point.c196
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_projective_dbl_point.c147
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_mgf1.c108
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_decode.c189
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_decode.c177
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_decode.c110
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_exptmod.c113
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_free.c34
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_import.c143
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_make_key.c112
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_verify_hash.c167
-rw-r--r--dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_verify_simple.c87
-rw-r--r--dep/StormLib/src/libtommath/bn_fast_mp_invmod.c148
-rw-r--r--dep/StormLib/src/libtommath/bn_fast_mp_montgomery_reduce.c172
-rw-r--r--dep/StormLib/src/libtommath/bn_fast_s_mp_mul_digs.c107
-rw-r--r--dep/StormLib/src/libtommath/bn_fast_s_mp_mul_high_digs.c98
-rw-r--r--dep/StormLib/src/libtommath/bn_fast_s_mp_sqr.c114
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_2expt.c48
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_abs.c43
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_add.c53
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_add_d.c112
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_addmod.c41
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_and.c57
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_clamp.c44
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_clear.c44
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_clear_multi.c34
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_cmp.c43
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_cmp_d.c44
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_cmp_mag.c55
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_cnt_lsb.c53
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_copy.c68
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_count_bits.c45
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_div.c292
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_div_2.c68
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_div_2d.c97
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_div_3.c79
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_div_d.c115
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_dr_is_modulus.c43
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_dr_reduce.c94
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_dr_setup.c32
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_exch.c34
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_expt_d.c57
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_exptmod.c112
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_exptmod_fast.c321
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_exteuclid.c82
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_fread.c67
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_fwrite.c52
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_gcd.c105
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_get_int.c45
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_grow.c57
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_init.c46
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_init_copy.c32
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_init_multi.c59
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_init_set.c32
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_init_set_int.c31
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_init_size.c48
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_invmod.c43
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_invmod_slow.c175
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_is_square.c109
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_jacobi.c105
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_karatsuba_mul.c167
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_karatsuba_sqr.c121
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_lcm.c60
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_lshd.c67
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_mod.c48
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_mod_2d.c55
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_mod_d.c27
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_montgomery_calc_normalization.c59
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_montgomery_reduce.c118
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_montgomery_setup.c59
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_mul.c66
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_mul_2.c82
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_mul_2d.c85
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_mul_d.c79
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_mulmod.c40
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_n_root.c132
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_neg.c40
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_or.c50
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_prime_fermat.c62
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_prime_is_divisible.c50
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_prime_is_prime.c83
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_prime_miller_rabin.c103
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_prime_next_prime.c170
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_prime_rabin_miller_trials.c52
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_prime_random_ex.c125
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_radix_size.c78
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_radix_smap.c24
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_rand.c55
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_read_radix.c85
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_read_signed_bin.c41
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_read_unsigned_bin.c55
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_reduce.c100
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_reduce_2k.c61
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_reduce_2k_l.c62
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_reduce_2k_setup.c47
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_reduce_2k_setup_l.c44
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_reduce_is_2k.c52
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_reduce_is_2k_l.c44
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_reduce_setup.c34
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_rshd.c72
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_set.c29
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_set_int.c48
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_shrink.c35
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_signed_bin_size.c27
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_sqr.c58
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_sqrmod.c41
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_sqrt.c81
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_sub.c59
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_sub_d.c93
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_submod.c42
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_to_signed_bin.c33
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_to_signed_bin_n.c31
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_to_unsigned_bin.c48
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_to_unsigned_bin_n.c31
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_toom_mul.c284
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_toom_sqr.c226
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_toradix.c75
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_toradix_n.c88
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_unsigned_bin_size.c28
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_xor.c51
-rw-r--r--dep/StormLib/src/libtommath/bn_mp_zero.c36
-rw-r--r--dep/StormLib/src/libtommath/bn_prime_tab.c61
-rw-r--r--dep/StormLib/src/libtommath/bn_reverse.c39
-rw-r--r--dep/StormLib/src/libtommath/bn_s_mp_add.c109
-rw-r--r--dep/StormLib/src/libtommath/bn_s_mp_exptmod.c252
-rw-r--r--dep/StormLib/src/libtommath/bn_s_mp_mul_digs.c90
-rw-r--r--dep/StormLib/src/libtommath/bn_s_mp_mul_high_digs.c81
-rw-r--r--dep/StormLib/src/libtommath/bn_s_mp_sqr.c84
-rw-r--r--dep/StormLib/src/libtommath/bn_s_mp_sub.c89
-rw-r--r--dep/StormLib/src/libtommath/bncore.c36
-rw-r--r--dep/StormLib/src/libtommath/tommath.h584
-rw-r--r--dep/StormLib/src/libtommath/tommath_class.h999
-rw-r--r--dep/StormLib/src/libtommath/tommath_superclass.h76
-rw-r--r--dep/StormLib/src/lzma/C/LzFind.c761
-rw-r--r--dep/StormLib/src/lzma/C/LzFind.h115
-rw-r--r--dep/StormLib/src/lzma/C/LzFindMt.c793
-rw-r--r--dep/StormLib/src/lzma/C/LzFindMt.h105
-rw-r--r--dep/StormLib/src/lzma/C/LzHash.h54
-rw-r--r--dep/StormLib/src/lzma/C/LzmaDec.c999
-rw-r--r--dep/StormLib/src/lzma/C/LzmaDec.h231
-rw-r--r--dep/StormLib/src/lzma/C/LzmaEnc.c2268
-rw-r--r--dep/StormLib/src/lzma/C/LzmaEnc.h80
-rw-r--r--dep/StormLib/src/lzma/C/Threads.c84
-rw-r--r--dep/StormLib/src/lzma/C/Threads.h59
-rw-r--r--dep/StormLib/src/lzma/C/Types.h236
-rw-r--r--dep/StormLib/src/lzma/info.txt1
-rw-r--r--dep/StormLib/src/pklib/crc32.c66
-rw-r--r--dep/StormLib/src/pklib/explode.c522
-rw-r--r--dep/StormLib/src/pklib/implode.c769
-rw-r--r--dep/StormLib/src/pklib/pklib.h148
-rw-r--r--dep/StormLib/src/sparse/sparse.cpp292
-rw-r--r--dep/StormLib/src/sparse/sparse.h19
-rw-r--r--dep/StormLib/src/zlib/adler32.c149
-rw-r--r--dep/StormLib/src/zlib/compress2.c79
-rw-r--r--dep/StormLib/src/zlib/crc32.c423
-rw-r--r--dep/StormLib/src/zlib/crc32.h441
-rw-r--r--dep/StormLib/src/zlib/deflate.c1736
-rw-r--r--dep/StormLib/src/zlib/deflate.h331
-rw-r--r--dep/StormLib/src/zlib/inffast.c318
-rw-r--r--dep/StormLib/src/zlib/inffast.h11
-rw-r--r--dep/StormLib/src/zlib/inffixed.h94
-rw-r--r--dep/StormLib/src/zlib/inflate.c1368
-rw-r--r--dep/StormLib/src/zlib/inflate.h115
-rw-r--r--dep/StormLib/src/zlib/inftrees.c329
-rw-r--r--dep/StormLib/src/zlib/inftrees.h55
-rw-r--r--dep/StormLib/src/zlib/trees.c1219
-rw-r--r--dep/StormLib/src/zlib/trees.h128
-rw-r--r--dep/StormLib/src/zlib/zconf.h332
-rw-r--r--dep/StormLib/src/zlib/zlib.h1357
-rw-r--r--dep/StormLib/src/zlib/zutil.c318
-rw-r--r--dep/StormLib/src/zlib/zutil.h269
-rw-r--r--dep/StormLib/storm_dll/storm_dll.cpp117
-rw-r--r--dep/StormLib/storm_dll/storm_dll.def25
-rw-r--r--dep/StormLib/storm_dll/storm_dll.h67
-rw-r--r--dep/StormLib/stormlib_dll/DllMain.c24
-rw-r--r--dep/StormLib/stormlib_dll/StormLib.def76
-rw-r--r--dep/StormLib/stormlib_dll/StormLib.exp75
-rw-r--r--dep/StormLib/test/Test.cpp1892
-rw-r--r--dep/StormLib/test/x86_ripped_code.asm1231
-rw-r--r--dep/StormLib/test/x86_starcraft_lzma.asm11066
-rw-r--r--dep/libmpq/AUTHORS10
-rw-r--r--dep/libmpq/CMakeLists.txt34
-rw-r--r--dep/libmpq/COPYING339
-rw-r--r--dep/libmpq/FAQ68
-rw-r--r--dep/libmpq/INSTALL182
-rw-r--r--dep/libmpq/Makefile.am26
-rw-r--r--dep/libmpq/NEWS76
-rw-r--r--dep/libmpq/README34
-rw-r--r--dep/libmpq/THANKS21
-rw-r--r--dep/libmpq/TODO10
-rw-r--r--dep/libmpq/autogen.sh19
-rw-r--r--dep/libmpq/bindings/Makefile.am6
-rw-r--r--dep/libmpq/bindings/d/Makefile.am6
-rw-r--r--dep/libmpq/bindings/d/dsss.conf2
-rw-r--r--dep/libmpq/bindings/d/mpq.d318
-rw-r--r--dep/libmpq/bindings/python/Makefile.am5
-rw-r--r--dep/libmpq/bindings/python/mpq-info16
-rw-r--r--dep/libmpq/bindings/python/mpq.py322
-rw-r--r--dep/libmpq/config.h74
-rw-r--r--dep/libmpq/configure.ac84
-rw-r--r--dep/libmpq/debian/changelog35
-rw-r--r--dep/libmpq/debian/compat1
-rw-r--r--dep/libmpq/debian/control50
-rw-r--r--dep/libmpq/debian/copyright23
-rw-r--r--dep/libmpq/debian/libmpq-dev.dirs6
-rw-r--r--dep/libmpq/debian/libmpq-dev.install6
-rw-r--r--dep/libmpq/debian/libmpq0.dirs1
-rw-r--r--dep/libmpq/debian/libmpq0.docs6
-rw-r--r--dep/libmpq/debian/libmpq0.install1
-rw-r--r--dep/libmpq/debian/python-mpq.install1
-rw-r--r--dep/libmpq/debian/rules112
-rw-r--r--dep/libmpq/doc/Makefile.am5
-rw-r--r--dep/libmpq/doc/man1/Makefile.am9
-rw-r--r--dep/libmpq/doc/man1/libmpq-config.169
-rw-r--r--dep/libmpq/doc/man3/Makefile.am31
-rw-r--r--dep/libmpq/doc/man3/libmpq.3207
-rw-r--r--dep/libmpq/doc/man3/libmpq__archive_close.357
-rw-r--r--dep/libmpq/doc/man3/libmpq__archive_files.350
-rw-r--r--dep/libmpq/doc/man3/libmpq__archive_offset.351
-rw-r--r--dep/libmpq/doc/man3/libmpq__archive_open.371
-rw-r--r--dep/libmpq/doc/man3/libmpq__archive_packed_size.351
-rw-r--r--dep/libmpq/doc/man3/libmpq__archive_unpacked_size.351
-rw-r--r--dep/libmpq/doc/man3/libmpq__archive_version.348
-rw-r--r--dep/libmpq/doc/man3/libmpq__block_close_offset.353
-rw-r--r--dep/libmpq/doc/man3/libmpq__block_open_offset.365
-rw-r--r--dep/libmpq/doc/man3/libmpq__block_read.378
-rw-r--r--dep/libmpq/doc/man3/libmpq__block_unpacked_size.359
-rw-r--r--dep/libmpq/doc/man3/libmpq__file_blocks.354
-rw-r--r--dep/libmpq/doc/man3/libmpq__file_compressed.354
-rw-r--r--dep/libmpq/doc/man3/libmpq__file_encrypted.354
-rw-r--r--dep/libmpq/doc/man3/libmpq__file_imploded.354
-rw-r--r--dep/libmpq/doc/man3/libmpq__file_number.352
-rw-r--r--dep/libmpq/doc/man3/libmpq__file_offset.355
-rw-r--r--dep/libmpq/doc/man3/libmpq__file_packed_size.355
-rw-r--r--dep/libmpq/doc/man3/libmpq__file_read.377
-rw-r--r--dep/libmpq/doc/man3/libmpq__file_unpacked_size.355
-rw-r--r--dep/libmpq/doc/man3/libmpq__strerror.345
-rw-r--r--dep/libmpq/doc/man3/libmpq__version.345
-rw-r--r--dep/libmpq/libmpq-config.in57
-rw-r--r--dep/libmpq/libmpq.pc.in10
-rw-r--r--dep/libmpq/libmpq/Makefile.am23
-rw-r--r--dep/libmpq/libmpq/common.c220
-rw-r--r--dep/libmpq/libmpq/common.h61
-rw-r--r--dep/libmpq/libmpq/crypt_buf.h217
-rw-r--r--dep/libmpq/libmpq/explode.c602
-rw-r--r--dep/libmpq/libmpq/explode.h87
-rw-r--r--dep/libmpq/libmpq/extract.c361
-rw-r--r--dep/libmpq/libmpq/extract.h106
-rw-r--r--dep/libmpq/libmpq/huffman.c1101
-rw-r--r--dep/libmpq/libmpq/huffman.h151
-rw-r--r--dep/libmpq/libmpq/mpq-internal.h145
-rw-r--r--dep/libmpq/libmpq/mpq.c1004
-rw-r--r--dep/libmpq/libmpq/mpq.h101
-rw-r--r--dep/libmpq/libmpq/pack_begin.h34
-rw-r--r--dep/libmpq/libmpq/pack_end.h31
-rw-r--r--dep/libmpq/libmpq/platform.h28
-rw-r--r--dep/libmpq/libmpq/wave.c250
-rw-r--r--dep/libmpq/libmpq/wave.h45
-rw-r--r--dep/libmpq/tools/Makefile.am8
-rw-r--r--dep/libmpq/tools/crypt_buf_gen.c85
-rw-r--r--dep/libmpq/win/config.h81
-rw-r--r--dep/libmpq/win/dirent.h230
-rw-r--r--dep/libmpq/win/stdint.h247
384 files changed, 80564 insertions, 8739 deletions
diff --git a/dep/CMakeLists.txt b/dep/CMakeLists.txt
index ad5e04cb321..4778c309df9 100644
--- a/dep/CMakeLists.txt
+++ b/dep/CMakeLists.txt
@@ -39,5 +39,5 @@ if(SERVERS)
endif()
if(TOOLS)
- add_subdirectory(libmpq)
+ add_subdirectory(StormLib)
endif()
diff --git a/dep/PackageList.txt b/dep/PackageList.txt
index 95503cee302..7f91f862d0c 100644
--- a/dep/PackageList.txt
+++ b/dep/PackageList.txt
@@ -16,10 +16,6 @@ jemalloc (a general-purpose scalable concurrent malloc-implementation)
http://www.canonware.com/jemalloc/
Version: 2.1.0
-libMPQ (a library for reading MPQ files)
- https://libmpq.org/
- Version: 1.0.4
-
MySQL (the world's most popular open source database software)
http://www.mysql.com/
Version: 5.5.9 (GA)
@@ -43,3 +39,7 @@ gSOAP (a portable development toolkit for C and C++ XML Web services and XML dat
recastnavigation (Recast is state of the art navigation mesh construction toolset for games)
http://code.google.com/p/recastnavigation/
Version: 1.4
+
+StormLib (a pack of modules, written in C++, which are able to read and also to write files from/to the MPQ archives)
+ http://www.zezula.net/en/mpq/stormlib.html
+ Version: 8.04
diff --git a/dep/StormLib/CMakeLists.txt b/dep/StormLib/CMakeLists.txt
new file mode 100644
index 00000000000..7096c8f8729
--- /dev/null
+++ b/dep/StormLib/CMakeLists.txt
@@ -0,0 +1,272 @@
+set(SRC_FILES
+ src/adpcm/adpcm.cpp
+ src/huffman/huff.cpp
+ src/jenkins/lookup3.c
+ src/lzma/C/LzFind.c
+ src/lzma/C/LzmaDec.c
+ src/lzma/C/LzmaEnc.c
+ src/pklib/explode.c
+ src/pklib/implode.c
+ src/sparse/sparse.cpp
+ src/FileStream.cpp
+ src/SBaseCommon.cpp
+ src/SBaseFileTable.cpp
+ src/SCompression.cpp
+ src/SFileAddFile.cpp
+ src/SFileAttributes.cpp
+ src/SFileCompactArchive.cpp
+ src/SFileCreateArchive.cpp
+ src/SFileExtractFile.cpp
+ src/SFileFindFile.cpp
+ src/SFileListFile.cpp
+ src/SFileOpenArchive.cpp
+ src/SFileOpenFileEx.cpp
+ src/SFilePatchArchives.cpp
+ src/SFileReadFile.cpp
+ src/SFileVerify.cpp
+)
+
+set(TOMCRYPT_FILES
+ src/libtomcrypt/src/hashes/hash_memory.c
+ src/libtomcrypt/src/hashes/md5.c
+ src/libtomcrypt/src/hashes/sha1.c
+ src/libtomcrypt/src/math/ltm_desc.c
+ src/libtomcrypt/src/math/multi.c
+ src/libtomcrypt/src/math/rand_prime.c
+ src/libtomcrypt/src/misc/base64_decode.c
+ src/libtomcrypt/src/misc/crypt_argchk.c
+ src/libtomcrypt/src/misc/crypt_find_hash.c
+ src/libtomcrypt/src/misc/crypt_find_prng.c
+ src/libtomcrypt/src/misc/crypt_hash_descriptor.c
+ src/libtomcrypt/src/misc/crypt_hash_is_valid.c
+ src/libtomcrypt/src/misc/crypt_libc.c
+ src/libtomcrypt/src/misc/crypt_ltc_mp_descriptor.c
+ src/libtomcrypt/src/misc/crypt_prng_descriptor.c
+ src/libtomcrypt/src/misc/crypt_prng_is_valid.c
+ src/libtomcrypt/src/misc/crypt_register_hash.c
+ src/libtomcrypt/src/misc/crypt_register_prng.c
+ src/libtomcrypt/src/misc/zeromem.c
+ src/libtomcrypt/src/pk/asn1/der_decode_bit_string.c
+ src/libtomcrypt/src/pk/asn1/der_decode_boolean.c
+ src/libtomcrypt/src/pk/asn1/der_decode_choice.c
+ src/libtomcrypt/src/pk/asn1/der_decode_ia5_string.c
+ src/libtomcrypt/src/pk/asn1/der_decode_integer.c
+ src/libtomcrypt/src/pk/asn1/der_decode_object_identifier.c
+ src/libtomcrypt/src/pk/asn1/der_decode_octet_string.c
+ src/libtomcrypt/src/pk/asn1/der_decode_printable_string.c
+ src/libtomcrypt/src/pk/asn1/der_decode_sequence_ex.c
+ src/libtomcrypt/src/pk/asn1/der_decode_sequence_flexi.c
+ src/libtomcrypt/src/pk/asn1/der_decode_sequence_multi.c
+ src/libtomcrypt/src/pk/asn1/der_decode_short_integer.c
+ src/libtomcrypt/src/pk/asn1/der_decode_utctime.c
+ src/libtomcrypt/src/pk/asn1/der_decode_utf8_string.c
+ src/libtomcrypt/src/pk/asn1/der_length_bit_string.c
+ src/libtomcrypt/src/pk/asn1/der_length_boolean.c
+ src/libtomcrypt/src/pk/asn1/der_length_ia5_string.c
+ src/libtomcrypt/src/pk/asn1/der_length_integer.c
+ src/libtomcrypt/src/pk/asn1/der_length_object_identifier.c
+ src/libtomcrypt/src/pk/asn1/der_length_octet_string.c
+ src/libtomcrypt/src/pk/asn1/der_length_printable_string.c
+ src/libtomcrypt/src/pk/asn1/der_length_sequence.c
+ src/libtomcrypt/src/pk/asn1/der_length_utctime.c
+ src/libtomcrypt/src/pk/asn1/der_sequence_free.c
+ src/libtomcrypt/src/pk/asn1/der_length_utf8_string.c
+ src/libtomcrypt/src/pk/asn1/der_length_short_integer.c
+ src/libtomcrypt/src/pk/ecc/ltc_ecc_map.c
+ src/libtomcrypt/src/pk/ecc/ltc_ecc_mul2add.c
+ src/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod.c
+ src/libtomcrypt/src/pk/ecc/ltc_ecc_points.c
+ src/libtomcrypt/src/pk/ecc/ltc_ecc_projective_add_point.c
+ src/libtomcrypt/src/pk/ecc/ltc_ecc_projective_dbl_point.c
+ src/libtomcrypt/src/pk/pkcs1/pkcs_1_mgf1.c
+ src/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_decode.c
+ src/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_decode.c
+ src/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_decode.c
+ src/libtomcrypt/src/pk/rsa/rsa_exptmod.c
+ src/libtomcrypt/src/pk/rsa/rsa_free.c
+ src/libtomcrypt/src/pk/rsa/rsa_import.c
+ src/libtomcrypt/src/pk/rsa/rsa_make_key.c
+ src/libtomcrypt/src/pk/rsa/rsa_verify_hash.c
+ src/libtomcrypt/src/pk/rsa/rsa_verify_simple.c
+)
+
+set(TOMMATH_FILES
+ src/libtommath/bncore.c
+ src/libtommath/bn_fast_mp_invmod.c
+ src/libtommath/bn_fast_mp_montgomery_reduce.c
+ src/libtommath/bn_fast_s_mp_mul_digs.c
+ src/libtommath/bn_fast_s_mp_mul_high_digs.c
+ src/libtommath/bn_fast_s_mp_sqr.c
+ src/libtommath/bn_mp_2expt.c
+ src/libtommath/bn_mp_abs.c
+ src/libtommath/bn_mp_add.c
+ src/libtommath/bn_mp_addmod.c
+ src/libtommath/bn_mp_add_d.c
+ src/libtommath/bn_mp_and.c
+ src/libtommath/bn_mp_clamp.c
+ src/libtommath/bn_mp_clear.c
+ src/libtommath/bn_mp_clear_multi.c
+ src/libtommath/bn_mp_cmp.c
+ src/libtommath/bn_mp_cmp_d.c
+ src/libtommath/bn_mp_cmp_mag.c
+ src/libtommath/bn_mp_cnt_lsb.c
+ src/libtommath/bn_mp_copy.c
+ src/libtommath/bn_mp_count_bits.c
+ src/libtommath/bn_mp_div.c
+ src/libtommath/bn_mp_div_2.c
+ src/libtommath/bn_mp_div_2d.c
+ src/libtommath/bn_mp_div_3.c
+ src/libtommath/bn_mp_div_d.c
+ src/libtommath/bn_mp_dr_is_modulus.c
+ src/libtommath/bn_mp_dr_reduce.c
+ src/libtommath/bn_mp_dr_setup.c
+ src/libtommath/bn_mp_exch.c
+ src/libtommath/bn_mp_exptmod.c
+ src/libtommath/bn_mp_exptmod_fast.c
+ src/libtommath/bn_mp_expt_d.c
+ src/libtommath/bn_mp_exteuclid.c
+ src/libtommath/bn_mp_fread.c
+ src/libtommath/bn_mp_fwrite.c
+ src/libtommath/bn_mp_gcd.c
+ src/libtommath/bn_mp_get_int.c
+ src/libtommath/bn_mp_grow.c
+ src/libtommath/bn_mp_init.c
+ src/libtommath/bn_mp_init_copy.c
+ src/libtommath/bn_mp_init_multi.c
+ src/libtommath/bn_mp_init_set.c
+ src/libtommath/bn_mp_init_set_int.c
+ src/libtommath/bn_mp_init_size.c
+ src/libtommath/bn_mp_invmod.c
+ src/libtommath/bn_mp_invmod_slow.c
+ src/libtommath/bn_mp_is_square.c
+ src/libtommath/bn_mp_jacobi.c
+ src/libtommath/bn_mp_karatsuba_mul.c
+ src/libtommath/bn_mp_karatsuba_sqr.c
+ src/libtommath/bn_mp_lcm.c
+ src/libtommath/bn_mp_lshd.c
+ src/libtommath/bn_mp_mod.c
+ src/libtommath/bn_mp_mod_2d.c
+ src/libtommath/bn_mp_mod_d.c
+ src/libtommath/bn_mp_montgomery_calc_normalization.c
+ src/libtommath/bn_mp_montgomery_reduce.c
+ src/libtommath/bn_mp_montgomery_setup.c
+ src/libtommath/bn_mp_mul.c
+ src/libtommath/bn_mp_mulmod.c
+ src/libtommath/bn_mp_mul_2.c
+ src/libtommath/bn_mp_mul_2d.c
+ src/libtommath/bn_mp_mul_d.c
+ src/libtommath/bn_mp_neg.c
+ src/libtommath/bn_mp_n_root.c
+ src/libtommath/bn_mp_or.c
+ src/libtommath/bn_mp_prime_fermat.c
+ src/libtommath/bn_mp_prime_is_divisible.c
+ src/libtommath/bn_mp_prime_is_prime.c
+ src/libtommath/bn_mp_prime_miller_rabin.c
+ src/libtommath/bn_mp_prime_next_prime.c
+ src/libtommath/bn_mp_prime_rabin_miller_trials.c
+ src/libtommath/bn_mp_prime_random_ex.c
+ src/libtommath/bn_mp_radix_size.c
+ src/libtommath/bn_mp_radix_smap.c
+ src/libtommath/bn_mp_rand.c
+ src/libtommath/bn_mp_read_radix.c
+ src/libtommath/bn_mp_read_signed_bin.c
+ src/libtommath/bn_mp_read_unsigned_bin.c
+ src/libtommath/bn_mp_reduce.c
+ src/libtommath/bn_mp_reduce_2k.c
+ src/libtommath/bn_mp_reduce_2k_l.c
+ src/libtommath/bn_mp_reduce_2k_setup.c
+ src/libtommath/bn_mp_reduce_2k_setup_l.c
+ src/libtommath/bn_mp_reduce_is_2k.c
+ src/libtommath/bn_mp_reduce_is_2k_l.c
+ src/libtommath/bn_mp_reduce_setup.c
+ src/libtommath/bn_mp_rshd.c
+ src/libtommath/bn_mp_set.c
+ src/libtommath/bn_mp_set_int.c
+ src/libtommath/bn_mp_shrink.c
+ src/libtommath/bn_mp_signed_bin_size.c
+ src/libtommath/bn_mp_sqr.c
+ src/libtommath/bn_mp_sqrmod.c
+ src/libtommath/bn_mp_sqrt.c
+ src/libtommath/bn_mp_sub.c
+ src/libtommath/bn_mp_submod.c
+ src/libtommath/bn_mp_sub_d.c
+ src/libtommath/bn_mp_toom_mul.c
+ src/libtommath/bn_mp_toom_sqr.c
+ src/libtommath/bn_mp_toradix.c
+ src/libtommath/bn_mp_toradix_n.c
+ src/libtommath/bn_mp_to_signed_bin.c
+ src/libtommath/bn_mp_to_signed_bin_n.c
+ src/libtommath/bn_mp_to_unsigned_bin.c
+ src/libtommath/bn_mp_to_unsigned_bin_n.c
+ src/libtommath/bn_mp_unsigned_bin_size.c
+ src/libtommath/bn_mp_xor.c
+ src/libtommath/bn_mp_zero.c
+ src/libtommath/bn_prime_tab.c
+ src/libtommath/bn_reverse.c
+ src/libtommath/bn_s_mp_add.c
+ src/libtommath/bn_s_mp_exptmod.c
+ src/libtommath/bn_s_mp_mul_digs.c
+ src/libtommath/bn_s_mp_mul_high_digs.c
+ src/libtommath/bn_s_mp_sqr.c
+ src/libtommath/bn_s_mp_sub.c
+)
+
+set(ZLIB_BZIP2_FILES
+ src/bzip2/blocksort.c
+ src/bzip2/bzlib.c
+ src/bzip2/compress.c
+ src/bzip2/crctable.c
+ src/bzip2/decompress.c
+ src/bzip2/huffman.c
+ src/bzip2/randtable.c
+ src/zlib/adler32.c
+ src/zlib/compress2.c
+ src/zlib/crc32.c
+ src/zlib/deflate.c
+ src/zlib/inffast.c
+ src/zlib/inflate.c
+ src/zlib/inftrees.c
+ src/zlib/trees.c
+ src/zlib/zutil.c
+)
+
+set(TEST_SRC_FILES
+ test/Test.cpp
+)
+
+add_definitions(-D_7ZIP_ST -DBZ_STRICT_ANSI)
+
+if(WIN32)
+ if(MSVC)
+ add_definitions(-D_7ZIP_ST -DWIN32)
+ endif()
+ set(SRC_ADDITIONAL_FILES ${ZLIB_BZIP2_FILES} ${TOMCRYPT_FILES} ${TOMMATH_FILES})
+ set(LINK_LIBS wininet)
+endif()
+
+if(APPLE)
+ set(LINK_LIBS z bz2)
+ set(SRC_ADDITIONAL_FILES ${TOMCRYPT_FILES} ${TOMMATH_FILES})
+endif()
+
+if (${CMAKE_SYSTEM_NAME} STREQUAL Linux)
+ option(WITH_LIBTOMCRYPT "Use system LibTomCrypt library" OFF)
+ if(WITH_LIBTOMCRYPT)
+ set(LINK_LIBS z bz2 tomcrypt)
+ else()
+ set(LINK_LIBS z bz2)
+ set(SRC_ADDITIONAL_FILES ${TOMCRYPT_FILES} ${TOMMATH_FILES})
+ endif()
+endif()
+
+add_library(storm STATIC ${SRC_FILES} ${SRC_ADDITIONAL_FILES})
+target_link_libraries(storm ${LINK_LIBS})
+
+if(UNIX)
+ set_target_properties(storm PROPERTIES SOVERSION 0)
+endif()
+
+# On Win32, build StormLib.dll since we don't want to clash with Storm.dll
+if(WIN32)
+ set_target_properties(storm PROPERTIES OUTPUT_NAME StormLib)
+endif()
diff --git a/dep/StormLib/doc/History.txt b/dep/StormLib/doc/History.txt
new file mode 100644
index 00000000000..5e32894d7b1
--- /dev/null
+++ b/dep/StormLib/doc/History.txt
@@ -0,0 +1,62 @@
+
+ StormLib history
+ ================
+
+ Version 8.02
+
+ - Support for UNICODE encoding for on-disk files
+ - Optimized file deleting
+
+ Version 8.01
+
+ - SFileFindFirstFile and SFileFindNextFile no longer find files that have
+ patch file in the oldest MPQ in the patch chain
+ - Write support for MPQs version 4
+
+ Version 8.00
+
+ - Updated support for protected maps from Warcraft III
+
+ Version 7.11
+
+ - Support for MPQs v 3.0 (WOW-Cataclysm BETA)
+ - StormLib now deals properly with files that have MPQ_SECTOR_CHECKSUM missing,
+ but have sector checksum entry present in the sector offset table
+
+ Version 7.10
+
+ - Support for partial MPQs ("interface.MPQ.part")
+ - The only operation that is externally allowed to do with internal files
+ ("(listfile)", "(attributes)" and "(signature)") is reading. Attempt to modify any of the file
+ fails and GetLastError returns ERROR_INTERNAL_FILE
+ - Fixed memory leak that has occured when writing more than one sector to the file at once
+
+ Version 7.01
+
+ - Support for adding files from memory
+ - Fixed improper validation of handles to MPQ file and MPQ archive
+ - Fixed bug where StormLib didn't save CRC32 of the file when added to archive
+
+ Version 7.00
+
+ - Properly deals with MPQs protected by w3xMaster
+ - Major rewrite
+ - Fixed support for (attributes)
+ - Added file verification
+ - Added MPQ signature verification
+
+ Version 6.22
+
+ - Properly deals with MPQs protected by w3xMaster
+
+ Version 6.21
+
+ - SFileRenameFile now properly re-crypts the file if necessary.
+ - SFileFindFirstFile correctly deals with deleted files
+
+ Version 6.20
+
+ - Fixed lots of bugs when processing files with same names but different locales
+ - Fixed bugs when repeately extracts the same file with MPQ_FILE_SINGLE_UNIT flag
+ - Added SFileFlushArchive
+ - Fixed issue opening AVI files renamed to MPQ using SFileCreateArchiveEx
diff --git a/dep/StormLib/doc/Sector Offset MD5.txt b/dep/StormLib/doc/Sector Offset MD5.txt
new file mode 100644
index 00000000000..a22506ac704
--- /dev/null
+++ b/dep/StormLib/doc/Sector Offset MD5.txt
@@ -0,0 +1,25 @@
+
+ After sector offset table
+ =========================
+
+FileSize CmpSize DWORDs
+00007588 000075A4 0x01
+0000A9EA 000095EC 0x01
+0000E51D 0000E20D 0x02
+00015C00 00015C40 0x02
+0001C578 000186C4 0x02
+0002A9D4 0002A9EA 0x04
+00037BAC 00037A42 0x06
+0003C3C1 00034084 0x06
+0003D224 0003B30F 0x06
+00045105 0004195A 0x07
+00045D9C 0003D87D 0x07
+0004AAB8 0004860A 0x08
+0004D18E 00048E0C 0x07
+00056B4C 00056BDD 0x09
+0005DC08 00059426 0x09
+00061EC0 00057711 0x0A
+0006CEC4 00062561 0x0B
+000778EE 00066736 0x0C
+000AD0CB 0007F32E 0x11
+00327EAC 00303395 0x53
diff --git a/dep/StormLib/doc/The MoPaQ File Format 0.9.txt b/dep/StormLib/doc/The MoPaQ File Format 0.9.txt
new file mode 100644
index 00000000000..ce8d8f70166
--- /dev/null
+++ b/dep/StormLib/doc/The MoPaQ File Format 0.9.txt
@@ -0,0 +1,318 @@
+THE MOPAQ ARCHIVE FORMAT
+v0.9 (Thursday, June 30, 2005)
+by Justin Olbrantz(Quantam)
+
+Distribution and reproduction of this specification are allowed without limitation, as long as it is not altered. Quoting
+in other works is freely allowed, as long as the source and author of the quote is stated.
+
+TABLE OF CONTENTS
+1. Introduction to the MoPaQ Format
+2. The MoPaQ Format
+ 2.1 General Archive Layout
+ 2.2 Archive Header
+ 2.3 Block Table
+ 2.4 Hash Table
+ 2.5 File Data
+ 2.6 Listfile
+ 2.7 Extended Attributes
+ 2.8 Weak (Old) Digital Signature
+ 2.9 Strong (New) Digital Signature
+3. Algorithm Source Code
+ 3.1 Encryption/Decryption
+ 3.2 Hashing
+ 3.3 Conversion of FILETIME and time_t
+
+1. INTRODUCTION TO THE MOPAQ FORMAT
+The MoPaQ (or MPQ) format is an archive file format designed by Mike O'Brien (hence the name Mike O'brien PaCK) at Blizzard
+Entertainment. The format has been used in all Blizzard games since (and including) Diablo. It is heavily optimized to be
+a read-only game archive format, and excels at this role.
+
+The Blizzard MoPaQ-reading functions are contained in the Storm module, which my be either statically or dynamically linked.
+The Blizzard MoPaQ-writing functions are contained in the MPQAPI module, which is always statically linked.
+
+2. THE MOPAQ FORMAT
+All numbers in the MoPaQ format are in little endian. Data types are listed either as int (integer, the number of bits specified),
+byte (8 bits), and char (bytes which contain ASCII characters). All sizes and offsets are in bytes, unless specified otherwise.
+Structure members are listed in the following general form:
+offset from the beginning of the structure: data type(array size) member name : member description
+
+2.1 GENERAL ARCHIVE LAYOUT
+- Archive Header
+- File Data
+- File Data - Special Files
+- Hash Table
+- Block Table
+- Strong Digital signature
+
+This is the usual archive format, and is not absolutely essential. Some archives have been observed placing the hash table
+and file table after the archive header, and before the file data.
+
+2.2 ARCHIVE HEADER
+00h: char(4) Magic : Indicates that the file is a MoPaQ archive. Must be ASCII "MPQ" 1Ah.
+04h: int32 HeaderSize : Size of the archive header. Should be 32.
+08h: int32 ArchiveSize : Size of the whole archive, including the header. Does not include the strong digital signature, if present.
+This size is used, among other things, for determining the region to hash in computing the digital signature.
+0Ch: int16 Unknown : Unknown
+0Eh: int8 SectorSizeShift : Power of two exponent specifying the number of 512-byte disk sectors in each logical sector
+in the archive. The size of each logical sector the archive is 512 * 2^SectorSizeShift. Bugs in the Storm library dictate
+that this should always be 3 (4096 byte sectors).
+10h: int32 HashTableOffset : Offset to the beginning of the hash table, relative to the beginning of the archive.
+14h: int32 BlockTableOffset : Offset to the beginning of the block table, relative to the beginning of the archive.
+18h: int32 HashTableEntries : Number of entries in the hash table. Must be a power of two, and must be less than 2^16.
+1Ch: int32 BlockTableEntries : Number of entries in the block table.
+
+The archive header is the first structure in the archive, at archive offset 0, but the archive does not need to be at offset
+0 of the containing file. The offset of the archive in the file is referred to here as ArchiveOffset. If the archive is not
+at the beginning of the file, it must begin at a disk sector boundary (512 bytes). Early versions of Storm require that the
+archive be at the end of the containing file (ArchiveOffset + ArchiveSize = file size), but this is not required in newer
+versions (due to the strong digital signature not being considered a part of the archive).
+
+2.3 BLOCK TABLE
+The block table contains entries for each region in the archive. Regions may be either files or empty space, which may be
+overwritten by new files (typically this space is from deleted file data). The block table is encrypted, using the hash
+of "(block table)" as the key. Each entry is structured as follows:
+
+00h: int32 BlockOffset : Offset of the beginning of the block, relative to the beginning of the archive. Meaningless if the block size is 0.
+04h: int32 BlockSize : Size of the block in the archive.
+08h: int32 FileSize : Size of the file data stored in the block. Only valid if the block is a file, otherwise meaningless, and should be 0. If the file is compressed, this is the size of the uncompressed file data.
+0Ch: int32 Flags : Bit mask of the flags for the block. The following values are conclusively identified:
+ 80000000h: Block is a file, and follows the file data format; otherwise, block is free space, and may be overwritten. If the block is not a file, all other flags should be cleared.
+ 01000000h: File is stored as a single unit, rather than split into sectors.
+ 00020000h: The file's encryption key is adjusted by the block offset and file size (explained in detail in the File Data section). File must be encrypted.
+ 00010000h: File is encrypted.
+ 00000200h: File is compressed. Mutually exclusive to file imploded.
+ 00000100h: File is imploded. Mutually exclusive to file compressed.
+
+2.4 HASH TABLE
+Instead of storing file names, for quick access MoPaQs use a fixed, power of two-size hash table of files in the archive. A file is uniquely identified by its file path, its language, and its platform. The home entry for a file in the hash table is computed as a hash of the file path. In the event of a collision (the home entry is occupied by another file), progressive overflow is used, and the file is placed in the next available hash table entry. Searches for a desired file in the hash table proceed from the home entry for the file until either the file is found, the entire hash table is searched, or an empty hash table entry (FileBlockIndex of FFFFFFFFh) is encountered. The hash table is encrypted using the hash of "(hash table)" as the key. Each entry is structured as follows:
+
+00h: int32 FilePathHashA : The hash of the file path, using method A.
+04h: int32 FilePathHashB : The hash of the file path, using method B.
+08h: int16 Language : The language of the file. This is a Windows LANGID data type, and uses the same values. 0 indicates the default language (American English), or that the file is language-neutral.
+0Ah: int8 Platform : The platform the file is used for. 0 indicates the default platform. No other values have been observed.
+0Ch: int32 FileBlockIndex : If the hash table entry is valid, this is the index into the block table of the file. Otherwise, one of the following two values:
+ FFFFFFFFh: Hash table entry is empty, and has always been empty. Terminates searches for a given file.
+ FFFFFFFEh: Hash table entry is empty, but was valid at some point (in other words, the file was deleted). Does not terminate searches for a given file.
+
+2.5 FILE DATA
+00h: int32(SectorsInFile + 1) SectorOffsetTable : Offsets to the start of each sector's data, relative to the beginning of the file data. Not present if this information is calculatable (see details below).
+immediately following SectorOffsetTable: SectorData : Data of each sector in the file, packed end to end (see details below).
+
+Normally, file data is split up into sectors, for simple streaming. All sectors, save for the last, will contain as many bytes of file data as specified in the archive header's SectorSizeShift; the last sector may be smaller than this, depending on the size of the file data. This sector size is the size of the raw file data; if the file is compressed, the compressed sector will be smaller or the same size as the uncompressed sector size. Individual sectors in a compressed file may be stored uncompressed; this occurs if and only if the sector could not be compressed by the algorithm used (if the compressed sector size was greater than or equal to the size of the raw data), and is indicated by the sector's compressed size in SectorOffsetTable being equal to the uncompressed size of the sector (which may be calculated from the FileSize).
+
+If the sector is compressed (but not imploded), a bit mask byte of the compression algorithm(s) used to compress the sector is appended to the beginning of the compressed sector data. This additional byte counts towards the total size of the sector; if the size of the sector (including this byte) exceeds or matches the uncompressed size of the sector data, the sector will be stored uncompressed, and this byte omitted. Multiple compression algorithms may be used on the same sector; in this case, successive compression occurs in the order the algorithms are listed below, and decompression occurs in the opposite order. For implimentations of all of these algorithms, see StormLib.
+ 40h: IMA ADPCM mono
+ 80h: IMA ADPCM stereo
+ 01h: Huffman encoded
+ 02h: Deflated (see ZLib)
+ 08h: Imploded (see PKWare Data Compression Library)
+ 10h: BZip2 compressed (see BZip2)
+
+If the file is stored as a single unit (indicated in the file's Flags), there is effectively only a single sector, which
+contains the entire file.
+
+If the file is encrypted, each sector (after compression and appendage of the compression type byte, if applicable)
+is encrypted with the file's key. The base key for a file is determined by a hash of the file name stripped of the
+directory (i.e. the key for a file named "directory\file" would be computed as the hash of "file"). If this key is
+adjusted, as indicated in the file's Flags, the final key is calculated as ((base key + BlockOffset - ArchiveOffset)
+XOR FileSize) (StormLib - an open-source implementation of the MoPaQ reading and writing functions,
+by Ladislav Zezula - incorrectly uses an AND in place of the XOR). Each sector is encrypted using the key + the
+0-based index of the sector in the file. The SectorOffsetTable, if present, is encrypted using the key - 1.
+
+The SectorOffsetTable is omitted when the sizes and offsets of all sectors in the file are calculatable from the FileSize.
+This can happen in several circumstances. If the file is not compressed/imploded, then the size and offset of all sectors
+is known, based on the archive's SectorSizeShift. If the file is stored as a single unit compressed/imploded, then the
+SectorOffsetTable is omitted, as the single file "sector" corresponds to BlockSize and FileSize, as mentioned previously.
+Note that the SectorOffsetTable will always be present if the file is compressed/imploded and the file is not stored as
+a single unit, even if there is only a single sector in the file (the size of the file is less than or equal to the
+archive's sector size).
+
+2.6 LISTFILE
+The listfile is a very simple extension to the MoPaQ format that contains the file paths of (most) files in the archive.
+The languages and platforms of the files are not stored in the listfile. The listfile is contained in the file "(listfile)",
+and is simply a non-Unix-style text file with one file path on each line, lines terminated with the bytes 0Dh 0Ah. The file
+"(listfile)" may not be listed in the listfile.
+
+2.7 EXTENDED ATTRIBUTES
+The extended attributes are optional file attributes for files in the block table. These attributes were added at times after
+the MoPaQ format was already finalized, and it is not necessary for every archive to have all (or any) of the extended attributes.
+If an archive contains a given attribute, there will be an instance of that attribute for every block in the block table, although
+the attribute will be meaningless if the block is not a file. The order of the attributes for blocks correspond to the order of the
+blocks in the block table, and are of the same number. The attributes are stored in parallel arrays in the "(attributes)" file,
+in the archive. The attributes corresponding to this file need not be valid (and logically cannot be). Unlike all the other
+structures in the MoPaQ format, entries in the extended attributes are NOT guaranteed to be aligned. Also note that in some
+archives, malicious zeroing of the attributes has been observed, perhaps with the intent of breaking archive viewers. This
+file is structured as follows:
+
+00h: int32 Version : Specifies the extended attributes format version. For now, must be 100.
+04h: int32 AttributesPresent : Bit mask of the extended attributes present in the archive:
+ 00000001h: File CRC32s.
+ 00000002h: File timestamps.
+ 00000004h: File MD5s.
+08h: int32(BlockTableEntries) CRC32s : CRC32s of the (uncompressed) file data for each block in the archive. Omitted if the
+archive does not have CRC32s. immediately after CRC32s: FILETIME(BlockTableEntries) Timestamps : Timestamps for each block
+in the archive. The format is that of the Windows FILETIME structure. Omitted if the archive does not have timestamps.
+immediately after Timestamps: MD5(BlockTableEntries) MD5s : MD5s of the (uncompressed) file data for each block in the archive.
+Omitted if the archive does not have MD5s.
+
+2.8 WEAK DIGITAL SIGNATURE
+The weak digital signature is a digital signature using Microsoft CryptoAPI. It is an implimentation of the RSASSA-PKCS1-v1_5
+digital signature protocol, using the MD5 hashing algorithm and a 512-bit (weak) RSA key (for more information about this
+protocol, see the RSA Labs PKCS1 specification). The public key and exponent are stored in a resource in Storm. The signature
+is stored uncompressed, unencrypted in the file "(signature)" in the archive. The archive is hashed from the beginning of the
+archive (ArchiveOffset in the containing file) to the end of the archive (the length indicated by ArchiveSize); the signature
+file is added to the archive before signing, and the space occupied by the file is considered to be all binary 0s during
+signing/verification. This file is structured as follows:
+
+00h: int32 Unknown : Must be 0.
+04h: int32 Unknown : must be 0.
+08h: int512 Signature : The digital signature. Like all other numbers in the MoPaQ format, this is stored in little-endian order.
+
+2.9 STRONG DIGITAL SIGNATURE
+The strong digital signature uses a simple proprietary implementation of RSA signing, using the SHA-1 hashing algorithm and
+a 2048-bit (strong) RSA key. The default public key and exponent are stored in Storm, but other keys may be used as well.
+The strong digital signature is stored immediately after the archive, in the containing file; the entire archive (ArchiveSize
+bytes, starting at ArchiveOffset in the containing file) is hashed as a single block. The signature has the following format:
+
+00h: char(4) Magic : Indicates the presence of a digital signature. Must be "NGIS" ("SIGN" backwards).
+04h: int2048 Signature : The digital signature, stored in little-endian format.
+
+When the Signature field is decrypted with the public key and exponent, and the result stored in little-endian order, it is structured as follows:
+
+00h: byte Padding : Must be 0Bh.
+01h: byte(235) Padding : Must be BBh.
+ECh: byte(20) SHA-1 : SHA-1 hash of the archive, in standard SHA-1 format.
+
+3. ALGORITHM SOURCE CODE
+3.1 ENCRYPTION/DECRYPTION
+I believe this was derived at some point from code in StormLib. Assumes the long type to be 32 bits, and the machine to be little endian order.
+
+unsigned long dwCryptTable[0x500];
+
+void InitializeCryptTable()
+{
+ unsigned long seed = 0x00100001;
+ unsigned long index1 = 0;
+ unsigned long index2 = 0;
+ int i;
+
+ for (index1 = 0; index1 < 0x100; index1++)
+ {
+ for (index2 = index1, i = 0; i < 5; i++, index2 += 0x100)
+ {
+ unsigned long temp1, temp2;
+
+ seed = (seed * 125 + 3) % 0x2AAAAB;
+ temp1 = (seed & 0xFFFF) << 0x10;
+
+ seed = (seed * 125 + 3) % 0x2AAAAB;
+ temp2 = (seed & 0xFFFF);
+
+ dwCryptTable[index2] = (temp1 | temp2);
+ }
+ }
+}
+
+void EncryptData(void *lpbyBuffer, unsigned long dwLength, unsigned long dwKey)
+{
+ unsigned long *lpdwBuffer = (unsigned long *)lpbyBuffer;
+ unsigned long seed = 0xEEEEEEEE;
+ unsigned long ch;
+
+ assert(lpbyBuffer);
+
+ dwLength /= sizeof(unsigned long);
+
+ while(dwLength-- > 0)
+ {
+ seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
+ ch = *lpdwBuffer ^ (dwKey + seed);
+
+ dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
+ seed = *lpdwBuffer + seed + (seed << 5) + 3;
+
+ *lpdwBuffer++ = ch;
+ }
+}
+
+void DecryptData(void *lpbyBuffer, unsigned long dwLength, unsigned long dwKey)
+{
+ unsigned long *lpdwBuffer = (unsigned long *)lpbyBuffer;
+ unsigned long seed = 0xEEEEEEEE;
+ unsigned long ch;
+
+ assert(lpbyBuffer);
+
+ dwLength /= sizeof(unsigned long);
+
+ while(dwLength-- > 0)
+ {
+ seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
+ ch = *lpdwBuffer ^ (dwKey + seed);
+
+ dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
+ seed = ch + seed + (seed << 5) + 3;
+
+ *lpdwBuffer++ = ch;
+ }
+}
+
+3.2 HASHING
+Based on code from StormLib.
+
+// Different types of hashes to make with HashString
+#define MPQ_HASH_TABLE_OFFSET 0
+#define MPQ_HASH_NAME_A 1
+#define MPQ_HASH_NAME_B 2
+#define MPQ_HASH_FILE_KEY 3
+
+unsigned long HashString(const char *lpszString, unsigned long dwHashType)
+{
+ unsigned long seed1 = 0x7FED7FED;
+ unsigned long seed2 = 0xEEEEEEEE;
+ int ch;
+
+ while (*lpszString != 0)
+ {
+ ch = toupper(*lpszString++);
+
+ seed1 = dwCryptTable[(dwHashType * 0xFF) + ch] ^ (seed1 + seed2);
+ seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
+ }
+ return seed1;
+}
+
+3.3 CONVERSION OF FILETIME AND time_t
+
+#define EPOCH_OFFSET 116444736000000000ULL // Number of 100 ns units between 01/01/1601 and 01/01/1970
+
+bool GetTimeFromFileTime(FILETIME &fileTime, time_t &time)
+{
+ // The FILETIME represents a 64-bit integer: the number of 100 ns units since January 1, 1601
+ unsigned long long nTime = ((unsigned long long)fileTime.dwHighDateTime << 32) + fileTime.dwLowDateTime;
+
+ if (nTime < EPOCH_OFFSET)
+ return false;
+
+ nTime -= EPOCH_OFFSET; // Convert the time base from 01/01/1601 to 01/01/1970
+ nTime /= 10000000ULL; // Convert 100 ns to sec
+
+ time = (time_t)nTime;
+
+ // Test for overflow (FILETIME is 64 bits, time_t is 32 bits)
+ if ((nTime - (unsigned long long)time) > 0)
+ return false;
+
+ return true;
+}
+
+void GetFileTimeFromTime(time_t &time, FILETIME &fileTime)
+{
+ unsigned long long nTime = (unsigned long long)time;
+
+ nTime *= 10000000ULL;
+ nTime += EPOCH_OFFSET;
+
+ fileTime.dwLowDateTime = (DWORD)nTime;
+ fileTime.dwHighDateTime = (DWORD)(nTime >> 32);
+}
diff --git a/dep/StormLib/doc/The MoPaQ File Format 1.0.txt b/dep/StormLib/doc/The MoPaQ File Format 1.0.txt
new file mode 100644
index 00000000000..2f139453e0e
--- /dev/null
+++ b/dep/StormLib/doc/The MoPaQ File Format 1.0.txt
@@ -0,0 +1,433 @@
+THE MOPAQ ARCHIVE FORMAT
+v1.0 (Friday, September 1, 2006)
+by Justin Olbrantz(Quantam)
+
+Distribution and reproduction of this specification are allowed without limitation, as long as it is not altered. Quotation in other works is freely allowed, as long as the source and author of the quote are stated.
+
+TABLE OF CONTENTS
+1. Introduction to the MoPaQ Format
+2. The MoPaQ Format
+ 2.1 General Archive Layout
+ 2.2 Archive Header
+ 2.3 Block Table
+ 2.4 Extended Block Table
+ 2.5 Hash Table
+ 2.6 File Data
+ 2.7 Listfile
+ 2.8 Extended Attributes
+ 2.9 Weak (Old) Digital Signature
+ 2.10 Strong (New) Digital Signature
+3. Algorithm Source Code
+ 3.1 Encryption/Decryption
+ 3.2 Hashing and File Key Computation
+ 3.3 Finding Files
+ 3.4 Deleting Files
+ 3.5 Conversion of FILETIME and time_t
+ 3.6 Forming a 64-bit Large Archive Offset from 32-bit and 16-bit Components
+4. Revision History
+
+1. INTRODUCTION TO THE MOPAQ FORMAT
+The MoPaQ (or MPQ) format is an archive file format designed by Mike O'Brien (hence the name Mike O'brien PaCK) at Blizzard Entertainment. The format has been used in all Blizzard games since (and including) Diablo. It is heavily optimized to be a read-only game archive format, and excels at this role.
+
+The Blizzard MoPaQ-reading functions are contained in the Storm module, which my be either statically or dynamically linked. The Blizzard MoPaQ-writing functions are contained in the MPQAPI module, which is always statically linked.
+
+StormLib - mentioned several times in this specification - is an open-source MoPaQ reading and writing library written by Ladislav Zezula (no affiliation with Blizzard Entertainment). While it's a bit dated, and does not support all of the newer MoPaQ features, it contains source code to the more exotic compression methods used by MoPaQ, such as the PKWare implode algorithm, MoPaQ's huffman compression algorithm, and the IMA ADPCM compression used by MoPaQ.
+
+2. THE MOPAQ FORMAT
+All numbers in the MoPaQ format are in little endian byte order; signed numbers use the two's complement system. Data types are listed either as int (integer, the number of bits specified), byte (8 bits), or char (bytes which contain ASCII characters). All sizes and offsets are in bytes, unless specified otherwise. Structure members are listed in the following general form:
+offset from the beginning of the structure: data type(array size) member name : member description
+
+2.1 GENERAL ARCHIVE LAYOUT
+- Archive Header
+- File Data
+- File Data - Special Files
+- Hash Table
+- Block Table
+- Extended Block Table
+- Strong Digital signature
+
+This is the usual archive format, but it is not mandatory. Some archives have been observed placing the hash table and file table after the archive header, and before the file data.
+
+2.2 ARCHIVE HEADER
+00h: char(4) Magic : Indicates that the file is a MoPaQ archive. Must be ASCII "MPQ" 1Ah.
+04h: int32 HeaderSize : Size of the archive header.
+08h: int32 ArchiveSize : Size of the whole archive, including the header. Does not include the strong digital signature, if present. This size is used, among other things, for determining the region to hash in computing the digital signature. This field is deprecated in the Burning Crusade MoPaQ format, and the size of the archive is calculated as the size from the beginning of the archive to the end of the hash table, block table, or extended block table (whichever is largest).
+0Ch: int16 FormatVersion : MoPaQ format version. MPQAPI will not open archives where this is negative. Known versions:
+ 0000h: Original format. HeaderSize should be 20h, and large archives are not supported.
+ 0001h: Burning Crusade format. Header size should be 2Ch, and large archives are supported.
+0Eh: int8 SectorSizeShift : Power of two exponent specifying the number of 512-byte disk sectors in each logical sector in the archive. The size of each logical sector in the archive is 512 * 2^SectorSizeShift. Bugs in the Storm library dictate that this should always be 3 (4096 byte sectors).
+10h: int32 HashTableOffset : Offset to the beginning of the hash table, relative to the beginning of the archive.
+14h: int32 BlockTableOffset : Offset to the beginning of the block table, relative to the beginning of the archive.
+18h: int32 HashTableEntries : Number of entries in the hash table. Must be a power of two, and must be less than 2^16 for the original MoPaQ format, or less than 2^20 for the Burning Crusade format.
+1Ch: int32 BlockTableEntries : Number of entries in the block table.
+Fields only present in the Burning Crusade format and later:
+20h: int64 ExtendedBlockTableOffset : Offset to the beginning of the extended block table, relative to the beginning of the archive.
+28h: int16 HashTableOffsetHigh : High 16 bits of the hash table offset for large archives.
+2Ah: int16 BlockTableOffsetHigh : High 16 bits of the block table offset for large archives.
+
+The archive header is the first structure in the archive, at archive offset 0; however, the archive does not need to be at offset 0 of the containing file. The offset of the archive in the file is referred to here as ArchiveOffset. If the archive is not at the beginning of the file, it must begin at a disk sector boundary (512 bytes). Early versions of Storm require that the archive be at the end of the containing file (ArchiveOffset + ArchiveSize = file size), but this is not required in newer versions (due to the strong digital signature not being considered a part of the archive).
+
+2.3 BLOCK TABLE
+The block table contains entries for each region in the archive. Regions may be either files, empty space, which may be overwritten by new files (typically this space is from deleted file data), or unused block table entries. Empty space entries should have BlockOffset and BlockSize nonzero, and FileSize and Flags zero; unused block table entries should have BlockSize, FileSize, and Flags zero. The block table is encrypted, using the hash of "(block table)" as the key. Each entry is structured as follows:
+
+00h: int32 BlockOffset : Offset of the beginning of the block, relative to the beginning of the archive.
+04h: int32 BlockSize : Size of the block in the archive.
+08h: int32 FileSize : Size of the file data stored in the block. Only valid if the block is a file; otherwise meaningless, and should be 0. If the file is compressed, this is the size of the uncompressed file data.
+0Ch: int32 Flags : Bit mask of the flags for the block. The following values are conclusively identified:
+ 80000000h: Block is a file, and follows the file data format; otherwise, block is free space or unused. If the block is not a file, all other flags should be cleared, and FileSize should be 0.
+ 01000000h: File is stored as a single unit, rather than split into sectors.
+ 00020000h: The file's encryption key is adjusted by the block offset and file size (explained in detail in the File Data section). File must be encrypted.
+ 00010000h: File is encrypted.
+ 00000200h: File is compressed. File cannot be imploded.
+ 00000100h: File is imploded. File cannot be compressed.
+
+2.4 EXTENDED BLOCK TABLE
+The extended block table was added to support archives larger than 4 gigabytes (2^32 bytes). The table contains the upper bits of the archive offsets for each block in the block table. It is simply an array of int16s, which become bits 32-47 of the archive offsets for each block, with bits 48-63 being zero. Individual blocks in the archive are still limited to 4 gigabytes in size. This table is only present in Burning Crusade format archives that exceed 4 gigabytes size.
+
+As of the Burning Crusade Friends and Family beta, this table is not encrypted.
+
+2.5 HASH TABLE
+Instead of storing file names, for quick access MoPaQs use a fixed, power of two-size hash table of files in the archive. A file is uniquely identified by its file path, its language, and its platform. The home entry for a file in the hash table is computed as a hash of the file path. In the event of a collision (the home entry is occupied by another file), progressive overflow is used, and the file is placed in the next available hash table entry. Searches for a desired file in the hash table proceed from the home entry for the file until either the file is found, the entire hash table is searched, or an empty hash table entry (FileBlockIndex of FFFFFFFFh) is encountered. The hash table is encrypted using the hash of "(hash table)" as the key. Each entry is structured as follows:
+
+00h: int32 FilePathHashA : The hash of the file path, using method A.
+04h: int32 FilePathHashB : The hash of the file path, using method B.
+08h: int16 Language : The language of the file. This is a Windows LANGID data type, and uses the same values. 0 indicates the default language (American English), or that the file is language-neutral.
+0Ah: int8 Platform : The platform the file is used for. 0 indicates the default platform. No other values have been observed.
+0Ch: int32 FileBlockIndex : If the hash table entry is valid, this is the index into the block table of the file. Otherwise, one of the following two values:
+ FFFFFFFFh: Hash table entry is empty, and has always been empty. Terminates searches for a given file.
+ FFFFFFFEh: Hash table entry is empty, but was valid at some point (in other words, the file was deleted). Does not terminate searches for a given file.
+
+2.6 FILE DATA
+The data for each file is composed of the following structure:
+00h: int32(SectorsInFile + 1) SectorOffsetTable : Offsets to the start of each sector, relative to the beginning of the file data. The last entry contains the file size, making it possible to easily calculate the size of any given sector. This table is not present if this information can be calculated (see details below).
+immediately following SectorOffsetTable: SECTOR Sectors(SectorsInFile) : Data of each sector in the file, packed end to end (see details below).
+
+Normally, file data is split up into sectors, for simple streaming. All sectors, save for the last, will contain as many bytes of file data as specified in the archive header's SectorSizeShift; the last sector may contain less than this, depending on the size of the entire file's data. If the file is compressed or imploded, the sector will be smaller or the same size as the file data it contains. Individual sectors in a compressed or imploded file may be stored uncompressed; this occurs if and only if the file data the sector contains could not be compressed by the algorithm(s) used (if the compressed sector size was greater than or equal to the size of the file data), and is indicated by the sector's size in SectorOffsetTable being equal to the size of the file data in the sector (which may be calculated from the FileSize).
+
+The format of each sector depends on the kind of sector it is. Uncompressed sectors are simply the the raw file data contained in the sector. Imploded sectors are the raw compressed data following compression with the implode algorithm (these sectors can only be in imploded files). Compressed sectors (only found in compressed - not imploded - files) are compressed with one or more compression algorithms, and have the following structure:
+00h: byte CompressionMask : Mask of the compression types applied to this sector. If multiple compression types are used, they are applied in the order listed below, and decompression is performed in the opposite order. This byte counts towards the total sector size, meaning that the sector will be stored uncompressed if the data cannot be compressed by at least two bytes; as well, this byte is encrypted with the sector data, if applicable. The following compression types are defined (for implementations of these algorithms, see StormLib):
+ 40h: IMA ADPCM mono
+ 80h: IMA ADPCM stereo
+ 01h: Huffman encoded
+ 02h: Deflated (see ZLib)
+ 08h: Imploded (see PKWare Data Compression Library)
+ 10h: BZip2 compressed (see BZip2)
+01h: byte(SectorSize - 1) SectorData : The compressed data for the sector.
+
+If the file is stored as a single unit (indicated in the file's Flags), there is effectively only a single sector, which contains the entire file data.
+
+If the file is encrypted, each sector (after compression/implosion, if applicable) is encrypted with the file's key. The base key for a file is determined by a hash of the file name stripped of the directory (i.e. the key for a file named "directory\file" would be computed as the hash of "file"). If this key is adjusted, as indicated in the file's Flags, the final key is calculated as ((base key + BlockOffset - ArchiveOffset) XOR FileSize) (StormLib incorrectly uses an AND in place of the XOR). Each sector is encrypted using the key + the 0-based index of the sector in the file. The SectorOffsetTable, if present, is encrypted using the key - 1.
+
+The SectorOffsetTable is omitted when the sizes and offsets of all sectors in the file are calculatable from the FileSize. This can happen in several circumstances. If the file is not compressed/imploded, then the size and offset of all sectors is known, based on the archive's SectorSizeShift. If the file is stored as a single unit compressed/imploded, then the SectorOffsetTable is omitted, as the single file "sector" corresponds to BlockSize and FileSize, as mentioned previously. However, the SectorOffsetTable will be present if the file is compressed/imploded and the file is not stored as a single unit, even if there is only a single sector in the file (the size of the file is less than or equal to the archive's sector size).
+
+2.7 LISTFILE
+The listfile is a very simple extension to the MoPaQ format that contains the file paths of (most) files in the archive. The languages and platforms of the files are not stored in the listfile. The listfile is contained in the file "(listfile)" (default language and platform), and is simply a text file with file paths separated by ';', 0Dh, 0Ah, or some combination of these. The file "(listfile)" may not be listed in the listfile.
+
+2.8 EXTENDED ATTRIBUTES
+The extended attributes are optional file attributes for files in the block table. These attributes were added at times after the MoPaQ format was already finalized, and it is not necessary for every archive to have all (or any) of the extended attributes. If an archive contains a given attribute, there will be an instance of that attribute for every block in the block table, although the attribute will be meaningless if the block is not a file. The order of the attributes for blocks correspond to the order of the blocks in the block table, and are of the same number. The attributes are stored in parallel arrays in the "(attributes)" file (default language and platform), in the archive. The attributes corresponding to this file need not be valid (and logically cannot be). Unlike all the other structures in the MoPaQ format, entries in the extended attributes are NOT guaranteed to be aligned. Also note that in some archives, malicious zeroing of the attributes has been observed, perhaps with the intent of breaking archive viewers. This file is structured as follows:
+
+00h: int32 Version : Specifies the extended attributes format version. For now, must be 100.
+04h: int32 AttributesPresent : Bit mask of the extended attributes present in the archive:
+ 00000001h: File CRC32s.
+ 00000002h: File timestamps.
+ 00000004h: File MD5s.
+08h: int32(BlockTableEntries) CRC32s : CRC32s of the (uncompressed) file data for each block in the archive. Omitted if the archive does not have CRC32s.
+immediately after CRC32s: FILETIME(BlockTableEntries) Timestamps : Timestamps for each block in the archive. The format is that of the Windows FILETIME structure. Omitted if the archive does not have timestamps.
+immediately after Timestamps: MD5(BlockTableEntries) MD5s : MD5s of the (uncompressed) file data for each block in the archive. Omitted if the archive does not have MD5s.
+
+2.9 WEAK DIGITAL SIGNATURE
+The weak digital signature is a digital signature using Microsoft CryptoAPI. It is an implimentation
+of the RSASSA-PKCS1-v1_5 digital signature protocol, using the MD5 hashing algorithm and a 512-bit (weak)
+RSA key (for more information about this protocol, see the RSA Labs PKCS1 specification). The public key
+and exponent are stored in a resource in Storm, the private key is stored in a separate file, whose filename
+is passed to MPQAPI (the private key is not stored in MPQAPI). The signature is stored uncompressed,
+unencrypted in the file "(signature)" (default language and platform) in the archive. The archive
+is hashed from the beginning of the archive (ArchiveOffset in the containing file) to the end of
+the archive (the length indicated by ArchiveSize, or calculated in the Burning Crusade MoPaQ format);
+the signature file is added to the archive before signing, and the space occupied by the file is considered
+to be all binary 0s during signing/verification. This file is structured as follows:
+
+00h: int32 Unknown : Must be 0.
+04h: int32 Unknown : Must be 0.
+08h: int512 Signature : The digital signature. Like all other numbers in the MoPaQ format, this is stored
+in little-endian order. The structure of this, when decrypted, follows the RSASSA-PKCS1-v1_5 specification;
+this format is rather icky to work with (I wrote a program to verify this signature using nothing but an MD5
+function and huge integer functions; it wasn't pleasant), and best left to an encryption library such as Cryto++.
+
+2.10 STRONG DIGITAL SIGNATURE
+The strong digital signature uses a simple proprietary implementation of RSA signing, using the SHA-1 hashing algorithm and a 2048-bit (strong) RSA key. The default public key and exponent are stored in Storm, but other keys may be used as well. The strong digital signature is stored immediately after the archive, in the containing file; the entire archive (ArchiveSize bytes, starting at ArchiveOffset in the containing file) is hashed as a single block. The signature has the following format:
+
+00h: char(4) Magic : Indicates the presence of a digital signature. Must be "NGIS" ("SIGN" backwards).
+04h: int2048 Signature : The digital signature, stored in little-endian format.
+
+When the Signature field is decrypted with the public key and exponent, and the resulting large integer is stored in little-endian order, it is structured as follows:
+
+00h: byte Padding : Must be 0Bh.
+01h: byte(235) Padding : Must be BBh.
+ECh: byte(20) SHA-1 : SHA-1 hash of the archive, in standard SHA-1 byte order.
+
+3. ALGORITHM SOURCE CODE
+All of the sample code here assumes little endian machine byte order, that the short type is 16 bits, that the long type is 32 bits, and that the long long type is 64 bits. Adjustments must be made if these assumptions are not correct on a given platform. All code not credited otherwise was written by myself in the writing of this specification.
+
+3.1 ENCRYPTION/DECRYPTION
+Based on code from StormLib.
+
+unsigned long dwCryptTable[0x500];
+
+// The encryption and hashing functions use a number table in their procedures. This table must be initialized before the functions are called the first time.
+void InitializeCryptTable()
+{
+ unsigned long seed = 0x00100001;
+ unsigned long index1 = 0;
+ unsigned long index2 = 0;
+ int i;
+
+ for (index1 = 0; index1 < 0x100; index1++)
+ {
+ for (index2 = index1, i = 0; i < 5; i++, index2 += 0x100)
+ {
+ unsigned long temp1, temp2;
+
+ seed = (seed * 125 + 3) % 0x2AAAAB;
+ temp1 = (seed & 0xFFFF) << 0x10;
+
+ seed = (seed * 125 + 3) % 0x2AAAAB;
+ temp2 = (seed & 0xFFFF);
+
+ dwCryptTable[index2] = (temp1 | temp2);
+ }
+ }
+}
+
+void EncryptData(void *lpbyBuffer, unsigned long dwLength, unsigned long dwKey)
+{
+ assert(lpbyBuffer);
+
+ unsigned long *lpdwBuffer = (unsigned long *)lpbyBuffer;
+ unsigned long seed = 0xEEEEEEEE;
+ unsigned long ch;
+
+ dwLength /= sizeof(unsigned long);
+
+ while(dwLength-- > 0)
+ {
+ seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
+ ch = *lpdwBuffer ^ (dwKey + seed);
+
+ dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
+ seed = *lpdwBuffer + seed + (seed << 5) + 3;
+
+ *lpdwBuffer++ = ch;
+ }
+}
+
+void DecryptData(void *lpbyBuffer, unsigned long dwLength, unsigned long dwKey)
+{
+ assert(lpbyBuffer);
+
+ unsigned long *lpdwBuffer = (unsigned long *)lpbyBuffer;
+ unsigned long seed = 0xEEEEEEEEL;
+ unsigned long ch;
+
+ dwLength /= sizeof(unsigned long);
+
+ while(dwLength-- > 0)
+ {
+ seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
+ ch = *lpdwBuffer ^ (dwKey + seed);
+
+ dwKey = ((~dwKey << 0x15) + 0x11111111L) | (dwKey >> 0x0B);
+ seed = ch + seed + (seed << 5) + 3;
+
+ *lpdwBuffer++ = ch;
+ }
+}
+
+3.2 HASHING AND FILE KEY COMPUTATION
+These functions may have been derived from StormLib code at some point in the very distant past. It was so long ago that I don't remember for certain.
+
+// Different types of hashes to make with HashString
+#define MPQ_HASH_TABLE_OFFSET 0
+#define MPQ_HASH_NAME_A 1
+#define MPQ_HASH_NAME_B 2
+#define MPQ_HASH_FILE_KEY 3
+
+// Based on code from StormLib.
+unsigned long HashString(const char *lpszString, unsigned long dwHashType)
+{
+ assert(lpszString);
+ assert(dwHashType <= MPQ_HASH_FILE_KEY);
+
+ unsigned long seed1 = 0x7FED7FEDL;
+ unsigned long seed2 = 0xEEEEEEEEL;
+ int ch;
+
+ while (*lpszString != 0)
+ {
+ ch = toupper(*lpszString++);
+
+ seed1 = dwCryptTable[(dwHashType * 0x100) + ch] ^ (seed1 + seed2);
+ seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
+ }
+ return seed1;
+}
+
+#define BLOCK_OFFSET_ADJUSTED_KEY 0x00020000L
+
+unsigned long ComputeFileKey(const char *lpszFilePath, const BlockTableEntry &blockEntry, unsigned long nArchiveOffset)
+{
+ assert(lpszFilePath);
+
+ // Find the file name part of the path
+ const char *lpszFileName = strrchr(lpszFilePath, '\\');
+ if (lpszFileName)
+ lpszFileName++; // Skip the \
+ else
+ lpszFileName = lpszFilePath;
+
+ // Hash the name to get the base key
+ unsigned long nFileKey = HashString(lpszFileName, MPQ_HASH_FILE_KEY);
+
+ // Offset-adjust the key if necessary
+ if (blockEntry.Flags & BLOCK_OFFSET_ADJUSTED_KEY)
+ nFileKey = (nFileKey + blockEntry.BlockOffset) ^ blockEntry.FileSize;
+
+ return nFileKey;
+}
+
+3.3 FINDING FILES
+
+#define MPQ_HASH_ENTRY_EMPTY 0xFFFFFFFFL
+#define MPQ_HASH_ENTRY_DELETED 0xFFFFFFFEL
+
+bool FindFileInHashTable(const HashTableEntry *lpHashTable, unsigned long nHashTableSize, const char *lpszFilePath, unsigned short nLang, unsigned char nPlatform, unsigned long &iFileHashEntry)
+{
+ assert(lpHashTable);
+ assert(nHashTableSize);
+ assert(lpszFilePath);
+
+ // Find the home entry in the hash table for the file
+ unsigned long iInitEntry = HashString(lpszFilePath, MPQ_HASH_TABLE_OFFSET) & (nHashTableSize - 1);
+
+ // Is there anything there at all?
+ if (lpHashTable[iInitEntry].FileBlockIndex == MPQ_HASH_ENTRY_EMPTY)
+ return false;
+
+ // Compute the hashes to compare the hash table entry against
+ unsigned long nNameHashA = HashString(lpszFilePath, MPQ_HASH_NAME_A),
+ nNameHashB = HashString(lpszFilePath, MPQ_HASH_NAME_B),
+ iCurEntry = iInitEntry;
+
+ // Check each entry in the hash table till a termination point is reached
+ do
+ {
+ if (lpHashTable[iCurEntry].FileBlockIndex != MPQ_HASH_ENTRY_DELETED)
+ {
+ if (lpHashTable[iCurEntry].FilePathHashA == nNameHashA
+ && lpHashTable[iCurEntry].FilePathHashB == nNameHashB
+ && lpHashTable[iCurEntry].Language == nLang
+ && lpHashTable[iCurEntry].Platform == nPlatform)
+ {
+ iFileHashEntry = iCurEntry;
+
+ return true;
+ }
+ }
+
+ iCurEntry = (iCurEntry + 1) & (nHashTableSize - 1);
+ } while (iCurEntry != iInitEntry && lpHashTable[iCurEntry].FileBlockIndex != MPQ_HASH_ENTRY_EMPTY);
+
+ return false;
+}
+
+3.4 DELETING FILES
+
+bool DeleteFile(HashTableEntry *lpHashTable, unsigned long nHashTableSize, BlockTableEntry *lpBlockTable, const char *lpszFilePath, unsigned short nLang, unsigned char nPlatform)
+{
+ assert(lpHashTable);
+ assert(nHashTableSize);
+ assert(lpBlockTable);
+
+ // Find the file in the hash table
+ unsigned long iFileHashEntry;
+
+ if (!FindFileInHashTable(lpHashTable, nHashTableSize, lpszFilePath, nLang, nPlatform, iFileHashEntry))
+ return false;
+
+ // Get the block table index before we nuke the hash table entry
+ unsigned long iFileBlockEntry = lpHashTable[iFileHashEntry].FileBlockIndex;
+
+ // Delete the file's entry in the hash table
+ memset(&lpHashTable[iFileHashEntry], 0xFF, sizeof(HashTableEntry));
+
+ // If the next entry is empty, mark this one as empty; otherwise, mark this as deleted.
+ if (lpHashTable[(iFileHashEntry + 1) & (nHashTableSize - 1)].FileBlockIndex == MPQ_HASH_ENTRY_EMPTY)
+ lpHashTable[iFileHashEntry].FileBlockIndex = MPQ_HASH_ENTRY_EMPTY;
+ else
+ lpHashTable[iFileHashEntry].FileBlockIndex = MPQ_HASH_ENTRY_DELETED;
+
+ // If the block occupies space, mark the block as free space; otherwise, clear the block table entry.
+ if (lpBlockTable[iFileBlockEntry].BlockSize > 0)
+ {
+ lpBlockTable[iFileBlockEntry].FileSize = 0;
+ lpBlockTable[iFileBlockEntry].Flags = 0;
+ }
+ else
+ memset(&lpBlockTable[iFileBlockEntry], 0, sizeof(BlockTableEntry);
+
+ return true;
+}
+
+3.5 CONVERSION OF FILETIME AND time_t
+This code assumes that the base ("zero") date for time_t is 01/01/1970. This is true on Windows, Unix System V systems, and Mac OS X. It is unknown whether this is true on all other platforms. You'll need to research this yourself, if you plan on porting it somewhere else.
+
+#define EPOCH_OFFSET 116444736000000000ULL // Number of 100 ns units between 01/01/1601 and 01/01/1970
+
+bool GetTimeFromFileTime(const FILETIME &fileTime, time_t &time)
+{
+ // The FILETIME represents a 64-bit integer: the number of 100 ns units since January 1, 1601
+ unsigned long long nTime = ((unsigned long long)fileTime.dwHighDateTime << 32) + fileTime.dwLowDateTime;
+
+ if (nTime < EPOCH_OFFSET)
+ return false;
+
+ nTime -= EPOCH_OFFSET; // Convert the time base from 01/01/1601 to 01/01/1970
+ nTime /= 10000000ULL; // Convert 100 ns to sec
+
+ time = (time_t)nTime;
+
+ // Test for overflow (FILETIME is 64 bits, time_t is 32 bits)
+ if ((nTime - (unsigned long long)time) > 0)
+ return false;
+
+ return true;
+}
+
+void GetFileTimeFromTime(const time_t &time, FILETIME &fileTime)
+{
+ unsigned long long nTime = (unsigned long long)time;
+
+ nTime *= 10000000ULL;
+ nTime += EPOCH_OFFSET;
+
+ fileTime.dwLowDateTime = (DWORD)nTime;
+ fileTime.dwHighDateTime = (DWORD)(nTime >> 32);
+}
+
+3.6 FORMING A 64-BIT LARGE ARCHIVE OFFSET FROM 32-BIT AND 16-BIT COMPONENTS
+unsigned long long MakeLargeArchiveOffset(unsigned long nOffsetLow, unsigned short nOffsetHigh)
+{
+ return ((unsigned long long)nOffsetHigh << 32) + (unsigned long long)nOffsetLow;
+}
+
+4. REVISION HISTORY
+1.0
+ - Updated to include most of the changes found in the Burning Crusade Friends and Family beta
+
+0.91.
+ - Updated several structure member descriptions
+ - Listed the full set of characters that can separate list file entries
+ - Noted that (attributes), (listfile), and (signature) use the default language and platform codes
+ - Redid part of the file data specs to clarify the format of sectors
+ - Enhanced descriptions of the different kinds of block table entries
+ - Added ComputeFileKey, FindFileInHashTable, and DeleteFile source \ No newline at end of file
diff --git a/dep/StormLib/doc/d3-authenticationcode-deDE.txt b/dep/StormLib/doc/d3-authenticationcode-deDE.txt
new file mode 100644
index 00000000000..cac66712af0
--- /dev/null
+++ b/dep/StormLib/doc/d3-authenticationcode-deDE.txt
@@ -0,0 +1 @@
+UCMXF6EJY352EFH4XFRXCFH2XC9MQRZK \ No newline at end of file
diff --git a/dep/StormLib/doc/d3-authenticationcode-enGB.txt b/dep/StormLib/doc/d3-authenticationcode-enGB.txt
new file mode 100644
index 00000000000..2bc9c83859d
--- /dev/null
+++ b/dep/StormLib/doc/d3-authenticationcode-enGB.txt
@@ -0,0 +1 @@
+MMKVHY48RP7WXP4GHYBQ7SL9J9UNPHBP \ No newline at end of file
diff --git a/dep/StormLib/doc/d3-authenticationcode-enSG.txt b/dep/StormLib/doc/d3-authenticationcode-enSG.txt
new file mode 100644
index 00000000000..e6f1ec29609
--- /dev/null
+++ b/dep/StormLib/doc/d3-authenticationcode-enSG.txt
@@ -0,0 +1 @@
+8MXLWHQ7VGGLTZ9MQZQSFDCLJYET3CPP \ No newline at end of file
diff --git a/dep/StormLib/doc/d3-authenticationcode-enUS.txt b/dep/StormLib/doc/d3-authenticationcode-enUS.txt
new file mode 100644
index 00000000000..8d73e61def9
--- /dev/null
+++ b/dep/StormLib/doc/d3-authenticationcode-enUS.txt
@@ -0,0 +1 @@
+EJ2R5TM6XFE2GUNG5QDGHKQ9UAKPWZSZ \ No newline at end of file
diff --git a/dep/StormLib/doc/d3-authenticationcode-esES.txt b/dep/StormLib/doc/d3-authenticationcode-esES.txt
new file mode 100644
index 00000000000..6b1b0a1b811
--- /dev/null
+++ b/dep/StormLib/doc/d3-authenticationcode-esES.txt
@@ -0,0 +1 @@
+PBGFBE42Z6LNK65UGJQ3WZVMCLP4HQQT \ No newline at end of file
diff --git a/dep/StormLib/doc/d3-authenticationcode-esMX.txt b/dep/StormLib/doc/d3-authenticationcode-esMX.txt
new file mode 100644
index 00000000000..504759e8d55
--- /dev/null
+++ b/dep/StormLib/doc/d3-authenticationcode-esMX.txt
@@ -0,0 +1 @@
+X7SEJJS9TSGCW5P28EBSC47AJPEY8VU2 \ No newline at end of file
diff --git a/dep/StormLib/doc/d3-authenticationcode-frFR.txt b/dep/StormLib/doc/d3-authenticationcode-frFR.txt
new file mode 100644
index 00000000000..bb35a2bfdc6
--- /dev/null
+++ b/dep/StormLib/doc/d3-authenticationcode-frFR.txt
@@ -0,0 +1 @@
+5KVBQA8VYE6XRY3DLGC5ZDE4XS4P7YA2 \ No newline at end of file
diff --git a/dep/StormLib/doc/d3-authenticationcode-itIT.txt b/dep/StormLib/doc/d3-authenticationcode-itIT.txt
new file mode 100644
index 00000000000..a62031d3883
--- /dev/null
+++ b/dep/StormLib/doc/d3-authenticationcode-itIT.txt
@@ -0,0 +1 @@
+478JD2K56EVNVVY4XX8TDWYT5B8KB254 \ No newline at end of file
diff --git a/dep/StormLib/doc/d3-authenticationcode-koKR.txt b/dep/StormLib/doc/d3-authenticationcode-koKR.txt
new file mode 100644
index 00000000000..296ffcc9450
--- /dev/null
+++ b/dep/StormLib/doc/d3-authenticationcode-koKR.txt
@@ -0,0 +1 @@
+8TS4VNFQRZTN6YWHE9CHVDH9NVWD474A \ No newline at end of file
diff --git a/dep/StormLib/doc/d3-authenticationcode-plPL.txt b/dep/StormLib/doc/d3-authenticationcode-plPL.txt
new file mode 100644
index 00000000000..a92563c1815
--- /dev/null
+++ b/dep/StormLib/doc/d3-authenticationcode-plPL.txt
@@ -0,0 +1 @@
+LJ52Z32DF4LZ4ZJJXVKK3AZQA6GABLJB \ No newline at end of file
diff --git a/dep/StormLib/doc/d3-authenticationcode-ptBR.txt b/dep/StormLib/doc/d3-authenticationcode-ptBR.txt
new file mode 100644
index 00000000000..e6e5c3568d9
--- /dev/null
+++ b/dep/StormLib/doc/d3-authenticationcode-ptBR.txt
@@ -0,0 +1 @@
+K6BDHY2ECUE2545YKNLBJPVYWHE7XYAG \ No newline at end of file
diff --git a/dep/StormLib/doc/d3-authenticationcode-zhTW.txt b/dep/StormLib/doc/d3-authenticationcode-zhTW.txt
new file mode 100644
index 00000000000..138a5449c7a
--- /dev/null
+++ b/dep/StormLib/doc/d3-authenticationcode-zhTW.txt
@@ -0,0 +1 @@
+6VWCQTN8V3ZZMRUCZXV8A8CGUX2TAA8H \ No newline at end of file
diff --git a/dep/StormLib/doc/diablo3_ruru_disk_encrypted_win.blob b/dep/StormLib/doc/diablo3_ruru_disk_encrypted_win.blob
new file mode 100644
index 00000000000..7972b2d7636
--- /dev/null
+++ b/dep/StormLib/doc/diablo3_ruru_disk_encrypted_win.blob
@@ -0,0 +1,49 @@
+{
+"config":{
+ "product": "D3",
+ "install_progress_percent": 70.0,
+ "install_progress_info": [8000000000.0, 0.0, 0.0],
+ "download_progress_info": [10000000.0, 500000000.0, 500000000.0],
+ "install_progress_speed": 5000000.0,
+ "tome_download_progress_percent": 0.0,
+ "updater_product": "d3_patch",
+ "expansion_level": 0,
+ "ptr": false,
+ "beta": false,
+ "update_method": "patch on demand",
+ "supports_multibox": false,
+ "data_dir": "Data_D3/PC/MPQs/",
+ "patch_url": "http://ruRU.patch.battle.net:1119/patch",
+ "update_regex": "(?P<prefix>d3-update-(?P<dataset>\\w+))-(?P<build>\\d+)\\.mpq$",
+ "update_identifier": "d3-update-",
+ "torrent_file_path": "Diablo III.tfil",
+ "manifest_file_path": "Diablo III.mfil",
+ "priority_file_path": "Diablo III.pfil",
+ "priority_file_layout": "Retail",
+ "binary_version_path": "Diablo III.exe",
+ "binary_launch_path": "Diablo III.exe",
+ "display_locales":["ruRU"],
+ "supported_locales" : ["enUS", "esMX", "ptBR", "enGB", "deDE", "esES", "frFR", "itIT", "plPL", "enSG", "ptPT", "ruRU", "koKR", "zhTW", "zhCN"],
+ "launch_arguments":["-launch","-uid","diablo3_ruru"],
+ "form": {
+ "eula": {
+ "eula":false
+ },
+ "game_dir": {
+ "default": "Program Files",
+ "dirname": "Diablo III",
+ "required_space": 15032385536
+ },
+ "language": {
+ "default":["ruRU"],
+ "list":["ruRU"]
+ },
+ "authentication_key": {
+ "url": [
+ "http://ruru.nydus.battle.net/D3/ruRU/setup/mediakey",
+ "http://dist.blizzard.com/mediakey/d3-authenticationcode-ruRU.txt"
+ ]
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/dep/StormLib/doc/diablo3_urls.txt b/dep/StormLib/doc/diablo3_urls.txt
new file mode 100644
index 00000000000..d89f4899528
--- /dev/null
+++ b/dep/StormLib/doc/diablo3_urls.txt
@@ -0,0 +1,14 @@
+http://dist.blizzard.com/mediakey/d3-authenticationcode-deDE.txt
+http://dist.blizzard.com/mediakey/d3-authenticationcode-enGB.txt
+http://dist.blizzard.com/mediakey/d3-authenticationcode-enSG.txt
+http://dist.blizzard.com/mediakey/d3-authenticationcode-enUS.txt
+http://dist.blizzard.com/mediakey/d3-authenticationcode-esES.txt
+http://dist.blizzard.com/mediakey/d3-authenticationcode-esMX.txt
+http://dist.blizzard.com/mediakey/d3-authenticationcode-frFR.txt
+http://dist.blizzard.com/mediakey/d3-authenticationcode-itIT.txt
+http://dist.blizzard.com/mediakey/d3-authenticationcode-koKR.txt
+http://dist.blizzard.com/mediakey/d3-authenticationcode-plPL.txt
+http://dist.blizzard.com/mediakey/d3-authenticationcode-ptBR.txt
+http://dist.blizzard.com/mediakey/d3-authenticationcode-ruRU.txt <====
+http://dist.blizzard.com/mediakey/d3-authenticationcode-zhTW.txt
+http://dist.blizzard.com/mediakey/d3-authenticationcode-zhCN.txt <====
diff --git a/dep/StormLib/src/FileStream.cpp b/dep/StormLib/src/FileStream.cpp
new file mode 100644
index 00000000000..413f2acb3a2
--- /dev/null
+++ b/dep/StormLib/src/FileStream.cpp
@@ -0,0 +1,2294 @@
+/*****************************************************************************/
+/* FileStream.cpp Copyright (c) Ladislav Zezula 2010 */
+/*---------------------------------------------------------------------------*/
+/* File stream support for StormLib */
+/* */
+/* Windows support: Written by Ladislav Zezula */
+/* Mac support: Written by Sam Wilkins */
+/* Linux support: Written by Sam Wilkins and Ivan Komissarov */
+/* Big-endian: Written & debugged by Sam Wilkins */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 11.06.10 1.00 Lad Derived from StormPortMac.cpp and StormPortLinux.cpp */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+#include "FileStream.h"
+
+#ifdef _MSC_VER
+#pragma comment(lib, "wininet.lib")
+#endif
+
+//-----------------------------------------------------------------------------
+// Local defines
+
+#ifndef INVALID_HANDLE_VALUE
+#define INVALID_HANDLE_VALUE ((HANDLE)-1)
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(disable: 4800) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+//-----------------------------------------------------------------------------
+// Local functions - platform-specific functions
+
+#ifndef PLATFORM_WINDOWS
+static int nLastError = ERROR_SUCCESS;
+
+int GetLastError()
+{
+ return nLastError;
+}
+
+void SetLastError(int nError)
+{
+ nLastError = nError;
+}
+#endif
+
+#ifndef PLATFORM_LITTLE_ENDIAN
+void ConvertPartHeader(void * partHeader)
+{
+ PPART_FILE_HEADER theHeader = (PPART_FILE_HEADER)partHeader;
+
+ theHeader->PartialVersion = SwapUInt32(theHeader->PartialVersion);
+ theHeader->Flags = SwapUInt32(theHeader->Flags);
+ theHeader->FileSizeLo = SwapUInt32(theHeader->FileSizeLo);
+ theHeader->FileSizeHi = SwapUInt32(theHeader->FileSizeHi);
+ theHeader->BlockSize = SwapUInt32(theHeader->BlockSize);
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Preparing file bitmap for a complete file of a given size
+
+#define DEFAULT_BLOCK_SIZE 0x4000
+
+static bool Dummy_GetBitmap(
+ TFileStream * pStream,
+ TFileBitmap * pBitmap,
+ DWORD Length,
+ LPDWORD LengthNeeded)
+{
+ ULONGLONG FileSize = 0;
+ DWORD TotalLength;
+ DWORD BlockCount;
+ DWORD BitmapSize;
+ DWORD LastByte;
+ bool bResult = false;
+
+ // Get file size and calculate bitmap length
+ FileStream_GetSize(pStream, FileSize);
+ BlockCount = (DWORD)(((FileSize - 1) / DEFAULT_BLOCK_SIZE) + 1);
+ BitmapSize = (DWORD)(((BlockCount - 1) / 8) + 1);
+
+ // Calculate and give the total length
+ TotalLength = sizeof(TFileBitmap) + BitmapSize;
+ if(LengthNeeded != NULL)
+ *LengthNeeded = TotalLength;
+
+ // Has the caller given enough space for storing the structure?
+ if(Length >= sizeof(TFileBitmap))
+ {
+ memset(pBitmap, 0, sizeof(TFileBitmap));
+ pBitmap->EndOffset = FileSize;
+ pBitmap->IsComplete = 1;
+ pBitmap->BitmapSize = BitmapSize;
+ pBitmap->BlockSize = DEFAULT_BLOCK_SIZE;
+ bResult = true;
+ }
+
+ // Do we have enough space to fill the bitmap as well?
+ if(Length >= TotalLength)
+ {
+ LPBYTE pbBitmap = (LPBYTE)(pBitmap + 1);
+
+ // Fill the full blocks
+ memset(pbBitmap, 0xFF, (BlockCount / 8));
+ pbBitmap += (BlockCount / 8);
+ bResult = true;
+
+ // Supply the last block
+ if(BlockCount & 7)
+ {
+ LastByte = (1 << (BlockCount & 7)) - 1;
+ pbBitmap[0] = (BYTE)LastByte;
+ }
+ }
+
+ return bResult;
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - base file support
+
+static bool BaseFile_Read(
+ TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position
+ void * pvBuffer, // Pointer to data to be read
+ DWORD dwBytesToRead) // Number of bytes to read from the file
+{
+ ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.File.FilePos;
+ DWORD dwBytesRead = 0; // Must be set by platform-specific code
+
+#ifdef PLATFORM_WINDOWS
+ {
+ // Note: StormLib no longer supports Windows 9x.
+ // Thus, we can use the OVERLAPPED structure to specify
+ // file offset to read from file. This allows us to skip
+ // one system call to SetFilePointer
+
+ // Update the byte offset
+ pStream->Base.File.FilePos = ByteOffset;
+
+ // Read the data
+ if(dwBytesToRead != 0)
+ {
+ OVERLAPPED Overlapped;
+
+ Overlapped.OffsetHigh = (DWORD)(ByteOffset >> 32);
+ Overlapped.Offset = (DWORD)ByteOffset;
+ Overlapped.hEvent = NULL;
+ if(!ReadFile(pStream->Base.File.hFile, pvBuffer, dwBytesToRead, &dwBytesRead, &Overlapped))
+ return false;
+ }
+/*
+ // If the byte offset is different from the current file position,
+ // we have to update the file position
+ if(ByteOffset != pStream->Base.File.FilePos)
+ {
+ LONG ByteOffsetHi = (LONG)(ByteOffset >> 32);
+
+ SetFilePointer(pStream->Base.File.hFile, (LONG)ByteOffset, &ByteOffsetHi, FILE_BEGIN);
+ pStream->Base.File.FilePos = ByteOffset;
+ }
+
+ // Read the data
+ if(dwBytesToRead != 0)
+ {
+ if(!ReadFile(pStream->Base.File.hFile, pvBuffer, dwBytesToRead, &dwBytesRead, NULL))
+ return false;
+ }
+*/
+ }
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ {
+ ssize_t bytes_read;
+
+ // If the byte offset is different from the current file position,
+ // we have to update the file position
+ if(ByteOffset != pStream->Base.File.FilePos)
+ {
+ lseek((intptr_t)pStream->Base.File.hFile, (off_t)(ByteOffset), SEEK_SET);
+ pStream->Base.File.FilePos = ByteOffset;
+ }
+
+ // Perform the read operation
+ if(dwBytesToRead != 0)
+ {
+ bytes_read = read((intptr_t)pStream->Base.File.hFile, pvBuffer, (size_t)dwBytesToRead);
+ if(bytes_read == -1)
+ {
+ nLastError = errno;
+ return false;
+ }
+
+ dwBytesRead = (DWORD)(size_t)bytes_read;
+ }
+ }
+#endif
+
+ // Increment the current file position by number of bytes read
+ // If the number of bytes read doesn't match to required amount, return false
+ pStream->Base.File.FilePos = ByteOffset + dwBytesRead;
+ if(dwBytesRead != dwBytesToRead)
+ SetLastError(ERROR_HANDLE_EOF);
+ return (dwBytesRead == dwBytesToRead);
+}
+
+/**
+ * \a pStream Pointer to an open stream
+ * \a pByteOffset Pointer to file byte offset. If NULL, writes to current position
+ * \a pvBuffer Pointer to data to be written
+ * \a dwBytesToWrite Number of bytes to write to the file
+ */
+
+static bool BaseFile_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite)
+{
+ ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.File.FilePos;
+ DWORD dwBytesWritten = 0; // Must be set by platform-specific code
+
+#ifdef PLATFORM_WINDOWS
+ {
+ // Note: StormLib no longer supports Windows 9x.
+ // Thus, we can use the OVERLAPPED structure to specify
+ // file offset to read from file. This allows us to skip
+ // one system call to SetFilePointer
+
+ // Update the byte offset
+ pStream->Base.File.FilePos = ByteOffset;
+
+ // Read the data
+ if(dwBytesToWrite != 0)
+ {
+ OVERLAPPED Overlapped;
+
+ Overlapped.OffsetHigh = (DWORD)(ByteOffset >> 32);
+ Overlapped.Offset = (DWORD)ByteOffset;
+ Overlapped.hEvent = NULL;
+ if(!WriteFile(pStream->Base.File.hFile, pvBuffer, dwBytesToWrite, &dwBytesWritten, &Overlapped))
+ return false;
+ }
+/*
+ // If the byte offset is different from the current file position,
+ // we have to update the file position
+ if(ByteOffset != pStream->Base.File.FilePos)
+ {
+ LONG ByteOffsetHi = (LONG)(ByteOffset >> 32);
+
+ SetFilePointer(pStream->Base.File.hFile, (LONG)ByteOffset, &ByteOffsetHi, FILE_BEGIN);
+ pStream->Base.File.FilePos = ByteOffset;
+ }
+
+ // Read the data
+ if(dwBytesToWrite != 0)
+ {
+ if(!WriteFile(pStream->Base.File.hFile, pvBuffer, dwBytesToWrite, &dwBytesWritten, NULL))
+ return false;
+ }
+*/
+ }
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ {
+ ssize_t bytes_written;
+
+ // If the byte offset is different from the current file position,
+ // we have to update the file position
+ if(ByteOffset != pStream->Base.File.FilePos)
+ {
+ lseek((intptr_t)pStream->Base.File.hFile, (off_t)(ByteOffset), SEEK_SET);
+ pStream->Base.File.FilePos = ByteOffset;
+ }
+
+ // Perform the read operation
+ bytes_written = write((intptr_t)pStream->Base.File.hFile, pvBuffer, (size_t)dwBytesToWrite);
+ if(bytes_written == -1)
+ {
+ nLastError = errno;
+ return false;
+ }
+
+ dwBytesWritten = (DWORD)(size_t)bytes_written;
+ }
+#endif
+
+ // Increment the current file position by number of bytes read
+ pStream->Base.File.FilePos = ByteOffset + dwBytesWritten;
+
+ // Also modify the file size, if needed
+ if(pStream->Base.File.FilePos > pStream->Base.File.FileSize)
+ pStream->Base.File.FileSize = pStream->Base.File.FilePos;
+
+ if(dwBytesWritten != dwBytesToWrite)
+ SetLastError(ERROR_DISK_FULL);
+ return (dwBytesWritten == dwBytesToWrite);
+}
+
+static bool BaseFile_GetPos(
+ TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG & ByteOffset) // Pointer to file byte offset
+{
+ ByteOffset = pStream->Base.File.FilePos;
+ return true;
+}
+
+static bool BaseFile_GetSize(
+ TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG & FileSize) // Pointer where to store file size
+{
+ FileSize = pStream->Base.File.FileSize;
+ return true;
+}
+
+/**
+ * \a pStream Pointer to an open stream
+ * \a NewFileSize New size of the file
+ */
+static bool BaseFile_SetSize(TFileStream * pStream, ULONGLONG NewFileSize)
+{
+#ifdef PLATFORM_WINDOWS
+ {
+ LONG FileSizeHi = (LONG)(NewFileSize >> 32);
+ LONG FileSizeLo;
+ DWORD dwNewPos;
+ bool bResult;
+
+ // Set the position at the new file size
+ dwNewPos = SetFilePointer(pStream->Base.File.hFile, (LONG)NewFileSize, &FileSizeHi, FILE_BEGIN);
+ if(dwNewPos == INVALID_SET_FILE_POINTER && GetLastError() != ERROR_SUCCESS)
+ return false;
+
+ // Set the current file pointer as the end of the file
+ bResult = (bool)SetEndOfFile(pStream->Base.File.hFile);
+
+ // Restore the file position
+ FileSizeHi = (LONG)(pStream->Base.File.FilePos >> 32);
+ FileSizeLo = (LONG)(pStream->Base.File.FilePos);
+ SetFilePointer(pStream->Base.File.hFile, FileSizeLo, &FileSizeHi, FILE_BEGIN);
+ return bResult;
+ }
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ {
+ if(ftruncate((intptr_t)pStream->Base.File.hFile, (off_t)NewFileSize) == -1)
+ {
+ nLastError = errno;
+ return false;
+ }
+
+ return true;
+ }
+#endif
+}
+
+static bool BaseFile_GetTime(TFileStream * pStream, ULONGLONG * pFileTime)
+{
+ *pFileTime = pStream->Base.File.FileTime;
+ return true;
+}
+
+// Renames the file pointed by pStream so that it contains data from pNewStream
+static bool BaseFile_Switch(TFileStream * pStream, TFileStream * pNewStream)
+{
+#ifdef PLATFORM_WINDOWS
+ // Delete the original stream file. Don't check the result value,
+ // because if the file doesn't exist, it would fail
+ DeleteFile(pStream->szFileName);
+
+ // Rename the new file to the old stream's file
+ return (bool)MoveFile(pNewStream->szFileName, pStream->szFileName);
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ // "rename" on Linux also works if the target file exists
+ if(rename(pNewStream->szFileName, pStream->szFileName) == -1)
+ {
+ nLastError = errno;
+ return false;
+ }
+
+ return true;
+#endif
+}
+
+static void BaseFile_Close(TFileStream * pStream)
+{
+ if(pStream->Base.File.hFile != INVALID_HANDLE_VALUE)
+ {
+#ifdef PLATFORM_WINDOWS
+ CloseHandle(pStream->Base.File.hFile);
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ close((intptr_t)pStream->Base.File.hFile);
+#endif
+ }
+
+ // Also invalidate the handle
+ pStream->Base.File.hFile = INVALID_HANDLE_VALUE;
+}
+
+static bool BaseFile_Create(
+ TFileStream * pStream,
+ const TCHAR * szFileName,
+ DWORD dwStreamFlags)
+{
+#ifdef PLATFORM_WINDOWS
+ {
+ DWORD dwWriteShare = (dwStreamFlags & STREAM_FLAG_WRITE_SHARE) ? FILE_SHARE_WRITE : 0;
+
+ pStream->Base.File.hFile = CreateFile(szFileName,
+ GENERIC_READ | GENERIC_WRITE,
+ dwWriteShare | FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ 0,
+ NULL);
+ if(pStream->Base.File.hFile == INVALID_HANDLE_VALUE)
+ return false;
+ }
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ {
+ intptr_t handle;
+
+ handle = open(szFileName, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if(handle == -1)
+ {
+ nLastError = errno;
+ return false;
+ }
+
+ pStream->Base.File.hFile = (HANDLE)handle;
+ }
+#endif
+
+ // Fill-in the entry points
+ pStream->BaseRead = BaseFile_Read;
+ pStream->BaseWrite = BaseFile_Write;
+ pStream->BaseGetPos = BaseFile_GetPos;
+ pStream->BaseGetSize = BaseFile_GetSize;
+ pStream->BaseSetSize = BaseFile_SetSize;
+ pStream->BaseSetSize = BaseFile_SetSize;
+ pStream->BaseGetTime = BaseFile_GetTime;
+ pStream->BaseClose = BaseFile_Close;
+
+ // Reset the file position
+ pStream->Base.File.FileSize = 0;
+ pStream->Base.File.FilePos = 0;
+ pStream->dwFlags = dwStreamFlags;
+ return true;
+}
+
+static bool BaseFile_Open(
+ TFileStream * pStream,
+ const TCHAR * szFileName,
+ DWORD dwStreamFlags)
+{
+#ifdef PLATFORM_WINDOWS
+ {
+ ULARGE_INTEGER FileSize;
+ DWORD dwDesiredAccess = (dwStreamFlags & STREAM_FLAG_READ_ONLY) ? GENERIC_READ : GENERIC_ALL;
+ DWORD dwWriteShare = (dwStreamFlags & STREAM_FLAG_WRITE_SHARE) ? FILE_SHARE_WRITE : 0;
+
+ // Open the file
+ pStream->Base.File.hFile = CreateFile(szFileName,
+ dwDesiredAccess,
+ dwWriteShare | FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ if(pStream->Base.File.hFile == INVALID_HANDLE_VALUE)
+ return false;
+
+ // Query the file size
+ FileSize.LowPart = GetFileSize(pStream->Base.File.hFile, &FileSize.HighPart);
+ pStream->Base.File.FileSize = FileSize.QuadPart;
+
+ // Query last write time
+ GetFileTime(pStream->Base.File.hFile, NULL, NULL, (LPFILETIME)&pStream->Base.File.FileTime);
+ }
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ {
+ struct stat fileinfo;
+ int oflag = (dwStreamFlags & STREAM_FLAG_READ_ONLY) ? O_RDONLY : O_RDWR;
+ intptr_t handle;
+
+ // Open the file
+ handle = open(szFileName, oflag);
+ if(handle == -1)
+ {
+ nLastError = errno;
+ return false;
+ }
+
+ // Get the file size
+ if(fstat(handle, &fileinfo) == -1)
+ {
+ nLastError = errno;
+ return false;
+ }
+
+ // time_t is number of seconds since 1.1.1970, UTC.
+ // 1 second = 10000000 (decimal) in FILETIME
+ // Set the start to 1.1.1970 00:00:00
+ pStream->Base.File.FileTime = 0x019DB1DED53E8000ULL + (10000000 * fileinfo.st_mtime);
+ pStream->Base.File.FileSize = (ULONGLONG)fileinfo.st_size;
+ pStream->Base.File.hFile = (HANDLE)handle;
+ }
+#endif
+
+ // Fill-in the entry points
+ pStream->BaseRead = BaseFile_Read;
+ pStream->BaseWrite = BaseFile_Write;
+ pStream->BaseGetPos = BaseFile_GetPos;
+ pStream->BaseGetSize = BaseFile_GetSize;
+ pStream->BaseSetSize = BaseFile_SetSize;
+ pStream->BaseGetTime = BaseFile_GetTime;
+ pStream->BaseClose = BaseFile_Close;
+
+ // Reset the file position
+ pStream->Base.File.FilePos = 0;
+ pStream->dwFlags = dwStreamFlags;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - base memory-mapped file support
+
+static bool BaseMap_Read(
+ TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position
+ void * pvBuffer, // Pointer to data to be read
+ DWORD dwBytesToRead) // Number of bytes to read from the file
+{
+ ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.Map.FilePos;
+
+ // Do we have to read anything at all?
+ if(dwBytesToRead != 0)
+ {
+ // Don't allow reading past file size
+ if((ByteOffset + dwBytesToRead) > pStream->Base.Map.FileSize)
+ return false;
+
+ // Copy the required data
+ memcpy(pvBuffer, pStream->Base.Map.pbFile + (size_t)ByteOffset, dwBytesToRead);
+ }
+
+ // Move the current file position
+ pStream->Base.Map.FilePos += dwBytesToRead;
+ return true;
+}
+
+static bool BaseMap_GetPos(
+ TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG & ByteOffset) // Pointer to file byte offset
+{
+ ByteOffset = pStream->Base.Map.FilePos;
+ return true;
+}
+
+static bool BaseMap_GetSize(
+ TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG & FileSize) // Pointer where to store file size
+{
+ FileSize = pStream->Base.Map.FileSize;
+ return true;
+}
+
+static bool BaseMap_GetTime(TFileStream * pStream, ULONGLONG * pFileTime)
+{
+ *pFileTime = pStream->Base.Map.FileTime;
+ return true;
+}
+
+static void BaseMap_Close(TFileStream * pStream)
+{
+#ifdef PLATFORM_WINDOWS
+ if(pStream->Base.Map.pbFile != NULL)
+ UnmapViewOfFile(pStream->Base.Map.pbFile);
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ if(pStream->Base.Map.pbFile != NULL)
+ munmap(pStream->Base.Map.pbFile, (size_t )pStream->Base.Map.FileSize);
+#endif
+
+ pStream->Base.Map.pbFile = NULL;
+}
+
+static bool BaseMap_Open(
+ TFileStream * pStream,
+ const TCHAR * szFileName,
+ DWORD dwStreamFlags)
+{
+#ifdef PLATFORM_WINDOWS
+
+ ULARGE_INTEGER FileSize;
+ HANDLE hFile;
+ HANDLE hMap;
+ bool bResult = false;
+
+ // Open the file for read access
+ hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if(hFile != NULL)
+ {
+ // Retrieve file size. Don't allow mapping file of a zero size.
+ FileSize.LowPart = GetFileSize(hFile, &FileSize.HighPart);
+ if(FileSize.QuadPart != 0)
+ {
+ // Retrieve file time
+ GetFileTime(hFile, NULL, NULL, (LPFILETIME)&pStream->Base.Map.FileTime);
+
+ // Now create mapping object
+ hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+ if(hMap != NULL)
+ {
+ // Map the entire view into memory
+ // Note that this operation will fail if the file can't fit
+ // into usermode address space
+ pStream->Base.Map.pbFile = (LPBYTE)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
+ if(pStream->Base.Map.pbFile != NULL)
+ {
+ pStream->Base.Map.FileSize = FileSize.QuadPart;
+ pStream->Base.Map.FilePos = 0;
+ bResult = true;
+ }
+
+ // Close the map handle
+ CloseHandle(hMap);
+ }
+ }
+
+ // Close the file handle
+ CloseHandle(hFile);
+ }
+
+ // If the file is not there and is not available for random access,
+ // report error
+ if(bResult == false)
+ return false;
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ struct stat fileinfo;
+ intptr_t handle;
+ bool bResult = false;
+
+ // Open the file
+ handle = open(szFileName, O_RDONLY);
+ if(handle != -1)
+ {
+ // Get the file size
+ if(fstat(handle, &fileinfo) != -1)
+ {
+ pStream->Base.Map.pbFile = (LPBYTE)mmap(NULL, (size_t)fileinfo.st_size, PROT_READ, MAP_PRIVATE, handle, 0);
+ if(pStream->Base.Map.pbFile != NULL)
+ {
+ // time_t is number of seconds since 1.1.1970, UTC.
+ // 1 second = 10000000 (decimal) in FILETIME
+ // Set the start to 1.1.1970 00:00:00
+ pStream->Base.Map.FileTime = 0x019DB1DED53E8000ULL + (10000000 * fileinfo.st_mtime);
+ pStream->Base.Map.FileSize = (ULONGLONG)fileinfo.st_size;
+ pStream->Base.Map.FilePos = 0;
+ bResult = true;
+ }
+ }
+ close(handle);
+ }
+
+ // Did the mapping fail?
+ if(bResult == false)
+ {
+ nLastError = errno;
+ return false;
+ }
+#endif
+
+ // Fill-in entry points
+ pStream->BaseRead = BaseMap_Read;
+ pStream->BaseGetPos = BaseMap_GetPos;
+ pStream->BaseGetSize = BaseMap_GetSize;
+ pStream->BaseGetTime = BaseMap_GetTime;
+ pStream->BaseClose = BaseMap_Close;
+ pStream->dwFlags = dwStreamFlags;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - base HTTP file support
+
+static const TCHAR * BaseHttp_ExtractServerName(const TCHAR * szFileName, TCHAR * szServerName)
+{
+ // Check for HTTP
+ if(!_tcsnicmp(szFileName, _T("http://"), 7))
+ szFileName += 7;
+
+ // Cut off the server name
+ if(szServerName != NULL)
+ {
+ while(szFileName[0] != 0 && szFileName[0] != _T('/'))
+ *szServerName++ = *szFileName++;
+ *szServerName = 0;
+ }
+ else
+ {
+ while(szFileName[0] != 0 && szFileName[0] != _T('/'))
+ *szFileName++;
+ }
+
+ // Return the remainder
+ return szFileName;
+}
+
+static bool BaseHttp_Read(
+ TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position
+ void * pvBuffer, // Pointer to data to be read
+ DWORD dwBytesToRead) // Number of bytes to read from the file
+{
+#ifdef PLATFORM_WINDOWS
+ ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.Http.FilePos;
+ DWORD dwTotalBytesRead = 0;
+
+ // Do we have to read anything at all?
+ if(dwBytesToRead != 0)
+ {
+ HINTERNET hRequest;
+ LPCTSTR szFileName;
+ LPBYTE pbBuffer = (LPBYTE)pvBuffer;
+ TCHAR szRangeRequest[0x80];
+ DWORD dwStartOffset = (DWORD)ByteOffset;
+ DWORD dwEndOffset = dwStartOffset + dwBytesToRead;
+ BYTE Buffer[0x200];
+
+ // Open HTTP request to the file
+ szFileName = BaseHttp_ExtractServerName(pStream->szFileName, NULL);
+ hRequest = HttpOpenRequest(pStream->Base.Http.hConnect, _T("GET"), szFileName, NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0);
+ if(hRequest != NULL)
+ {
+ // Add range request to the HTTP headers
+ // http://www.clevercomponents.com/articles/article015/resuming.asp
+ _stprintf(szRangeRequest, _T("Range: bytes=%d-%d"), dwStartOffset, dwEndOffset);
+ HttpAddRequestHeaders(hRequest, szRangeRequest, 0xFFFFFFFF, HTTP_ADDREQ_FLAG_ADD_IF_NEW);
+
+ // Send the request to the server
+ if(HttpSendRequest(hRequest, NULL, 0, NULL, 0))
+ {
+ while(dwTotalBytesRead < dwBytesToRead)
+ {
+ DWORD dwBlockBytesToRead = dwBytesToRead - dwTotalBytesRead;
+ DWORD dwBlockBytesRead = 0;
+
+ // Read the block from the file
+ if(dwBlockBytesToRead > sizeof(Buffer))
+ dwBlockBytesToRead = sizeof(Buffer);
+ InternetReadFile(hRequest, pbBuffer, dwBlockBytesToRead, &dwBlockBytesRead);
+
+ // Check for end
+ if(dwBlockBytesRead == 0)
+ break;
+
+ // Move buffers
+ dwTotalBytesRead += dwBlockBytesRead;
+ pbBuffer += dwBlockBytesRead;
+ }
+ }
+ InternetCloseHandle(hRequest);
+ }
+ }
+
+ // Increment the current file position by number of bytes read
+ pStream->Base.Http.FilePos = ByteOffset + dwTotalBytesRead;
+
+ // If the number of bytes read doesn't match the required amount, return false
+ if(dwTotalBytesRead != dwBytesToRead)
+ SetLastError(ERROR_HANDLE_EOF);
+ return (dwTotalBytesRead == dwBytesToRead);
+
+#else
+
+ // Not supported
+ pStream = pStream;
+ pByteOffset = pByteOffset;
+ pvBuffer = pvBuffer;
+ dwBytesToRead = dwBytesToRead;
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return false;
+
+#endif
+}
+
+static bool BaseHttp_GetPos(
+ TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG & ByteOffset) // Pointer to file byte offset
+{
+ ByteOffset = pStream->Base.Http.FilePos;
+ return true;
+}
+
+static bool BaseHttp_GetSize(
+ TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG & FileSize) // Pointer where to store file size
+{
+ FileSize = pStream->Base.Http.FileSize;
+ return true;
+}
+
+static bool BaseHttp_GetTime(TFileStream * pStream, ULONGLONG * pFileTime)
+{
+ *pFileTime = pStream->Base.Http.FileTime;
+ return true;
+}
+
+static void BaseHttp_Close(TFileStream * pStream)
+{
+#ifdef PLATFORM_WINDOWS
+ if(pStream->Base.Http.hConnect != NULL)
+ InternetCloseHandle(pStream->Base.Http.hConnect);
+ pStream->Base.Http.hConnect = NULL;
+
+ if(pStream->Base.Http.hInternet != NULL)
+ InternetCloseHandle(pStream->Base.Http.hInternet);
+ pStream->Base.Http.hInternet = NULL;
+#else
+ pStream = pStream;
+#endif
+}
+
+static bool BaseHttp_Open(
+ TFileStream * pStream,
+ const TCHAR * szFileName,
+ DWORD dwStreamFlags)
+{
+#ifdef PLATFORM_WINDOWS
+
+ HINTERNET hRequest;
+ DWORD dwTemp = 0;
+ bool bFileAvailable = false;
+ int nError = ERROR_SUCCESS;
+
+ // Don't connect to the internet
+ if(!InternetGetConnectedState(&dwTemp, 0))
+ nError = GetLastError();
+
+ // Initiate the connection to the internet
+ if(nError == ERROR_SUCCESS)
+ {
+ pStream->Base.Http.hInternet = InternetOpen(_T("StormLib HTTP MPQ reader"),
+ INTERNET_OPEN_TYPE_PRECONFIG,
+ NULL,
+ NULL,
+ 0);
+ if(pStream->Base.Http.hInternet == NULL)
+ nError = GetLastError();
+ }
+
+ // Connect to the server
+ if(nError == ERROR_SUCCESS)
+ {
+ TCHAR szServerName[MAX_PATH];
+ DWORD dwFlags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_UI | INTERNET_FLAG_NO_CACHE_WRITE;
+
+ // Initiate connection with the server
+ szFileName = BaseHttp_ExtractServerName(szFileName, szServerName);
+ pStream->Base.Http.hConnect = InternetConnect(pStream->Base.Http.hInternet,
+ szServerName,
+ INTERNET_DEFAULT_HTTP_PORT,
+ NULL,
+ NULL,
+ INTERNET_SERVICE_HTTP,
+ dwFlags,
+ 0);
+ if(pStream->Base.Http.hConnect == NULL)
+ nError = GetLastError();
+ }
+
+ // Now try to query the file size
+ if(nError == ERROR_SUCCESS)
+ {
+ // Open HTTP request to the file
+ hRequest = HttpOpenRequest(pStream->Base.Http.hConnect, _T("GET"), szFileName, NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0);
+ if(hRequest != NULL)
+ {
+ if(HttpSendRequest(hRequest, NULL, 0, NULL, 0))
+ {
+ ULONGLONG FileTime = 0;
+ DWORD dwFileSize = 0;
+ DWORD dwDataSize;
+ DWORD dwIndex = 0;
+
+ // Check if the MPQ has Last Modified field
+ dwDataSize = sizeof(ULONGLONG);
+ if(HttpQueryInfo(hRequest, HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME, &FileTime, &dwDataSize, &dwIndex))
+ pStream->Base.Http.FileTime = FileTime;
+
+ // Verify if the server supports random access
+ dwDataSize = sizeof(DWORD);
+ if(HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwFileSize, &dwDataSize, &dwIndex))
+ {
+ if(dwFileSize != 0)
+ {
+ pStream->Base.Http.FileSize = dwFileSize;
+ pStream->Base.Http.FilePos = 0;
+ bFileAvailable = true;
+ }
+ }
+ }
+ InternetCloseHandle(hRequest);
+ }
+ }
+
+ // If the file is not there and is not available for random access,
+ // report error
+ if(bFileAvailable == false)
+ {
+ BaseHttp_Close(pStream);
+ return false;
+ }
+
+ // Fill-in entry points
+ pStream->BaseRead = BaseHttp_Read;
+ pStream->BaseGetPos = BaseHttp_GetPos;
+ pStream->BaseGetSize = BaseHttp_GetSize;
+ pStream->BaseGetTime = BaseHttp_GetTime;
+ pStream->BaseClose = BaseHttp_Close;
+ pStream->dwFlags = dwStreamFlags;
+ return true;
+
+#else
+
+ // Not supported
+ pStream = pStream;
+ szFileName = szFileName;
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return false;
+
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - linear stream support
+
+static bool LinearStream_Read(
+ TLinearStream * pStream, // Pointer to an open stream
+ ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position
+ void * pvBuffer, // Pointer to data to be read
+ DWORD dwBytesToRead) // Number of bytes to read from the file
+{
+ ULONGLONG ByteOffset;
+ ULONGLONG EndOffset;
+ LPBYTE pbBitmap;
+ DWORD BlockIndex;
+ DWORD ByteIndex;
+ DWORD BitMask;
+
+ // At this point, we must have a bitmap set
+ assert(pStream->pBitmap != NULL);
+
+ // If we have data map, we must check if the data block is present in the MPQ
+ if(dwBytesToRead != 0)
+ {
+ DWORD BlockSize = pStream->pBitmap->BlockSize;
+
+ // Get the offset where we read it from
+ if(pByteOffset == NULL)
+ pStream->BaseGetPos(pStream, ByteOffset);
+ else
+ ByteOffset = *pByteOffset;
+ EndOffset = ByteOffset + dwBytesToRead;
+
+ // If the start of the area is within the region
+ // protected by data map, check each block
+ if(ByteOffset < pStream->pBitmap->EndOffset)
+ {
+ // Cut the end of the stream protected by the data map
+ EndOffset = STORMLIB_MIN(EndOffset, pStream->pBitmap->EndOffset);
+
+ // Calculate the initial block index
+ BlockIndex = (DWORD)(ByteOffset / BlockSize);
+ pbBitmap = (LPBYTE)(pStream->pBitmap + 1);
+
+ // Parse each block
+ while(ByteOffset < EndOffset)
+ {
+ // Prepare byte index and bit mask
+ ByteIndex = BlockIndex / 8;
+ BitMask = 1 << (BlockIndex & 0x07);
+
+ // If that bit is not set, it means that the block is not present
+ if((pbBitmap[ByteIndex] & BitMask) == 0)
+ {
+ SetLastError(ERROR_FILE_CORRUPT);
+ return false;
+ }
+
+ // Move to tne next block
+ ByteOffset += BlockSize;
+ BlockIndex++;
+ }
+ }
+ }
+
+ // Now if all tests passed, we can call the base read function
+ return pStream->BaseRead(pStream, pByteOffset, pvBuffer, dwBytesToRead);
+}
+
+static bool LinearStream_Switch(TLinearStream * pStream, TLinearStream * pNewStream)
+{
+ // Sanity checks
+ assert((pNewStream->dwFlags & STREAM_PROVIDER_MASK) == STREAM_PROVIDER_LINEAR);
+ assert((pNewStream->dwFlags & BASE_PROVIDER_MASK) == BASE_PROVIDER_FILE);
+ assert((pStream->dwFlags & STREAM_PROVIDER_MASK) == STREAM_PROVIDER_LINEAR);
+ assert((pStream->dwFlags & BASE_PROVIDER_MASK) == BASE_PROVIDER_FILE);
+
+ // Close the new stream
+ pNewStream->BaseClose(pNewStream);
+
+ // Close the source stream
+ pStream->BaseClose(pStream);
+
+ // Rename the new data source file to the existing file
+ if(!BaseFile_Switch(pStream, pNewStream))
+ return false;
+
+ // Now we have to open the "pStream" again
+ if(!BaseFile_Open(pStream, pStream->szFileName, pNewStream->dwFlags))
+ return false;
+
+ // We need to cleanup the new data stream
+ FileStream_Close(pNewStream);
+ return true;
+}
+
+static bool LinearStream_GetBitmap(
+ TLinearStream * pStream,
+ TFileBitmap * pBitmap,
+ DWORD Length,
+ LPDWORD LengthNeeded)
+{
+ DWORD TotalLength;
+ bool bResult = false;
+
+ // Assumed that we have bitmap now
+ assert(pStream->pBitmap != NULL);
+
+ // Give the bitmap length
+ TotalLength = sizeof(TFileBitmap) + pStream->pBitmap->BitmapSize;
+ if(LengthNeeded != NULL)
+ *LengthNeeded = TotalLength;
+
+ // Do we have enough space to fill at least the bitmap structure?
+ if(Length >= sizeof(TFileBitmap))
+ {
+ // Enough space for complete bitmap?
+ if(Length >= TotalLength)
+ {
+ memcpy(pBitmap, pStream->pBitmap, TotalLength);
+ bResult = true;
+ }
+ else
+ {
+ memcpy(pBitmap, pStream->pBitmap, sizeof(TFileBitmap));
+ bResult = true;
+ }
+ }
+
+ return bResult;
+}
+
+static void LinearStream_Close(TLinearStream * pStream)
+{
+ // Free the data map, if any
+ if(pStream->pBitmap != NULL)
+ STORM_FREE(pStream->pBitmap);
+ pStream->pBitmap = NULL;
+
+ // Call the base class for closing the stream
+ return pStream->BaseClose(pStream);
+}
+
+static bool LinearStream_Open(TLinearStream * pStream)
+{
+ // No extra work here really; just set entry points
+ pStream->StreamRead = pStream->BaseRead;
+ pStream->StreamWrite = pStream->BaseWrite;
+ pStream->StreamGetPos = pStream->BaseGetPos;
+ pStream->StreamGetSize = pStream->BaseGetSize;
+ pStream->StreamSetSize = pStream->BaseSetSize;
+ pStream->StreamGetTime = pStream->BaseGetTime;
+ pStream->StreamGetBmp = (STREAM_GETBMP)Dummy_GetBitmap;
+ pStream->StreamSwitch = (STREAM_SWITCH)LinearStream_Switch;
+ pStream->StreamClose = (STREAM_CLOSE)LinearStream_Close;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - partial stream support
+
+static bool IsPartHeader(PPART_FILE_HEADER pPartHdr)
+{
+ // Version number must be 2
+ if(pPartHdr->PartialVersion == 2)
+ {
+ // GameBuildNumber must be an ASCII number
+ if(isdigit(pPartHdr->GameBuildNumber[0]) && isdigit(pPartHdr->GameBuildNumber[1]) && isdigit(pPartHdr->GameBuildNumber[2]))
+ {
+ // Block size must be power of 2
+ if((pPartHdr->BlockSize & (pPartHdr->BlockSize - 1)) == 0)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool PartialStream_Read(
+ TPartialStream * pStream,
+ ULONGLONG * pByteOffset,
+ void * pvBuffer,
+ DWORD dwBytesToRead)
+{
+ ULONGLONG RawByteOffset;
+ LPBYTE pbBuffer = (LPBYTE)pvBuffer;
+ DWORD dwBytesRemaining = dwBytesToRead;
+ DWORD dwPartOffset;
+ DWORD dwPartIndex;
+ DWORD dwBytesRead = 0;
+ DWORD dwBlockSize = pStream->BlockSize;
+ bool bResult = false;
+ int nFailReason = ERROR_HANDLE_EOF; // Why it failed if not enough bytes was read
+
+ // If the byte offset is not entered, use the current position
+ if(pByteOffset == NULL)
+ pByteOffset = &pStream->VirtualPos;
+
+ // Check if the file position is not at or beyond end of the file
+ if(*pByteOffset >= pStream->VirtualSize)
+ {
+ SetLastError(ERROR_HANDLE_EOF);
+ return false;
+ }
+
+ // Get the part index where the read offset is
+ // Note that the part index should now be within the range,
+ // as read requests beyond-EOF are handled by the previous test
+ dwPartIndex = (DWORD)(*pByteOffset / pStream->BlockSize);
+ assert(dwPartIndex < pStream->BlockCount);
+
+ // If the number of bytes remaining goes past
+ // the end of the file, cut them
+ if((*pByteOffset + dwBytesRemaining) > pStream->VirtualSize)
+ dwBytesRemaining = (DWORD)(pStream->VirtualSize - *pByteOffset);
+
+ // Calculate the offset in the current part
+ dwPartOffset = (DWORD)(*pByteOffset) & (pStream->BlockSize - 1);
+
+ // Read all data, one part at a time
+ while(dwBytesRemaining != 0)
+ {
+ PPART_FILE_MAP_ENTRY PartMap = pStream->PartMap + dwPartIndex;
+ DWORD dwBytesInPart;
+
+ // If the part is not present in the file, we fail the read
+ if((PartMap->Flags & 3) == 0)
+ {
+ nFailReason = ERROR_FILE_CORRUPT;
+ bResult = false;
+ break;
+ }
+
+ // If we are in the last part, we have to cut the number of bytes in the last part
+ if(dwPartIndex == pStream->BlockCount - 1)
+ dwBlockSize = (DWORD)pStream->VirtualSize & (pStream->BlockSize - 1);
+
+ // Get the number of bytes reamining in the current part
+ dwBytesInPart = dwBlockSize - dwPartOffset;
+
+ // Compute the raw file offset of the file part
+ RawByteOffset = MAKE_OFFSET64(PartMap->BlockOffsHi, PartMap->BlockOffsLo);
+ if(RawByteOffset == 0)
+ {
+ nFailReason = ERROR_FILE_CORRUPT;
+ bResult = false;
+ break;
+ }
+
+ // If the number of bytes in part is too big, cut it
+ if(dwBytesInPart > dwBytesRemaining)
+ dwBytesInPart = dwBytesRemaining;
+
+ // Append the offset within the part
+ RawByteOffset += dwPartOffset;
+ if(!pStream->BaseRead(pStream, &RawByteOffset, pbBuffer, dwBytesInPart))
+ {
+ nFailReason = ERROR_FILE_CORRUPT;
+ bResult = false;
+ break;
+ }
+
+ // Increment the file position
+ dwBytesRemaining -= dwBytesInPart;
+ dwBytesRead += dwBytesInPart;
+ pbBuffer += dwBytesInPart;
+
+ // Move to the next file part
+ dwPartOffset = 0;
+ dwPartIndex++;
+ }
+
+ // Move the file position by the number of bytes read
+ pStream->VirtualPos = *pByteOffset + dwBytesRead;
+ if(dwBytesRead != dwBytesToRead)
+ SetLastError(nFailReason);
+ return (dwBytesRead == dwBytesToRead);
+}
+
+static bool PartialStream_GetPos(
+ TPartialStream * pStream,
+ ULONGLONG & ByteOffset)
+{
+ ByteOffset = pStream->VirtualPos;
+ return true;
+}
+
+static bool PartialStream_GetSize(
+ TPartialStream * pStream, // Pointer to an open stream
+ ULONGLONG & FileSize) // Pointer where to store file size
+{
+ FileSize = pStream->VirtualSize;
+ return true;
+}
+
+static bool PartialStream_GetBitmap(
+ TPartialStream * pStream,
+ TFileBitmap * pBitmap,
+ DWORD Length,
+ LPDWORD LengthNeeded)
+{
+ LPBYTE pbBitmap;
+ DWORD TotalLength;
+ DWORD BitmapSize = 0;
+ DWORD ByteOffset;
+ DWORD BitMask;
+ bool bResult = false;
+
+ // Do we have stream bitmap?
+ BitmapSize = ((pStream->BlockCount - 1) / 8) + 1;
+
+ // Give the bitmap length
+ TotalLength = sizeof(TFileBitmap) + BitmapSize;
+ if(LengthNeeded != NULL)
+ *LengthNeeded = TotalLength;
+
+ // Do we have enough to fill at least the header?
+ if(Length >= sizeof(TFileBitmap))
+ {
+ // Fill the bitmap header
+ pBitmap->StartOffset = 0;
+ pBitmap->EndOffset = pStream->VirtualSize;
+ pBitmap->IsComplete = 1;
+ pBitmap->BitmapSize = BitmapSize;
+ pBitmap->BlockSize = pStream->BlockSize;
+ pBitmap->Reserved = 0;
+
+ // Is there at least one incomplete block?
+ for(DWORD i = 0; i < pStream->BlockCount; i++)
+ {
+ if(pStream->PartMap[i].Flags != 3)
+ {
+ pBitmap->IsComplete = 0;
+ break;
+ }
+ }
+
+ bResult = true;
+ }
+
+ // Do we have enough space for supplying the bitmap?
+ if(Length >= TotalLength)
+ {
+ // Fill the file bitmap
+ pbBitmap = (LPBYTE)(pBitmap + 1);
+ for(DWORD i = 0; i < pStream->BlockCount; i++)
+ {
+ // Is the block there?
+ if(pStream->PartMap[i].Flags == 3)
+ {
+ ByteOffset = i / 8;
+ BitMask = 1 << (i & 7);
+ pbBitmap[ByteOffset] |= BitMask;
+ }
+ }
+ bResult = true;
+ }
+
+ return bResult;
+}
+
+static void PartialStream_Close(TPartialStream * pStream)
+{
+ // Free the part map
+ if(pStream->PartMap != NULL)
+ STORM_FREE(pStream->PartMap);
+ pStream->PartMap = NULL;
+
+ // Clear variables
+ pStream->VirtualSize = 0;
+ pStream->VirtualPos = 0;
+
+ // Close the base stream
+ assert(pStream->BaseClose != NULL);
+ pStream->BaseClose(pStream);
+}
+
+static bool PartialStream_Open(TPartialStream * pStream)
+{
+ PART_FILE_HEADER PartHdr;
+ ULONGLONG VirtualSize; // Size of the file stored in part file
+ ULONGLONG ByteOffset = {0};
+ DWORD BlockCount;
+
+ // Sanity check
+ assert(pStream->BaseRead != NULL);
+
+ // Attempt to read PART file header
+ if(pStream->BaseRead(pStream, &ByteOffset, &PartHdr, sizeof(PART_FILE_HEADER)))
+ {
+ // We need to swap PART file header on big-endian platforms
+ BSWAP_PART_HEADER(&PartHdr);
+
+ // Verify the PART file header
+ if(IsPartHeader(&PartHdr))
+ {
+ // Calculate the number of parts in the file
+ VirtualSize = MAKE_OFFSET64(PartHdr.FileSizeHi, PartHdr.FileSizeLo);
+ assert(VirtualSize != 0);
+ BlockCount = (DWORD)((VirtualSize + PartHdr.BlockSize - 1) / PartHdr.BlockSize);
+
+ // Allocate the map entry array
+ pStream->PartMap = STORM_ALLOC(PART_FILE_MAP_ENTRY, BlockCount);
+ if(pStream->PartMap != NULL)
+ {
+ // Load the block map
+ if(pStream->BaseRead(pStream, NULL, pStream->PartMap, BlockCount * sizeof(PART_FILE_MAP_ENTRY)))
+ {
+ // Swap the array of file map entries
+ BSWAP_ARRAY32_UNSIGNED(pStream->PartMap, BlockCount * sizeof(PART_FILE_MAP_ENTRY));
+
+ // Fill the members of PART file stream
+ pStream->VirtualSize = ((ULONGLONG)PartHdr.FileSizeHi) + PartHdr.FileSizeLo;
+ pStream->VirtualPos = 0;
+ pStream->BlockCount = BlockCount;
+ pStream->BlockSize = PartHdr.BlockSize;
+
+ // Set new function pointers
+ pStream->StreamRead = (STREAM_READ)PartialStream_Read;
+ pStream->StreamGetPos = (STREAM_GETPOS)PartialStream_GetPos;
+ pStream->StreamGetSize = (STREAM_GETSIZE)PartialStream_GetSize;
+ pStream->StreamGetTime = pStream->BaseGetTime;
+ pStream->StreamGetTime = pStream->BaseGetTime;
+ pStream->StreamGetBmp = (STREAM_GETBMP)PartialStream_GetBitmap;
+ pStream->StreamClose = (STREAM_CLOSE)PartialStream_Close;
+ return true;
+ }
+
+ // Free the part map
+ STORM_FREE(pStream->PartMap);
+ pStream->PartMap = NULL;
+ }
+ }
+ }
+
+ SetLastError(ERROR_BAD_FORMAT);
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - encrypted stream support
+
+// Note: Starcraft II - Installer.exe (4.1.1.4219): Suffix derived from battle.net auth. code
+// Address of decryption routine: 0053A3D0 http://us.battle.net/static/mediakey/sc2-authenticationcode-enUS.txt
+// Pointer to decryptor object: ECX Numbers mean offset of 4-char group of auth code (follows in comment)
+// Pointer to key: ECX+0x5C -0C- -1C--08- -18--04- -14--00- -10-
+static const char * MpqeKey_Starcraft2_Install_deDE = "expand 32-byte kSSXH00004XFXK4KX00008EKJD3CA0000Y64ZY45M0000YD9V"; // Y45MD3CAK4KXSSXHYD9VY64Z8EKJ4XFX
+static const char * MpqeKey_Starcraft2_Install_enGB = "expand 32-byte kANGY000029ZH6NA20000HRGF8UDG0000NY82G8MN00006A3D"; // G8MN8UDG6NA2ANGY6A3DNY82HRGF29ZH
+static const char * MpqeKey_Starcraft2_Install_enSG = "expand 32-byte kWW5B0000F7HWFDU90000FWZSHLB20000BLRSW9RR00003ECE"; // W9RRHLB2FDU9WW5B3ECEBLRSFWZSF7HW
+static const char * MpqeKey_Starcraft2_Install_enUS = "expand 32-byte kTFD80000ETR5VM5G0000K859RE5N0000WT6F3DH500005LXG"; // 3DH5RE5NVM5GTFD85LXGWT6FK859ETR5
+static const char * MpqeKey_Starcraft2_Install_esES = "expand 32-byte kQU4Y0000XKTQ94PF0000N4R4UAXE0000AZ248WLK0000249P"; // 8WLKUAXE94PFQU4Y249PAZ24N4R4XKTQ
+static const char * MpqeKey_Starcraft2_Install_esMX = "expand 32-byte kSQBR00004G54HGGX0000MF9GXX3V0000FFDXA34D0000FE5U"; // A34DXX3VHGGXSQBRFE5UFFDXMF9G4G54
+static const char * MpqeKey_Starcraft2_Install_frFR = "expand 32-byte kFWPQ00006EAJ8HJE0000PFER9K9300008MA2ZG7J0000UA76"; // ZG7J9K938HJEFWPQUA768MA2PFER6EAJ
+static const char * MpqeKey_Starcraft2_Install_itIT = "expand 32-byte kXV7E00008BL2TVAP0000GVMWUNNN0000SVBWNE7C00003G2B"; // NE7CUNNNTVAPXV7E3G2BSVBWGVMW8BL2
+static const char * MpqeKey_Starcraft2_Install_koKR = "expand 32-byte kQWK70000838FBM9Q0000WQDB2FTM0000MWAZ3V9E0000U6MA"; // 3V9E2FTMBM9QQWK7U6MAMWAZWQDB838F
+static const char * MpqeKey_Starcraft2_Install_plPL = "expand 32-byte k83U6000048L6LULJ00004MQDB8ME0000UP6K2NSF0000YHA3"; // 2NSFB8MELULJ83U6YHA3UP6K4MQD48L6
+static const char * MpqeKey_Starcraft2_Install_ptBR = "expand 32-byte kU8BM0000SW4EZ4CU00005F9CZ9EW0000CTY6QA2T0000B5WX"; // QA2TZ9EWZ4CUU8BMB5WXCTY65F9CSW4E
+static const char * MpqeKey_Starcraft2_Install_ruRU = "expand 32-byte k9SH70000YEGT4BAT0000QDK978W60000V9NLVHB30000D68V"; // VHB378W64BAT9SH7D68VV9NLQDK9YEGT
+static const char * MpqeKey_Starcraft2_Install_zhTW = "expand 32-byte k7KBN0000D9NEM6GC0000N3PLQJV400003BRDU3NF00009XQJ"; // U3NFQJV4M6GC7KBN9XQJ3BRDN3PLD9NE
+
+// Note: Diablo III: Agent.exe (1.0.0.954): Suffix derived from battle.net auth. code
+// Address of decryption routine: 00502b00 http://dist.blizzard.com/mediakey/d3-authenticationcode-enGB.txt
+// Pointer to decryptor object: ECX Numbers mean offset of 4-char group of auth code (follows in comment)
+// Pointer to key: ECX+0x5C -0C- -1C--08- -18--04- -14--00- -10-
+static const char * MpqeKey_Diablo3_Install_deDE = "expand 32-byte kEFH40000QRZKY3520000XC9MF6EJ0000CFH2UCMX0000XFRX"; // UCMXF6EJY352EFH4XFRXCFH2XC9MQRZK
+static const char * MpqeKey_Diablo3_Install_enGB = "expand 32-byte kXP4G0000PHBPRP7W0000J9UNHY4800007SL9MMKV0000HYBQ"; // MMKVHY48RP7WXP4GHYBQ7SL9J9UNPHBP
+static const char * MpqeKey_Diablo3_Install_enSG = "expand 32-byte kTZ9M00003CPPVGGL0000JYETWHQ70000FDCL8MXL0000QZQS"; // 8MXLWHQ7VGGLTZ9MQZQSFDCLJYET3CPP
+static const char * MpqeKey_Diablo3_Install_enUS = "expand 32-byte kGUNG0000WZSZXFE20000UAKP5TM60000HKQ9EJ2R00005QDG"; // EJ2R5TM6XFE2GUNG5QDGHKQ9UAKPWZSZ
+static const char * MpqeKey_Diablo3_Install_esES = "expand 32-byte kK65U0000HQQTZ6LN0000CLP4BE420000WZVMPBGF0000GJQ3"; // PBGFBE42Z6LNK65UGJQ3WZVMCLP4HQQT
+static const char * MpqeKey_Diablo3_Install_esMX = "expand 32-byte kW5P200008VU2TSGC0000JPEYJJS90000C47AX7SE00008EBS"; // X7SEJJS9TSGCW5P28EBSC47AJPEY8VU2
+static const char * MpqeKey_Diablo3_Install_frFR = "expand 32-byte kRY3D00007YA2YE6X0000XS4PQA8V0000ZDE45KVB0000LGC5"; // 5KVBQA8VYE6XRY3DLGC5ZDE4XS4P7YA2
+static const char * MpqeKey_Diablo3_Install_itIT = "expand 32-byte kVVY40000B2546EVN00005B8KD2K50000DWYT478J0000XX8T"; // 478JD2K56EVNVVY4XX8TDWYT5B8KB254
+static const char * MpqeKey_Diablo3_Install_koKR = "expand 32-byte k6YWH0000474ARZTN0000NVWDVNFQ0000VDH98TS40000E9CH"; // 8TS4VNFQRZTN6YWHE9CHVDH9NVWD474A
+static const char * MpqeKey_Diablo3_Install_plPL = "expand 32-byte k4ZJJ0000BLJBF4LZ0000A6GAZ32D00003AZQLJ520000XVKK"; // LJ52Z32DF4LZ4ZJJXVKK3AZQA6GABLJB
+static const char * MpqeKey_Diablo3_Install_ptBR = "expand 32-byte k545Y0000XYAGCUE20000WHE7HY2E0000JPVYK6BD0000KNLB"; // K6BDHY2ECUE2545YKNLBJPVYWHE7XYAG
+static const char * MpqeKey_Diablo3_Install_ruRU = "expand 32-byte kXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; //
+static const char * MpqeKey_Diablo3_Install_zhTW = "expand 32-byte kMRUC0000AA8HV3ZZ0000UX2TQTN80000A8CG6VWC0000ZXV8"; // 6VWCQTN8V3ZZMRUCZXV8A8CGUX2TAA8H
+static const char * MpqeKey_Diablo3_Install_zhCN = "expand 32-byte kXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; //
+
+static const char * MpqKeyArray[] =
+{
+ MpqeKey_Starcraft2_Install_deDE,
+ MpqeKey_Starcraft2_Install_enGB,
+ MpqeKey_Starcraft2_Install_enSG,
+ MpqeKey_Starcraft2_Install_enUS,
+ MpqeKey_Starcraft2_Install_esES,
+ MpqeKey_Starcraft2_Install_esMX,
+ MpqeKey_Starcraft2_Install_frFR,
+ MpqeKey_Starcraft2_Install_itIT,
+ MpqeKey_Starcraft2_Install_koKR,
+ MpqeKey_Starcraft2_Install_plPL,
+ MpqeKey_Starcraft2_Install_ptBR,
+ MpqeKey_Starcraft2_Install_ruRU,
+ MpqeKey_Starcraft2_Install_zhTW,
+
+ MpqeKey_Diablo3_Install_deDE,
+ MpqeKey_Diablo3_Install_enGB,
+ MpqeKey_Diablo3_Install_enSG,
+ MpqeKey_Diablo3_Install_enUS,
+ MpqeKey_Diablo3_Install_esES,
+ MpqeKey_Diablo3_Install_esMX,
+ MpqeKey_Diablo3_Install_frFR,
+ MpqeKey_Diablo3_Install_itIT,
+ MpqeKey_Diablo3_Install_koKR,
+ MpqeKey_Diablo3_Install_plPL,
+ MpqeKey_Diablo3_Install_ptBR,
+// MpqeKey_Diablo3_Install_ruRU,
+ MpqeKey_Diablo3_Install_zhTW,
+// MpqeKey_Diablo3_Install_zhCN,
+
+ NULL
+};
+
+static DWORD Rol32(DWORD dwValue, DWORD dwRolCount)
+{
+ DWORD dwShiftRight = 32 - dwRolCount;
+
+ return (dwValue << dwRolCount) | (dwValue >> dwShiftRight);
+}
+
+static void DecryptFileChunk(
+ DWORD * MpqData,
+ LPBYTE pbKey,
+ ULONGLONG ByteOffset,
+ DWORD dwLength)
+{
+ ULONGLONG ChunkOffset;
+ DWORD KeyShuffled[0x10];
+ DWORD KeyMirror[0x10];
+ DWORD RoundCount = 0x14;
+
+ // Prepare the key
+ ChunkOffset = ByteOffset / MPQE_CHUNK_SIZE;
+ memcpy(KeyMirror, pbKey, MPQE_CHUNK_SIZE);
+ BSWAP_ARRAY32_UNSIGNED(KeyMirror, MPQE_CHUNK_SIZE);
+ KeyMirror[0x05] = (DWORD)(ChunkOffset >> 32);
+ KeyMirror[0x08] = (DWORD)(ChunkOffset);
+
+ while(dwLength >= MPQE_CHUNK_SIZE)
+ {
+ // Shuffle the key - part 1
+ KeyShuffled[0x0E] = KeyMirror[0x00];
+ KeyShuffled[0x0C] = KeyMirror[0x01];
+ KeyShuffled[0x05] = KeyMirror[0x02];
+ KeyShuffled[0x0F] = KeyMirror[0x03];
+ KeyShuffled[0x0A] = KeyMirror[0x04];
+ KeyShuffled[0x07] = KeyMirror[0x05];
+ KeyShuffled[0x0B] = KeyMirror[0x06];
+ KeyShuffled[0x09] = KeyMirror[0x07];
+ KeyShuffled[0x03] = KeyMirror[0x08];
+ KeyShuffled[0x06] = KeyMirror[0x09];
+ KeyShuffled[0x08] = KeyMirror[0x0A];
+ KeyShuffled[0x0D] = KeyMirror[0x0B];
+ KeyShuffled[0x02] = KeyMirror[0x0C];
+ KeyShuffled[0x04] = KeyMirror[0x0D];
+ KeyShuffled[0x01] = KeyMirror[0x0E];
+ KeyShuffled[0x00] = KeyMirror[0x0F];
+
+ // Shuffle the key - part 2
+ for(DWORD i = 0; i < RoundCount; i += 2)
+ {
+ KeyShuffled[0x0A] = KeyShuffled[0x0A] ^ Rol32((KeyShuffled[0x0E] + KeyShuffled[0x02]), 0x07);
+ KeyShuffled[0x03] = KeyShuffled[0x03] ^ Rol32((KeyShuffled[0x0A] + KeyShuffled[0x0E]), 0x09);
+ KeyShuffled[0x02] = KeyShuffled[0x02] ^ Rol32((KeyShuffled[0x03] + KeyShuffled[0x0A]), 0x0D);
+ KeyShuffled[0x0E] = KeyShuffled[0x0E] ^ Rol32((KeyShuffled[0x02] + KeyShuffled[0x03]), 0x12);
+
+ KeyShuffled[0x07] = KeyShuffled[0x07] ^ Rol32((KeyShuffled[0x0C] + KeyShuffled[0x04]), 0x07);
+ KeyShuffled[0x06] = KeyShuffled[0x06] ^ Rol32((KeyShuffled[0x07] + KeyShuffled[0x0C]), 0x09);
+ KeyShuffled[0x04] = KeyShuffled[0x04] ^ Rol32((KeyShuffled[0x06] + KeyShuffled[0x07]), 0x0D);
+ KeyShuffled[0x0C] = KeyShuffled[0x0C] ^ Rol32((KeyShuffled[0x04] + KeyShuffled[0x06]), 0x12);
+
+ KeyShuffled[0x0B] = KeyShuffled[0x0B] ^ Rol32((KeyShuffled[0x05] + KeyShuffled[0x01]), 0x07);
+ KeyShuffled[0x08] = KeyShuffled[0x08] ^ Rol32((KeyShuffled[0x0B] + KeyShuffled[0x05]), 0x09);
+ KeyShuffled[0x01] = KeyShuffled[0x01] ^ Rol32((KeyShuffled[0x08] + KeyShuffled[0x0B]), 0x0D);
+ KeyShuffled[0x05] = KeyShuffled[0x05] ^ Rol32((KeyShuffled[0x01] + KeyShuffled[0x08]), 0x12);
+
+ KeyShuffled[0x09] = KeyShuffled[0x09] ^ Rol32((KeyShuffled[0x0F] + KeyShuffled[0x00]), 0x07);
+ KeyShuffled[0x0D] = KeyShuffled[0x0D] ^ Rol32((KeyShuffled[0x09] + KeyShuffled[0x0F]), 0x09);
+ KeyShuffled[0x00] = KeyShuffled[0x00] ^ Rol32((KeyShuffled[0x0D] + KeyShuffled[0x09]), 0x0D);
+ KeyShuffled[0x0F] = KeyShuffled[0x0F] ^ Rol32((KeyShuffled[0x00] + KeyShuffled[0x0D]), 0x12);
+
+ KeyShuffled[0x04] = KeyShuffled[0x04] ^ Rol32((KeyShuffled[0x0E] + KeyShuffled[0x09]), 0x07);
+ KeyShuffled[0x08] = KeyShuffled[0x08] ^ Rol32((KeyShuffled[0x04] + KeyShuffled[0x0E]), 0x09);
+ KeyShuffled[0x09] = KeyShuffled[0x09] ^ Rol32((KeyShuffled[0x08] + KeyShuffled[0x04]), 0x0D);
+ KeyShuffled[0x0E] = KeyShuffled[0x0E] ^ Rol32((KeyShuffled[0x09] + KeyShuffled[0x08]), 0x12);
+
+ KeyShuffled[0x01] = KeyShuffled[0x01] ^ Rol32((KeyShuffled[0x0C] + KeyShuffled[0x0A]), 0x07);
+ KeyShuffled[0x0D] = KeyShuffled[0x0D] ^ Rol32((KeyShuffled[0x01] + KeyShuffled[0x0C]), 0x09);
+ KeyShuffled[0x0A] = KeyShuffled[0x0A] ^ Rol32((KeyShuffled[0x0D] + KeyShuffled[0x01]), 0x0D);
+ KeyShuffled[0x0C] = KeyShuffled[0x0C] ^ Rol32((KeyShuffled[0x0A] + KeyShuffled[0x0D]), 0x12);
+
+ KeyShuffled[0x00] = KeyShuffled[0x00] ^ Rol32((KeyShuffled[0x05] + KeyShuffled[0x07]), 0x07);
+ KeyShuffled[0x03] = KeyShuffled[0x03] ^ Rol32((KeyShuffled[0x00] + KeyShuffled[0x05]), 0x09);
+ KeyShuffled[0x07] = KeyShuffled[0x07] ^ Rol32((KeyShuffled[0x03] + KeyShuffled[0x00]), 0x0D);
+ KeyShuffled[0x05] = KeyShuffled[0x05] ^ Rol32((KeyShuffled[0x07] + KeyShuffled[0x03]), 0x12);
+
+ KeyShuffled[0x02] = KeyShuffled[0x02] ^ Rol32((KeyShuffled[0x0F] + KeyShuffled[0x0B]), 0x07);
+ KeyShuffled[0x06] = KeyShuffled[0x06] ^ Rol32((KeyShuffled[0x02] + KeyShuffled[0x0F]), 0x09);
+ KeyShuffled[0x0B] = KeyShuffled[0x0B] ^ Rol32((KeyShuffled[0x06] + KeyShuffled[0x02]), 0x0D);
+ KeyShuffled[0x0F] = KeyShuffled[0x0F] ^ Rol32((KeyShuffled[0x0B] + KeyShuffled[0x06]), 0x12);
+ }
+
+ // Decrypt one data chunk
+ BSWAP_ARRAY32_UNSIGNED(MpqData, MPQE_CHUNK_SIZE);
+ MpqData[0x00] = MpqData[0x00] ^ (KeyShuffled[0x0E] + KeyMirror[0x00]);
+ MpqData[0x01] = MpqData[0x01] ^ (KeyShuffled[0x04] + KeyMirror[0x0D]);
+ MpqData[0x02] = MpqData[0x02] ^ (KeyShuffled[0x08] + KeyMirror[0x0A]);
+ MpqData[0x03] = MpqData[0x03] ^ (KeyShuffled[0x09] + KeyMirror[0x07]);
+ MpqData[0x04] = MpqData[0x04] ^ (KeyShuffled[0x0A] + KeyMirror[0x04]);
+ MpqData[0x05] = MpqData[0x05] ^ (KeyShuffled[0x0C] + KeyMirror[0x01]);
+ MpqData[0x06] = MpqData[0x06] ^ (KeyShuffled[0x01] + KeyMirror[0x0E]);
+ MpqData[0x07] = MpqData[0x07] ^ (KeyShuffled[0x0D] + KeyMirror[0x0B]);
+ MpqData[0x08] = MpqData[0x08] ^ (KeyShuffled[0x03] + KeyMirror[0x08]);
+ MpqData[0x09] = MpqData[0x09] ^ (KeyShuffled[0x07] + KeyMirror[0x05]);
+ MpqData[0x0A] = MpqData[0x0A] ^ (KeyShuffled[0x05] + KeyMirror[0x02]);
+ MpqData[0x0B] = MpqData[0x0B] ^ (KeyShuffled[0x00] + KeyMirror[0x0F]);
+ MpqData[0x0C] = MpqData[0x0C] ^ (KeyShuffled[0x02] + KeyMirror[0x0C]);
+ MpqData[0x0D] = MpqData[0x0D] ^ (KeyShuffled[0x06] + KeyMirror[0x09]);
+ MpqData[0x0E] = MpqData[0x0E] ^ (KeyShuffled[0x0B] + KeyMirror[0x06]);
+ MpqData[0x0F] = MpqData[0x0F] ^ (KeyShuffled[0x0F] + KeyMirror[0x03]);
+ BSWAP_ARRAY32_UNSIGNED(MpqData, MPQE_CHUNK_SIZE);
+
+ // Update byte offset in the key
+ KeyMirror[0x08]++;
+ if(KeyMirror[0x08] == 0)
+ KeyMirror[0x05]++;
+
+ // Move pointers and decrease number of bytes to decrypt
+ MpqData += (MPQE_CHUNK_SIZE / sizeof(DWORD));
+ dwLength -= MPQE_CHUNK_SIZE;
+ }
+}
+
+static const char * DetectFileKey(LPBYTE pbEncryptedHeader)
+{
+ ULONGLONG ByteOffset = 0;
+ BYTE FileHeader[MPQE_CHUNK_SIZE];
+ BYTE Key[MPQE_CHUNK_SIZE];
+
+ // We just try all known keys one by one
+ for(int i = 0; MpqKeyArray[i] != NULL; i++)
+ {
+ // Copy the key there
+ memcpy(Key, MpqKeyArray[i], MPQE_CHUNK_SIZE);
+ BSWAP_ARRAY32_UNSIGNED(Key, MPQE_CHUNK_SIZE);
+
+ // Try to decrypt with the given key
+ memcpy(FileHeader, pbEncryptedHeader, MPQE_CHUNK_SIZE);
+ DecryptFileChunk((LPDWORD)FileHeader, Key, ByteOffset, MPQE_CHUNK_SIZE);
+
+ // We check the decrypted data
+ // All known encrypted MPQs have header at the begin of the file,
+ // so we check for MPQ signature there.
+ if(FileHeader[0] == 'M' && FileHeader[1] == 'P' && FileHeader[2] == 'Q')
+ return MpqKeyArray[i];
+ }
+
+ // Key not found, sorry
+ return NULL;
+}
+
+static bool EncryptedStream_Read(
+ TEncryptedStream * pStream, // Pointer to an open stream
+ ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position
+ void * pvBuffer, // Pointer to data to be read
+ DWORD dwBytesToRead) // Number of bytes to read from the file
+{
+ ULONGLONG StartOffset; // Offset of the first byte to be read from the file
+ ULONGLONG ByteOffset; // Offset that the caller wants
+ ULONGLONG EndOffset; // End offset that is to be read from the file
+ DWORD dwBytesToAllocate;
+ DWORD dwBytesToDecrypt;
+ DWORD dwOffsetInCache;
+ LPBYTE pbMpqData = NULL;
+ bool bResult = false;
+
+ // Get the byte offset
+ if(pByteOffset == NULL)
+ pStream->BaseGetPos(pStream, ByteOffset);
+ else
+ ByteOffset = *pByteOffset;
+
+ // Cut it down to MPQE chunk size
+ StartOffset = ByteOffset;
+ StartOffset = StartOffset & ~(MPQE_CHUNK_SIZE - 1);
+ EndOffset = ByteOffset + dwBytesToRead;
+
+ // Calculate number of bytes to decrypt
+ dwBytesToDecrypt = (DWORD)(EndOffset - StartOffset);
+ dwBytesToAllocate = (dwBytesToDecrypt + (MPQE_CHUNK_SIZE - 1)) & ~(MPQE_CHUNK_SIZE - 1);
+
+ // Allocate buffers for encrypted and decrypted data
+ pbMpqData = STORM_ALLOC(BYTE, dwBytesToAllocate);
+ if(pbMpqData)
+ {
+ // Get the offset of the desired data in the cache
+ dwOffsetInCache = (DWORD)(ByteOffset - StartOffset);
+
+ // Read the file from the stream as-is
+ if(pStream->BaseRead(pStream, &StartOffset, pbMpqData, dwBytesToDecrypt))
+ {
+ // Decrypt the data
+ DecryptFileChunk((LPDWORD)pbMpqData, pStream->Key, StartOffset, dwBytesToAllocate);
+
+ // Copy the decrypted data
+ memcpy(pvBuffer, pbMpqData + dwOffsetInCache, dwBytesToRead);
+ bResult = true;
+ }
+ else
+ {
+ assert(false);
+ }
+
+ // Free decryption buffer
+ STORM_FREE(pbMpqData);
+ }
+
+ // Free buffers and exit
+ return bResult;
+}
+
+static bool EncryptedStream_Open(TEncryptedStream * pStream)
+{
+ ULONGLONG ByteOffset = 0;
+ BYTE EncryptedHeader[MPQE_CHUNK_SIZE];
+ const char * szKey;
+
+ // Sanity check
+ assert(pStream->BaseRead != NULL);
+
+ // Load one MPQE chunk and try to detect the file key
+ if(pStream->BaseRead(pStream, &ByteOffset, EncryptedHeader, sizeof(EncryptedHeader)))
+ {
+ // Attempt to decrypt the MPQ header with all known keys
+ szKey = DetectFileKey(EncryptedHeader);
+ if(szKey != NULL)
+ {
+ // Copy the key for the file
+ memcpy(pStream->Key, szKey, MPQE_CHUNK_SIZE);
+ BSWAP_ARRAY32_UNSIGNED(pStream->Key, MPQE_CHUNK_SIZE);
+
+ // Assign functions
+ pStream->StreamRead = (STREAM_READ)EncryptedStream_Read;
+ pStream->StreamGetPos = pStream->BaseGetPos;
+ pStream->StreamGetSize = pStream->BaseGetSize;
+ pStream->StreamGetTime = pStream->BaseGetTime;
+ pStream->StreamGetBmp = (STREAM_GETBMP)Dummy_GetBitmap;
+ pStream->StreamClose = pStream->BaseClose;
+
+ // We need to reset the position back to the begin of the file
+ pStream->BaseRead(pStream, &ByteOffset, EncryptedHeader, 0);
+ return true;
+ }
+
+ // An unknown key
+ SetLastError(ERROR_UNKNOWN_FILE_KEY);
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+/**
+ * This function creates a new file for read-write access
+ *
+ * - If the current platform supports file sharing,
+ * the file must be created for read sharing (i.e. another application
+ * can open the file for read, but not for write)
+ * - If the file does not exist, the function must create new one
+ * - If the file exists, the function must rewrite it and set to zero size
+ * - The parameters of the function must be validate by the caller
+ * - The function must initialize all stream function pointers in TFileStream
+ * - If the function fails from any reason, it must close all handles
+ * and free all memory that has been allocated in the process of stream creation,
+ * including the TFileStream structure itself
+ *
+ * \a szFileName Name of the file to create
+ */
+
+TFileStream * FileStream_CreateFile(
+ const TCHAR * szFileName,
+ DWORD dwStreamFlags)
+{
+ TFileStream * pStream;
+
+ // We only support creation of linear, local file
+ if((dwStreamFlags & (STREAM_PROVIDER_MASK | BASE_PROVIDER_MASK)) != (STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE))
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return NULL;
+ }
+
+ // Allocate file stream structure for linear stream
+ pStream = STORM_ALLOC(TFileStream, 1);
+ if(pStream != NULL)
+ {
+ // Reset entire structure to zero
+ memset(pStream, 0, sizeof(TFileStream));
+ _tcscpy(pStream->szFileName, szFileName);
+
+ // Attempt to create the disk file
+ if(BaseFile_Create(pStream, szFileName, dwStreamFlags))
+ {
+ // Fill the stream provider functions
+ pStream->StreamRead = pStream->BaseRead;
+ pStream->StreamWrite = pStream->BaseWrite;
+ pStream->StreamGetPos = pStream->BaseGetPos;
+ pStream->StreamGetSize = pStream->BaseGetSize;
+ pStream->StreamSetSize = pStream->BaseSetSize;
+ pStream->StreamGetTime = pStream->BaseGetTime;
+ pStream->StreamGetBmp = (STREAM_GETBMP)Dummy_GetBitmap;;
+ pStream->StreamSwitch = (STREAM_SWITCH)LinearStream_Switch;
+ pStream->StreamClose = pStream->BaseClose;
+ return pStream;
+ }
+
+ // File create failed, delete the stream
+ STORM_FREE(pStream);
+ pStream = NULL;
+ }
+
+ // Return the stream
+ return pStream;
+}
+
+/**
+ * This function opens an existing file for read or read-write access
+ * - If the current platform supports file sharing,
+ * the file must be open for read sharing (i.e. another application
+ * can open the file for read, but not for write)
+ * - If the file does not exist, the function must return NULL
+ * - If the file exists but cannot be open, then function must return NULL
+ * - The parameters of the function must be validate by the caller
+ * - The function must check if the file is a PART file,
+ * and create TPartialStream object if so.
+ * - The function must initialize all stream function pointers in TFileStream
+ * - If the function fails from any reason, it must close all handles
+ * and free all memory that has been allocated in the process of stream creation,
+ * including the TFileStream structure itself
+ *
+ * \a szFileName Name of the file to open
+ * \a dwStreamFlags specifies the provider and base storage type
+ */
+
+TFileStream * FileStream_OpenFile(
+ const TCHAR * szFileName,
+ DWORD dwStreamFlags)
+{
+ TFileStream * pStream = NULL;
+ size_t StreamSize = 0;
+ bool bStreamResult = false;
+ bool bBaseResult = false;
+
+ // Allocate file stream for each stream provider
+ switch(dwStreamFlags & STREAM_PROVIDER_MASK)
+ {
+ case STREAM_PROVIDER_LINEAR: // Allocate structure for linear stream
+ StreamSize = sizeof(TLinearStream);
+ break;
+
+ case STREAM_PROVIDER_PARTIAL:
+ dwStreamFlags |= STREAM_FLAG_READ_ONLY;
+ StreamSize = sizeof(TPartialStream);
+ break;
+
+ case STREAM_PROVIDER_ENCRYPTED:
+ dwStreamFlags |= STREAM_FLAG_READ_ONLY;
+ StreamSize = sizeof(TEncryptedStream);
+ break;
+
+ default:
+ return NULL;
+ }
+
+ // Allocate the stream for each type
+ pStream = (TFileStream *)STORM_ALLOC(BYTE, StreamSize);
+ if(pStream == NULL)
+ return NULL;
+
+ // Fill the stream structure with zeros
+ memset(pStream, 0, StreamSize);
+ _tcscpy(pStream->szFileName, szFileName);
+
+ // Now initialize the respective base provider
+ switch(dwStreamFlags & BASE_PROVIDER_MASK)
+ {
+ case BASE_PROVIDER_FILE:
+ bBaseResult = BaseFile_Open(pStream, szFileName, dwStreamFlags);
+ break;
+
+ case BASE_PROVIDER_MAP:
+ dwStreamFlags |= STREAM_FLAG_READ_ONLY;
+ bBaseResult = BaseMap_Open(pStream, szFileName, dwStreamFlags);
+ break;
+
+ case BASE_PROVIDER_HTTP:
+ dwStreamFlags |= STREAM_FLAG_READ_ONLY;
+ bBaseResult = BaseHttp_Open(pStream, szFileName, dwStreamFlags);
+ break;
+ }
+
+ // If we failed to open the base storage, fail the operation
+ if(bBaseResult == false)
+ {
+ STORM_FREE(pStream);
+ return NULL;
+ }
+
+ // Now initialize the stream provider
+ switch(dwStreamFlags & STREAM_PROVIDER_MASK)
+ {
+ case STREAM_PROVIDER_LINEAR:
+ bStreamResult = LinearStream_Open((TLinearStream *)pStream);
+ break;
+
+ case STREAM_PROVIDER_PARTIAL:
+ bStreamResult = PartialStream_Open((TPartialStream *)pStream);
+ break;
+
+ case STREAM_PROVIDER_ENCRYPTED:
+ bStreamResult = EncryptedStream_Open((TEncryptedStream *)pStream);
+ break;
+ }
+
+ // If the operation failed, free the stream and set it to NULL
+ if(bStreamResult == false)
+ {
+ // Only close the base stream
+ pStream->BaseClose(pStream);
+ STORM_FREE(pStream);
+ pStream = NULL;
+ }
+
+ return pStream;
+}
+
+/**
+ * Reads data from the stream
+ *
+ * - Returns true if the read operation succeeded and all bytes have been read
+ * - Returns false if either read failed or not all bytes have been read
+ * - If the pByteOffset is NULL, the function must read the data from the current file position
+ * - The function can be called with dwBytesToRead = 0. In that case, pvBuffer is ignored
+ * and the function just adjusts file pointer.
+ *
+ * \a pStream Pointer to an open stream
+ * \a pByteOffset Pointer to file byte offset. If NULL, it reads from the current position
+ * \a pvBuffer Pointer to data to be read
+ * \a dwBytesToRead Number of bytes to read from the file
+ *
+ * \returns
+ * - If the function reads the required amount of bytes, it returns true.
+ * - If the function reads less than required bytes, it returns false and GetLastError() returns ERROR_HANDLE_EOF
+ * - If the function fails, it reads false and GetLastError() returns an error code different from ERROR_HANDLE_EOF
+ */
+bool FileStream_Read(TFileStream * pStream, ULONGLONG * pByteOffset, void * pvBuffer, DWORD dwBytesToRead)
+{
+ assert(pStream->StreamRead != NULL);
+ return pStream->StreamRead(pStream, pByteOffset, pvBuffer, dwBytesToRead);
+}
+
+/**
+ * This function writes data to the stream
+ *
+ * - Returns true if the write operation succeeded and all bytes have been written
+ * - Returns false if either write failed or not all bytes have been written
+ * - If the pByteOffset is NULL, the function must write the data to the current file position
+ *
+ * \a pStream Pointer to an open stream
+ * \a pByteOffset Pointer to file byte offset. If NULL, it reads from the current position
+ * \a pvBuffer Pointer to data to be written
+ * \a dwBytesToWrite Number of bytes to write to the file
+ */
+bool FileStream_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite)
+{
+ if(pStream->dwFlags & STREAM_FLAG_READ_ONLY)
+ return false;
+
+ assert(pStream->StreamWrite != NULL);
+ return pStream->StreamWrite(pStream, pByteOffset, pvBuffer, dwBytesToWrite);
+}
+
+/**
+ * This function returns the current file position
+ * \a pStream
+ * \a ByteOffset
+ */
+bool FileStream_GetPos(TFileStream * pStream, ULONGLONG & ByteOffset)
+{
+ assert(pStream->StreamGetPos != NULL);
+ return pStream->StreamGetPos(pStream, ByteOffset);
+}
+
+/**
+ * Returns the size of a file
+ *
+ * \a pStream Pointer to an open stream
+ * \a FileSize Pointer where to store the file size
+ */
+bool FileStream_GetSize(TFileStream * pStream, ULONGLONG & FileSize)
+{
+ assert(pStream->StreamGetSize != NULL);
+ return pStream->StreamGetSize(pStream, FileSize);
+}
+
+/**
+ * Sets the size of a file
+ *
+ * \a pStream Pointer to an open stream
+ * \a NewFileSize File size to set
+ */
+bool FileStream_SetSize(TFileStream * pStream, ULONGLONG NewFileSize)
+{
+ if(pStream->dwFlags & STREAM_FLAG_READ_ONLY)
+ return false;
+
+ assert(pStream->StreamSetSize != NULL);
+ return pStream->StreamSetSize(pStream, NewFileSize);
+}
+
+/**
+ * Returns the last write time of a file
+ *
+ * \a pStream Pointer to an open stream
+ * \a pFileType Pointer where to store the file last write time
+ */
+bool FileStream_GetTime(TFileStream * pStream, ULONGLONG * pFileTime)
+{
+ assert(pStream->StreamGetTime != NULL);
+ return pStream->StreamGetTime(pStream, pFileTime);
+}
+
+/**
+ * Switches a stream with another. Used for final phase of archive compacting.
+ * Performs these steps:
+ *
+ * 1) Closes the handle to the existing MPQ
+ * 2) Renames the temporary MPQ to the original MPQ, overwrites existing one
+ * 3) Opens the MPQ stores the handle and stream position to the new stream structure
+ *
+ * \a pStream Pointer to an open stream
+ * \a pTempStream Temporary ("working") stream (created during archive compacting)
+ */
+bool FileStream_Switch(TFileStream * pStream, TFileStream * pNewStream)
+{
+ if(pStream->dwFlags & STREAM_FLAG_READ_ONLY)
+ return false;
+
+ assert(pStream->StreamSwitch != NULL);
+ return pStream->StreamSwitch(pStream, pNewStream);
+}
+
+/**
+ * Returns the file name of the stream
+ *
+ * \a pStream Pointer to an open stream
+ */
+TCHAR * FileStream_GetFileName(TFileStream * pStream)
+{
+ assert(pStream != NULL);
+ return pStream->szFileName;
+}
+
+/**
+ * Returns true if the stream is read-only
+ *
+ * \a pStream Pointer to an open stream
+ */
+bool FileStream_IsReadOnly(TFileStream * pStream)
+{
+ return (pStream->dwFlags & STREAM_FLAG_READ_ONLY) ? true : false;
+}
+
+/**
+ * This function enabled a linear stream to include data bitmap.
+ * Used by MPQs v 4.0 from WoW. Each file block is represented by
+ * a bit in the bitmap. 1 means the block is present, 0 means it's not.
+ *
+ * \a pStream Pointer to an open stream
+ * \a pBitmap Pointer to file bitmap
+ */
+
+bool FileStream_SetBitmap(TFileStream * pStream, TFileBitmap * pBitmap)
+{
+ TLinearStream * pLinearStream;
+
+ // It must be a linear stream.
+ if((pStream->dwFlags & STREAM_PROVIDER_MASK) != STREAM_PROVIDER_LINEAR)
+ return false;
+ pLinearStream = (TLinearStream *)pStream;
+
+ // Two bitmaps are not allowed
+ if(pLinearStream->pBitmap != NULL)
+ return false;
+
+ // We need to change some entry points
+ pLinearStream->StreamRead = (STREAM_READ)LinearStream_Read;
+ pLinearStream->StreamGetBmp = (STREAM_GETBMP)LinearStream_GetBitmap;
+
+ // Using data bitmap renders the stream to be read only.
+ pLinearStream->dwFlags |= STREAM_FLAG_READ_ONLY;
+ pLinearStream->pBitmap = pBitmap;
+ return true;
+}
+
+/**
+ * This function retrieves the file bitmap. A file bitmap is an array
+ * of bits, each bit representing one file block. A value of 1 means
+ * that the block is present in the file, a value of 0 means that the
+ * block is not present.
+ *
+ * \a pStream Pointer to an open stream
+ * \a pBitmap Pointer to buffer where to store the file bitmap
+ * \a Length Size of buffer pointed by pBitmap, in bytes
+ * \a LengthNeeded If non-NULL, the function supplies the necessary byte size of the buffer
+ */
+bool FileStream_GetBitmap(TFileStream * pStream, TFileBitmap * pBitmap, DWORD Length, LPDWORD LengthNeeded)
+{
+ assert(pStream->StreamGetBmp != NULL);
+ return pStream->StreamGetBmp(pStream, pBitmap, Length, LengthNeeded);
+}
+
+/**
+ * This function closes an archive file and frees any data buffers
+ * that have been allocated for stream management. The function must also
+ * support partially allocated structure, i.e. one or more buffers
+ * can be NULL, if there was an allocation failure during the process
+ *
+ * \a pStream Pointer to an open stream
+ */
+void FileStream_Close(TFileStream * pStream)
+{
+ // Check if the stream structure is allocated at all
+ if(pStream != NULL)
+ {
+ // Close the stream provider.
+ // This will also close the base stream
+ assert(pStream->StreamClose != NULL);
+ pStream->StreamClose(pStream);
+
+ // Free the stream itself
+ STORM_FREE(pStream);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// main - for testing purposes
+
+#ifdef __STORMLIB_TEST__
+int FileStream_Test(const TCHAR * szFileName, DWORD dwStreamFlags)
+{
+ TFileStream * pStream;
+ TMPQHeader MpqHeader;
+ ULONGLONG FilePos;
+ TMPQBlock * pBlock;
+ TMPQHash * pHash;
+
+ InitializeMpqCryptography();
+
+ pStream = FileStream_OpenFile(szFileName, dwStreamFlags);
+ if(pStream == NULL)
+ return GetLastError();
+
+ // Read the MPQ header
+ FileStream_Read(pStream, NULL, &MpqHeader, MPQ_HEADER_SIZE_V2);
+ if(MpqHeader.dwID != ID_MPQ)
+ return ERROR_FILE_CORRUPT;
+
+ // Read the hash table
+ pHash = STORM_ALLOC(TMPQHash, MpqHeader.dwHashTableSize);
+ if(pHash != NULL)
+ {
+ FilePos = MpqHeader.dwHashTablePos;
+ FileStream_Read(pStream, &FilePos, pHash, MpqHeader.dwHashTableSize * sizeof(TMPQHash));
+ DecryptMpqBlock(pHash, MpqHeader.dwHashTableSize * sizeof(TMPQHash), MPQ_KEY_HASH_TABLE);
+ STORM_FREE(pHash);
+ }
+
+ // Read the block table
+ pBlock = STORM_ALLOC(TMPQBlock, MpqHeader.dwBlockTableSize);
+ if(pBlock != NULL)
+ {
+ FilePos = MpqHeader.dwBlockTablePos;
+ FileStream_Read(pStream, &FilePos, pBlock, MpqHeader.dwBlockTableSize * sizeof(TMPQBlock));
+ DecryptMpqBlock(pBlock, MpqHeader.dwBlockTableSize * sizeof(TMPQBlock), MPQ_KEY_BLOCK_TABLE);
+ STORM_FREE(pBlock);
+ }
+
+ FileStream_Close(pStream);
+ return ERROR_SUCCESS;
+}
+#endif
+
+/*
+int FileStream_Test()
+{
+ TFileStream * pStream;
+
+ InitializeMpqCryptography();
+
+ //
+ // Test 1: Write to a stream
+ //
+
+ pStream = FileStream_CreateFile("E:\\Stream.bin", 0);
+ if(pStream != NULL)
+ {
+ char szString1[100] = "This is a single line\n\r";
+ DWORD dwLength = strlen(szString1);
+
+ for(int i = 0; i < 10; i++)
+ {
+ if(!FileStream_Write(pStream, NULL, szString1, dwLength))
+ {
+ printf("Failed to write to the stream\n");
+ return ERROR_CAN_NOT_COMPLETE;
+ }
+ }
+ FileStream_Close(pStream);
+ }
+
+ //
+ // Test2: Read from the stream
+ //
+
+ pStream = FileStream_OpenFile("E:\\Stream.bin", STREAM_FLAG_READ_ONLY | STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE);
+ if(pStream != NULL)
+ {
+ char szString1[100] = "This is a single line\n\r";
+ char szString2[100];
+ DWORD dwLength = strlen(szString1);
+
+ // This call must end with an error
+ if(FileStream_Write(pStream, NULL, "aaa", 3))
+ {
+ printf("Write succeeded while it should fail\n");
+ return -1;
+ }
+
+ for(int i = 0; i < 10; i++)
+ {
+ if(!FileStream_Read(pStream, NULL, szString2, dwLength))
+ {
+ printf("Failed to read from the stream\n");
+ return -1;
+ }
+
+ szString2[dwLength] = 0;
+ if(strcmp(szString1, szString2))
+ {
+ printf("Data read from file are different from data written\n");
+ return -1;
+ }
+ }
+ FileStream_Close(pStream);
+ }
+
+ //
+ // Test3: Open the temp stream, write some data and switch it to the original stream
+ //
+
+ pStream = FileStream_OpenFile("E:\\Stream.bin", STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE);
+ if(pStream != NULL)
+ {
+ TFileStream * pTempStream;
+ ULONGLONG FileSize;
+
+ pTempStream = FileStream_CreateFile("E:\\TempStream.bin", 0);
+ if(pTempStream == NULL)
+ {
+ printf("Failed to create temp stream\n");
+ return -1;
+ }
+
+ // Copy the original stream to the temp
+ if(!FileStream_GetSize(pStream, FileSize))
+ {
+ printf("Failed to get the file size\n");
+ return -1;
+ }
+
+ while(FileSize != 0)
+ {
+ DWORD dwBytesToRead = (DWORD)FileSize;
+ char Buffer[0x80];
+
+ if(dwBytesToRead > sizeof(Buffer))
+ dwBytesToRead = sizeof(Buffer);
+
+ if(!FileStream_Read(pStream, NULL, Buffer, dwBytesToRead))
+ {
+ printf("CopyStream: Read source file failed\n");
+ return -1;
+ }
+
+ if(!FileStream_Write(pTempStream, NULL, Buffer, dwBytesToRead))
+ {
+ printf("CopyStream: Write target file failed\n");
+ return -1;
+ }
+
+ FileSize -= dwBytesToRead;
+ }
+
+ // Switch the streams
+ // Note that the pTempStream is closed by the operation
+ FileStream_Switch(pStream, pTempStream);
+ FileStream_Close(pStream);
+ }
+
+ //
+ // Test4: Read from the stream again
+ //
+
+ pStream = FileStream_OpenFile("E:\\Stream.bin", STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE);
+ if(pStream != NULL)
+ {
+ char szString1[100] = "This is a single line\n\r";
+ char szString2[100];
+ DWORD dwLength = strlen(szString1);
+
+ for(int i = 0; i < 10; i++)
+ {
+ if(!FileStream_Read(pStream, NULL, szString2, dwLength))
+ {
+ printf("Failed to read from the stream\n");
+ return -1;
+ }
+
+ szString2[dwLength] = 0;
+ if(strcmp(szString1, szString2))
+ {
+ printf("Data read from file are different from data written\n");
+ return -1;
+ }
+ }
+ FileStream_Close(pStream);
+ }
+
+ return 0;
+}
+*/
+
diff --git a/dep/StormLib/src/FileStream.h b/dep/StormLib/src/FileStream.h
new file mode 100644
index 00000000000..31fe757514d
--- /dev/null
+++ b/dep/StormLib/src/FileStream.h
@@ -0,0 +1,189 @@
+/*****************************************************************************/
+/* FileStream.h Copyright (c) Ladislav Zezula 2012 */
+/*---------------------------------------------------------------------------*/
+/* Description: Definitions for FileStream object */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 14.04.12 1.00 Lad The first version of FileStream.h */
+/*****************************************************************************/
+
+#ifndef __FILESTREAM_H__
+#define __FILESTREAM_H__
+
+//-----------------------------------------------------------------------------
+// Function prototypes
+
+typedef bool (*STREAM_READ)(
+ struct TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position
+ void * pvBuffer, // Pointer to data to be read
+ DWORD dwBytesToRead // Number of bytes to read from the file
+ );
+
+typedef bool (*STREAM_WRITE)(
+ struct TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it writes to the current position
+ const void * pvBuffer, // Pointer to data to be written
+ DWORD dwBytesToWrite // Number of bytes to read from the file
+ );
+
+typedef bool (*STREAM_GETPOS)(
+ struct TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG & ByteOffset // Pointer to store current file position
+ );
+
+typedef bool (*STREAM_GETSIZE)(
+ struct TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG & FileSize // Receives the file size, in bytes
+ );
+
+typedef bool (*STREAM_SETSIZE)(
+ struct TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG FileSize // New size for the file, in bytes
+ );
+
+typedef bool (*STREAM_GETTIME)(
+ struct TFileStream * pStream,
+ ULONGLONG * pFT
+ );
+
+typedef bool (*STREAM_SWITCH)(
+ struct TFileStream * pStream,
+ struct TFileStream * pNewStream
+ );
+
+typedef bool (*STREAM_GETBMP)(
+ TFileStream * pStream,
+ TFileBitmap * pBitmap,
+ DWORD Length,
+ LPDWORD LengthNeeded
+ );
+
+typedef void (*STREAM_CLOSE)(
+ struct TFileStream * pStream
+ );
+
+//-----------------------------------------------------------------------------
+// Local structures - part file structure
+
+typedef struct _PART_FILE_HEADER
+{
+ DWORD PartialVersion; // Always set to 2
+ char GameBuildNumber[0x20]; // Minimum build number of the game that can use this MPQ
+ DWORD Flags; // Flags (details unknown)
+ DWORD FileSizeLo; // Low 32 bits of the contained file size
+ DWORD FileSizeHi; // High 32 bits of the contained file size
+ DWORD BlockSize; // Size of one file block, in bytes
+
+} PART_FILE_HEADER, *PPART_FILE_HEADER;
+
+// Structure describing the block-to-file map entry
+typedef struct _PART_FILE_MAP_ENTRY
+{
+ DWORD Flags; // 3 = the block is present in the file
+ DWORD BlockOffsLo; // Low 32 bits of the block position in the file
+ DWORD BlockOffsHi; // High 32 bits of the block position in the file
+ DWORD LargeValueLo; // 64-bit value, meaning is unknown
+ DWORD LargeValueHi;
+
+} PART_FILE_MAP_ENTRY, *PPART_FILE_MAP_ENTRY;
+
+//-----------------------------------------------------------------------------
+// Local structures
+
+union TBaseData
+{
+ struct
+ {
+ ULONGLONG FileSize; // Size of the file
+ ULONGLONG FilePos; // Current file position
+ ULONGLONG FileTime; // Date/time of last modification of the file
+ HANDLE hFile; // File handle
+ } File;
+
+ struct
+ {
+ ULONGLONG FileSize; // Mapped file size
+ ULONGLONG FilePos; // Current stream position
+ ULONGLONG FileTime; // Date/time of last modification of the file
+ LPBYTE pbFile; // Pointer to mapped view
+ } Map;
+
+ struct
+ {
+ ULONGLONG FileSize; // Size of the internet file
+ ULONGLONG FilePos; // Current position in the file
+ ULONGLONG FileTime; // Date/time of last modification of the file
+ HANDLE hInternet; // Internet handle
+ HANDLE hConnect; // Connection to the internet server
+ } Http;
+};
+
+//-----------------------------------------------------------------------------
+// Structure for linear stream
+
+struct TFileStream
+{
+ // Stream provider functions
+ STREAM_READ StreamRead; // Pointer to stream read function for this archive. Do not use directly.
+ STREAM_WRITE StreamWrite; // Pointer to stream write function for this archive. Do not use directly.
+ STREAM_GETPOS StreamGetPos; // Pointer to function that returns current file position
+ STREAM_GETSIZE StreamGetSize; // Pointer to function returning file size
+ STREAM_SETSIZE StreamSetSize; // Pointer to function changing file size
+ STREAM_GETTIME StreamGetTime; // Pointer to function retrieving the file time
+ STREAM_GETBMP StreamGetBmp; // Pointer to function that retrieves the file bitmap
+ STREAM_SWITCH StreamSwitch; // Pointer to function changing the stream to another file
+ STREAM_CLOSE StreamClose; // Pointer to function closing the stream
+
+ // Stream provider data members
+ TCHAR szFileName[MAX_PATH]; // File name
+ DWORD dwFlags; // Stream flags
+
+ // Base provider functions
+ STREAM_READ BaseRead;
+ STREAM_WRITE BaseWrite;
+ STREAM_GETPOS BaseGetPos; // Pointer to function that returns current file position
+ STREAM_GETSIZE BaseGetSize; // Pointer to function returning file size
+ STREAM_SETSIZE BaseSetSize; // Pointer to function changing file size
+ STREAM_GETTIME BaseGetTime; // Pointer to function retrieving the file time
+ STREAM_CLOSE BaseClose; // Pointer to function closing the stream
+
+ // Base provider data members
+ TBaseData Base; // Base provider data
+
+ // Followed by stream provider data, with variable length
+};
+
+//-----------------------------------------------------------------------------
+// Structure for linear stream
+
+struct TLinearStream : public TFileStream
+{
+ TFileBitmap * pBitmap; // Pointer to the stream bitmap
+};
+
+//-----------------------------------------------------------------------------
+// Structure for partial stream
+
+struct TPartialStream : public TFileStream
+{
+ ULONGLONG VirtualSize; // Virtual size of the file
+ ULONGLONG VirtualPos; // Virtual position in the file
+ DWORD BlockCount; // Number of file blocks. Used by partial file stream
+ DWORD BlockSize; // Size of one block. Used by partial file stream
+
+ PPART_FILE_MAP_ENTRY PartMap; // File map, variable length
+};
+
+//-----------------------------------------------------------------------------
+// Structure for encrypted stream
+
+#define MPQE_CHUNK_SIZE 0x40 // Size of one chunk to be decrypted
+
+struct TEncryptedStream : public TFileStream
+{
+ BYTE Key[MPQE_CHUNK_SIZE]; // File key
+};
+
+#endif // __FILESTREAM_H__
diff --git a/dep/StormLib/src/SBaseCommon.cpp b/dep/StormLib/src/SBaseCommon.cpp
new file mode 100644
index 00000000000..65818784521
--- /dev/null
+++ b/dep/StormLib/src/SBaseCommon.cpp
@@ -0,0 +1,1700 @@
+/*****************************************************************************/
+/* SBaseCommon.cpp Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Common functions for StormLib, used by all SFile*** modules */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 24.03.03 1.00 Lad The first version of SFileCommon.cpp */
+/* 19.11.03 1.01 Dan Big endian handling */
+/* 12.06.04 1.01 Lad Renamed to SCommon.cpp */
+/* 06.09.10 1.01 Lad Renamed to SBaseCommon.cpp */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+char StormLibCopyright[] = "StormLib v " STORMLIB_VERSION_STRING " Copyright Ladislav Zezula 1998-2012";
+
+//-----------------------------------------------------------------------------
+// The buffer for decryption engine.
+
+LCID lcFileLocale = LANG_NEUTRAL; // File locale
+USHORT wPlatform = 0; // File platform
+
+//-----------------------------------------------------------------------------
+// Storm buffer functions
+
+#define STORM_BUFFER_SIZE 0x500
+
+static DWORD StormBuffer[STORM_BUFFER_SIZE]; // Buffer for the decryption engine
+static bool bMpqCryptographyInitialized = false;
+
+DWORD HashString(const char * szFileName, DWORD dwHashType)
+{
+ LPBYTE pbKey = (BYTE *)szFileName;
+ DWORD dwSeed1 = 0x7FED7FED;
+ DWORD dwSeed2 = 0xEEEEEEEE;
+ DWORD ch;
+
+ while(*pbKey != 0)
+ {
+ ch = toupper(*pbKey++);
+
+ dwSeed1 = StormBuffer[dwHashType + ch] ^ (dwSeed1 + dwSeed2);
+ dwSeed2 = ch + dwSeed1 + dwSeed2 + (dwSeed2 << 5) + 3;
+ }
+
+ return dwSeed1;
+}
+
+void InitializeMpqCryptography()
+{
+ DWORD dwSeed = 0x00100001;
+ DWORD index1 = 0;
+ DWORD index2 = 0;
+ int i;
+
+ // Initialize the decryption buffer.
+ // Do nothing if already done.
+ if(bMpqCryptographyInitialized == false)
+ {
+ for(index1 = 0; index1 < 0x100; index1++)
+ {
+ for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100)
+ {
+ DWORD temp1, temp2;
+
+ dwSeed = (dwSeed * 125 + 3) % 0x2AAAAB;
+ temp1 = (dwSeed & 0xFFFF) << 0x10;
+
+ dwSeed = (dwSeed * 125 + 3) % 0x2AAAAB;
+ temp2 = (dwSeed & 0xFFFF);
+
+ StormBuffer[index2] = (temp1 | temp2);
+ }
+ }
+
+ // Also register both MD5 and SHA1 hash algorithms
+ register_hash(&md5_desc);
+ register_hash(&sha1_desc);
+
+ // Use LibTomMath as support math library for LibTomCrypt
+ ltc_mp = ltm_desc;
+
+ // Don't do that again
+ bMpqCryptographyInitialized = true;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Calculates the hash table size for a given amount of files
+
+DWORD GetHashTableSizeForFileCount(DWORD dwFileCount)
+{
+ DWORD dwPowerOfTwo;
+
+ // Round the hash table size up to the nearest power of two
+ for(dwPowerOfTwo = HASH_TABLE_SIZE_MIN; dwPowerOfTwo < HASH_TABLE_SIZE_MAX; dwPowerOfTwo <<= 1)
+ {
+ if(dwPowerOfTwo >= dwFileCount)
+ {
+ return dwPowerOfTwo;
+ }
+ }
+
+ // Don't allow the hash table size go over allowed maximum
+ return HASH_TABLE_SIZE_MAX;
+}
+
+//-----------------------------------------------------------------------------
+// Calculates a Jenkin's Encrypting and decrypting MPQ file data
+
+ULONGLONG HashStringJenkins(const char * szFileName)
+{
+ char * szTemp;
+ char szLocFileName[0x108];
+ char chOneChar;
+ size_t nLength = 0;
+ unsigned int primary_hash = 1;
+ unsigned int secondary_hash = 2;
+
+ // This is required to produce defined results
+ assert(szFileName != NULL);
+
+ // Normalize the file name - convert to uppercase, and convert "/" to "\\".
+ if(szFileName != NULL)
+ {
+ szTemp = szLocFileName;
+ while(*szFileName != 0)
+ {
+ chOneChar = (char)tolower(*szFileName++);
+ if(chOneChar == '/')
+ chOneChar = '\\';
+
+ *szTemp++ = chOneChar;
+ }
+
+ nLength = szTemp - szLocFileName;
+ *szTemp = 0;
+ }
+
+ // Thanks Quantam for finding out what the algorithm is.
+ // I am really getting old for reversing large chunks of assembly
+ // that does hashing :-)
+ hashlittle2(szLocFileName, nLength, &secondary_hash, &primary_hash);
+
+ // Combine those 2 together
+ return (ULONGLONG)primary_hash * (ULONGLONG)0x100000000ULL + (ULONGLONG)secondary_hash;
+}
+
+//-----------------------------------------------------------------------------
+// This function converts the MPQ header so it always looks like version 4
+
+int ConvertMpqHeaderToFormat4(
+ TMPQArchive * ha,
+ ULONGLONG FileSize,
+ DWORD dwFlags)
+{
+ ULONGLONG ByteOffset;
+ TMPQHeader * pHeader = ha->pHeader;
+ DWORD dwExpectedArchiveSize;
+ USHORT wFormatVersion = pHeader->wFormatVersion;
+ int nError = ERROR_SUCCESS;
+
+ // If version 1.0 is forced, then the format version is forced to be 1.0
+ // Reason: Storm.dll in Warcraft III ignores format version value
+ if(dwFlags & MPQ_OPEN_FORCE_MPQ_V1)
+ wFormatVersion = MPQ_FORMAT_VERSION_1;
+
+ // Format-specific fixes
+ switch(wFormatVersion)
+ {
+ case MPQ_FORMAT_VERSION_1:
+
+ // Check for malformed MPQ header version 1.0
+ if(pHeader->dwHeaderSize != MPQ_HEADER_SIZE_V1)
+ {
+ pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1;
+ ha->dwFlags |= MPQ_FLAG_PROTECTED;
+ }
+
+ //
+ // The value of "dwArchiveSize" member in the MPQ header
+ // is ignored by Storm.dll and can contain garbage value
+ // ("w3xmaster" protector).
+ //
+
+ dwExpectedArchiveSize = (DWORD)(FileSize - ha->MpqPos);
+ if(pHeader->dwArchiveSize != dwExpectedArchiveSize)
+ {
+ // Note: dwExpectedArchiveSize might be incorrect at this point.
+ // MPQs version 1.0 can have strong digital signature appended at the end,
+ // or they might just have arbitrary data there.
+ // In either case, we recalculate the archive size later when
+ // block table is loaded and positions of all files is known.
+ pHeader->dwArchiveSize = dwExpectedArchiveSize;
+ ha->dwFlags |= MPQ_FLAG_NEED_FIX_SIZE;
+ }
+
+ // Zero the fields in 2.0 part of the MPQ header
+ pHeader->HiBlockTablePos64 = 0;
+ pHeader->wHashTablePosHi = 0;
+ pHeader->wBlockTablePosHi = 0;
+ // No break here !!!
+
+ case MPQ_FORMAT_VERSION_2:
+ case MPQ_FORMAT_VERSION_3:
+
+ // In MPQ format 3.0, the entire header is optional
+ // and the size of the header can actually be identical
+ // to size of header 2.0
+ if(pHeader->dwHeaderSize < MPQ_HEADER_SIZE_V3)
+ {
+ ULONGLONG ArchiveSize64 = pHeader->dwArchiveSize;
+
+ // In format 2.0, the archive size is obsolete and is calculated
+ // as the highest offset of hash table, block table or hi-block table.
+ // However, we can still rely on it, if the size of the archive is under 4 GB
+ if((FileSize - ha->MpqPos) >> 32)
+ {
+ ByteOffset = MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos) + (pHeader->dwHashTableSize * sizeof(TMPQHash));
+ if(ByteOffset > ArchiveSize64)
+ ArchiveSize64 = ByteOffset;
+
+ ByteOffset = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos) + (pHeader->dwBlockTableSize * sizeof(TMPQBlock));
+ if(ByteOffset > ArchiveSize64)
+ ArchiveSize64 = ByteOffset;
+
+ // Only if we actually have a hi-block table
+ if(pHeader->HiBlockTablePos64)
+ {
+ ByteOffset = pHeader->HiBlockTablePos64 + (pHeader->dwBlockTableSize * sizeof(USHORT));
+ if(ByteOffset > ArchiveSize64)
+ ArchiveSize64 = ByteOffset;
+ }
+
+ // We need to recalculate archive size later,
+ // when block table is loaded and the position of files is known
+ ha->dwFlags |= MPQ_FLAG_NEED_FIX_SIZE;
+ }
+
+ // Initialize the rest of the 3.0 header
+ pHeader->ArchiveSize64 = ArchiveSize64;
+ pHeader->HetTablePos64 = 0;
+ pHeader->BetTablePos64 = 0;
+ }
+
+ //
+ // Calculate compressed size of each table. We assume the following order:
+ // 1) HET table
+ // 2) BET table
+ // 3) Classic hash table
+ // 4) Classic block table
+ // 5) Hi-block table
+ //
+
+ // Set all sizes to zero
+ pHeader->HetTableSize64 = 0;
+ pHeader->BetTableSize64 = 0;
+
+ // Either both HET and BET table exist or none of them does.
+ if(pHeader->HetTablePos64)
+ {
+ // Compressed size of the HET and BET tables
+ pHeader->HetTableSize64 = pHeader->BetTablePos64 - pHeader->HetTablePos64;
+ pHeader->BetTableSize64 = MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos) - pHeader->HetTablePos64;
+ }
+
+ // Compressed size of hash and block table
+ if(wFormatVersion >= MPQ_FORMAT_VERSION_2)
+ {
+ // Compressed size of the hash table
+ pHeader->HashTableSize64 = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos) - MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos);
+
+ // Block and hi-block table
+ if(pHeader->HiBlockTablePos64)
+ {
+ pHeader->BlockTableSize64 = pHeader->HiBlockTablePos64 - MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
+ pHeader->HiBlockTableSize64 = pHeader->ArchiveSize64 - pHeader->HiBlockTablePos64;
+ }
+ else
+ {
+ pHeader->BlockTableSize64 = pHeader->ArchiveSize64 - MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
+ pHeader->HiBlockTableSize64 = 0;
+ }
+ }
+ else
+ {
+ // No known MPQ in format 1.0 has any of the tables compressed
+ pHeader->HashTableSize64 = pHeader->dwHashTableSize * sizeof(TMPQHash);
+ pHeader->BlockTableSize64 = pHeader->dwBlockTableSize * sizeof(TMPQBlock);
+ pHeader->HiBlockTableSize64 = 0;
+ }
+
+ // Set the data chunk size for MD5 to zero
+ pHeader->dwRawChunkSize = 0;
+
+ // Fill the MD5's
+ memset(pHeader->MD5_BlockTable, 0, MD5_DIGEST_SIZE);
+ memset(pHeader->MD5_HashTable, 0, MD5_DIGEST_SIZE);
+ memset(pHeader->MD5_HiBlockTable, 0, MD5_DIGEST_SIZE);
+ memset(pHeader->MD5_BetTable, 0, MD5_DIGEST_SIZE);
+ memset(pHeader->MD5_HetTable, 0, MD5_DIGEST_SIZE);
+ memset(pHeader->MD5_MpqHeader, 0, MD5_DIGEST_SIZE);
+ // No break here !!!!
+
+ case MPQ_FORMAT_VERSION_4:
+
+ // Verify header MD5. Header MD5 is calculated from the MPQ header since the 'MPQ\x1A'
+ // signature until the position of header MD5 at offset 0xC0
+ if(!VerifyDataBlockHash(ha->pHeader, MPQ_HEADER_SIZE_V4 - MD5_DIGEST_SIZE, ha->pHeader->MD5_MpqHeader))
+ nError = ERROR_FILE_CORRUPT;
+ break;
+ }
+
+ return nError;
+}
+
+//-----------------------------------------------------------------------------
+// Default flags for (attributes) and (listfile)
+
+DWORD GetDefaultSpecialFileFlags(TMPQArchive * ha, DWORD dwFileSize)
+{
+ // Fixed for format 1.0
+ if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1)
+ return MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY;
+
+ // Size-dependent for formats 2.0-4.0
+ return (dwFileSize > 0x4000) ? (MPQ_FILE_COMPRESS | MPQ_FILE_SECTOR_CRC) : (MPQ_FILE_COMPRESS | MPQ_FILE_SINGLE_UNIT);
+}
+
+
+//-----------------------------------------------------------------------------
+// Encrypting and decrypting MPQ file data
+
+void EncryptMpqBlock(void * pvFileBlock, DWORD dwLength, DWORD dwSeed1)
+{
+ LPDWORD block = (LPDWORD)pvFileBlock;
+ DWORD dwSeed2 = 0xEEEEEEEE;
+ DWORD ch;
+
+ // Round to DWORDs
+ dwLength >>= 2;
+
+ while(dwLength-- > 0)
+ {
+ dwSeed2 += StormBuffer[0x400 + (dwSeed1 & 0xFF)];
+ ch = *block;
+ *block++ = ch ^ (dwSeed1 + dwSeed2);
+
+ dwSeed1 = ((~dwSeed1 << 0x15) + 0x11111111) | (dwSeed1 >> 0x0B);
+ dwSeed2 = ch + dwSeed2 + (dwSeed2 << 5) + 3;
+ }
+}
+
+void DecryptMpqBlock(void * pvFileBlock, DWORD dwLength, DWORD dwSeed1)
+{
+ LPDWORD block = (LPDWORD)pvFileBlock;
+ DWORD dwSeed2 = 0xEEEEEEEE;
+ DWORD ch;
+
+ // Round to DWORDs
+ dwLength >>= 2;
+
+ while(dwLength-- > 0)
+ {
+ dwSeed2 += StormBuffer[0x400 + (dwSeed1 & 0xFF)];
+ ch = *block ^ (dwSeed1 + dwSeed2);
+
+ dwSeed1 = ((~dwSeed1 << 0x15) + 0x11111111) | (dwSeed1 >> 0x0B);
+ dwSeed2 = ch + dwSeed2 + (dwSeed2 << 5) + 3;
+ *block++ = ch;
+ }
+}
+
+/*
+void EncryptMpqTable(void * pvMpqTable, DWORD dwLength, const char * szKey)
+{
+ EncryptMpqBlock(pvMpqTable, dwLength, HashString(szKey, MPQ_HASH_FILE_KEY));
+}
+
+void DecryptMpqTable(void * pvMpqTable, DWORD dwLength, const char * szKey)
+{
+ DecryptMpqBlock(pvMpqTable, dwLength, HashString(szKey, MPQ_HASH_FILE_KEY));
+}
+*/
+
+/**
+ * Functions tries to get file decryption key. The trick comes from sector
+ * positions which are stored at the begin of each compressed file. We know the
+ * file size, that means we know number of sectors that means we know the first
+ * DWORD value in sector position. And if we know encrypted and decrypted value,
+ * we can find the decryption key !!!
+ *
+ * hf - MPQ file handle
+ * SectorOffsets - DWORD array of sector positions
+ * ch - Decrypted value of the first sector pos
+ */
+
+DWORD DetectFileKeyBySectorSize(LPDWORD SectorOffsets, DWORD decrypted)
+{
+ DWORD saveKey1;
+ DWORD temp = *SectorOffsets ^ decrypted; // temp = seed1 + seed2
+ temp -= 0xEEEEEEEE; // temp = seed1 + StormBuffer[0x400 + (seed1 & 0xFF)]
+
+ for(int i = 0; i < 0x100; i++) // Try all 255 possibilities
+ {
+ DWORD seed1;
+ DWORD seed2 = 0xEEEEEEEE;
+ DWORD ch;
+
+ // Try the first DWORD (We exactly know the value)
+ seed1 = temp - StormBuffer[0x400 + i];
+ seed2 += StormBuffer[0x400 + (seed1 & 0xFF)];
+ ch = SectorOffsets[0] ^ (seed1 + seed2);
+
+ if(ch != decrypted)
+ continue;
+
+ // Add 1 because we are decrypting sector positions
+ saveKey1 = seed1 + 1;
+
+ // If OK, continue and test the second value. We don't know exactly the value,
+ // but we know that the second one has lower 16 bits set to zero
+ // (no compressed sector is larger than 0xFFFF bytes)
+ seed1 = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
+ seed2 = ch + seed2 + (seed2 << 5) + 3;
+
+ seed2 += StormBuffer[0x400 + (seed1 & 0xFF)];
+ ch = SectorOffsets[1] ^ (seed1 + seed2);
+
+ if((ch & 0xFFFF0000) == 0)
+ return saveKey1;
+ }
+ return 0;
+}
+
+// Function tries to detect file encryption key. It expectes at least two uncompressed bytes
+DWORD DetectFileKeyByKnownContent(void * pvFileContent, DWORD nDwords, ...)
+{
+ LPDWORD pdwContent = (LPDWORD)pvFileContent;
+ va_list argList;
+ DWORD dwDecrypted[0x10];
+ DWORD saveKey1;
+ DWORD dwTemp;
+ DWORD i, j;
+
+ // We need at least two DWORDS to detect the file key
+ if(nDwords < 0x02 || nDwords > 0x10)
+ return 0;
+
+ va_start(argList, nDwords);
+ for(i = 0; i < nDwords; i++)
+ dwDecrypted[i] = va_arg(argList, DWORD);
+ va_end(argList);
+
+ dwTemp = (*pdwContent ^ dwDecrypted[0]) - 0xEEEEEEEE;
+ for(i = 0; i < 0x100; i++) // Try all 256 possibilities
+ {
+ DWORD seed1;
+ DWORD seed2 = 0xEEEEEEEE;
+ DWORD ch;
+
+ // Try the first DWORD
+ seed1 = dwTemp - StormBuffer[0x400 + i];
+ seed2 += StormBuffer[0x400 + (seed1 & 0xFF)];
+ ch = pdwContent[0] ^ (seed1 + seed2);
+
+ if(ch != dwDecrypted[0])
+ continue;
+
+ saveKey1 = seed1;
+
+ // If OK, continue and test all bytes.
+ for(j = 1; j < nDwords; j++)
+ {
+ seed1 = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
+ seed2 = ch + seed2 + (seed2 << 5) + 3;
+
+ seed2 += StormBuffer[0x400 + (seed1 & 0xFF)];
+ ch = pdwContent[j] ^ (seed1 + seed2);
+
+ if(ch == dwDecrypted[j] && j == nDwords - 1)
+ return saveKey1;
+ }
+ }
+ return 0;
+}
+
+DWORD DetectFileKeyByContent(void * pvFileContent, DWORD dwFileSize)
+{
+ DWORD dwFileKey;
+
+ // Try to break the file encryption key as if it was a WAVE file
+ if(dwFileSize >= 0x0C)
+ {
+ dwFileKey = DetectFileKeyByKnownContent(pvFileContent, 3, 0x46464952, dwFileSize - 8, 0x45564157);
+ if(dwFileKey != 0)
+ return dwFileKey;
+ }
+
+ // Try to break the encryption key as if it was an EXE file
+ if(dwFileSize > 0x40)
+ {
+ dwFileKey = DetectFileKeyByKnownContent(pvFileContent, 2, 0x00905A4D, 0x00000003);
+ if(dwFileKey != 0)
+ return dwFileKey;
+ }
+
+ // Try to break the encryption key as if it was a XML file
+ if(dwFileSize > 0x04)
+ {
+ dwFileKey = DetectFileKeyByKnownContent(pvFileContent, 2, 0x6D783F3C, 0x6576206C);
+ if(dwFileKey != 0)
+ return dwFileKey;
+ }
+
+ // Not detected, sorry
+ return 0;
+}
+
+DWORD DecryptFileKey(
+ const char * szFileName,
+ ULONGLONG MpqPos,
+ DWORD dwFileSize,
+ DWORD dwFlags)
+{
+ DWORD dwFileKey;
+ DWORD dwMpqPos = (DWORD)MpqPos;
+
+ // File key is calculated from plain name
+ szFileName = GetPlainFileNameA(szFileName);
+ dwFileKey = HashString(szFileName, MPQ_HASH_FILE_KEY);
+
+ // Fix the key, if needed
+ if(dwFlags & MPQ_FILE_FIX_KEY)
+ dwFileKey = (dwFileKey + dwMpqPos) ^ dwFileSize;
+
+ // Return the key
+ return dwFileKey;
+}
+
+//-----------------------------------------------------------------------------
+// Handle validation functions
+
+bool IsValidMpqHandle(TMPQArchive * ha)
+{
+ if(ha == NULL)
+ return false;
+ if(ha->pHeader == NULL || ha->pHeader->dwID != ID_MPQ)
+ return false;
+
+ return (bool)(ha->pHeader->dwID == ID_MPQ);
+}
+
+bool IsValidFileHandle(TMPQFile * hf)
+{
+ if(hf == NULL)
+ return false;
+
+ if(hf->dwMagic != ID_MPQ_FILE)
+ return false;
+
+ if(hf->pStream != NULL)
+ return true;
+
+ return IsValidMpqHandle(hf->ha);
+}
+
+//-----------------------------------------------------------------------------
+// Hash table and block table manipulation
+
+// Retrieves the first hash entry for the given file.
+// Every locale version of a file has its own hash entry
+TMPQHash * GetFirstHashEntry(TMPQArchive * ha, const char * szFileName)
+{
+ TMPQHash * pStartHash; // File hash entry (start)
+ TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
+ TMPQHash * pHash; // File hash entry (current)
+ DWORD dwHashTableSizeMask;
+ DWORD dwIndex = HashString(szFileName, MPQ_HASH_TABLE_INDEX);
+ DWORD dwName1 = HashString(szFileName, MPQ_HASH_NAME_A);
+ DWORD dwName2 = HashString(szFileName, MPQ_HASH_NAME_B);
+
+ // Get the first possible has entry that might be the one
+ dwHashTableSizeMask = ha->pHeader->dwHashTableSize ? (ha->pHeader->dwHashTableSize - 1) : 0;
+ pStartHash = pHash = ha->pHashTable + (dwIndex & dwHashTableSizeMask);
+
+ // There might be deleted entries in the hash table prior to our desired entry.
+ while(pHash->dwBlockIndex != HASH_ENTRY_FREE)
+ {
+ // If the entry agrees, we found it.
+ if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && pHash->dwBlockIndex < ha->dwFileTableSize)
+ return pHash;
+
+ // Move to the next hash entry. Stop searching
+ // if we got reached the original hash entry
+ if(++pHash >= pHashEnd)
+ pHash = ha->pHashTable;
+ if(pHash == pStartHash)
+ break;
+ }
+
+ // The apropriate hash entry was not found
+ return NULL;
+}
+
+TMPQHash * GetNextHashEntry(TMPQArchive * ha, TMPQHash * pFirstHash, TMPQHash * pPrevHash)
+{
+ TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
+ TMPQHash * pHash = pPrevHash;
+ DWORD dwName1 = pPrevHash->dwName1;
+ DWORD dwName2 = pPrevHash->dwName2;
+
+ // Now go for any next entry that follows the pPrevHash,
+ // until either free hash entry was found, or the start entry was reached
+ for(;;)
+ {
+ // Move to the next hash entry. Stop searching
+ // if we got reached the original hash entry
+ if(++pHash >= pHashEnd)
+ pHash = ha->pHashTable;
+ if(pHash == pFirstHash)
+ break;
+
+ // If the entry is a free entry, stop search
+ if(pHash->dwBlockIndex == HASH_ENTRY_FREE)
+ break;
+
+ // If the entry is not free and the name agrees, we found it
+ if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && pHash->dwBlockIndex < ha->pHeader->dwBlockTableSize)
+ return pHash;
+ }
+
+ // No next entry
+ return NULL;
+}
+
+// Allocates an entry in the hash table
+DWORD AllocateHashEntry(
+ TMPQArchive * ha,
+ TFileEntry * pFileEntry)
+{
+ TMPQHash * pStartHash; // File hash entry (start)
+ TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
+ TMPQHash * pHash; // File hash entry (current)
+ DWORD dwHashTableSizeMask;
+ DWORD dwIndex = HashString(pFileEntry->szFileName, MPQ_HASH_TABLE_INDEX);
+ DWORD dwName1 = HashString(pFileEntry->szFileName, MPQ_HASH_NAME_A);
+ DWORD dwName2 = HashString(pFileEntry->szFileName, MPQ_HASH_NAME_B);
+
+ // Get the first possible has entry that might be the one
+ dwHashTableSizeMask = ha->pHeader->dwHashTableSize ? (ha->pHeader->dwHashTableSize - 1) : 0;
+ pStartHash = pHash = ha->pHashTable + (dwIndex & dwHashTableSizeMask);
+
+ // There might be deleted entries in the hash table prior to our desired entry.
+ while(pHash->dwBlockIndex < HASH_ENTRY_DELETED)
+ {
+ // If there already is an existing entry, reuse it.
+ if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && pHash->lcLocale == pFileEntry->lcLocale)
+ break;
+
+ // Move to the next hash entry.
+ // If we reached the starting entry, it's failure.
+ if(++pHash >= pHashEnd)
+ pHash = ha->pHashTable;
+ if(pHash == pStartHash)
+ return HASH_ENTRY_FREE;
+ }
+
+ // Fill the free hash entry
+ pHash->dwName1 = dwName1;
+ pHash->dwName2 = dwName2;
+ pHash->lcLocale = pFileEntry->lcLocale;
+ pHash->wPlatform = pFileEntry->wPlatform;
+ pHash->dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable);
+
+ // Fill the hash index in the file entry
+ pFileEntry->dwHashIndex = (DWORD)(pHash - ha->pHashTable);
+ return pFileEntry->dwHashIndex;
+}
+
+// Finds a free space in the MPQ where to store next data
+// The free space begins beyond the file that is stored at the fuhrtest
+// position in the MPQ.
+void FindFreeMpqSpace(TMPQArchive * ha, ULONGLONG * pFreeSpacePos)
+{
+ TMPQHeader * pHeader = ha->pHeader;
+ TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
+ TFileEntry * pFileEntry = ha->pFileTable;
+ ULONGLONG FreeSpacePos = ha->pHeader->dwHeaderSize;
+ DWORD dwChunkCount;
+
+ // Parse the entire block table
+ for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
+ {
+ // Only take existing files
+ if(pFileEntry->dwFlags & MPQ_FILE_EXISTS)
+ {
+ // If the end of the file is bigger than current MPQ table pos, update it
+ if((pFileEntry->ByteOffset + pFileEntry->dwCmpSize) > FreeSpacePos)
+ {
+ // Get the end of the file data
+ FreeSpacePos = pFileEntry->ByteOffset + pFileEntry->dwCmpSize;
+
+ // Add the MD5 chunks, if present
+ if(pHeader->dwRawChunkSize != 0 && pFileEntry->dwCmpSize != 0)
+ {
+ dwChunkCount = ((pFileEntry->dwCmpSize - 1) / pHeader->dwRawChunkSize) + 1;
+ FreeSpacePos += dwChunkCount * MD5_DIGEST_SIZE;
+ }
+ }
+ }
+ }
+
+ // Give the free space position to the caller
+ if(pFreeSpacePos != NULL)
+ *pFreeSpacePos = FreeSpacePos;
+}
+
+//-----------------------------------------------------------------------------
+// Common functions - MPQ File
+
+TMPQFile * CreateMpqFile(TMPQArchive * ha)
+{
+ TMPQFile * hf;
+
+ // Allocate space for TMPQFile
+ hf = STORM_ALLOC(TMPQFile, 1);
+ if(hf != NULL)
+ {
+ // Fill the file structure
+ memset(hf, 0, sizeof(TMPQFile));
+ hf->ha = ha;
+ hf->pStream = NULL;
+ hf->dwMagic = ID_MPQ_FILE;
+ }
+
+ return hf;
+}
+
+// Loads a table from MPQ.
+// Can be used for hash table, block table, sector offset table or sector checksum table
+int LoadMpqTable(
+ TMPQArchive * ha,
+ ULONGLONG ByteOffset,
+ void * pvTable,
+ DWORD dwCompressedSize,
+ DWORD dwRealSize,
+ DWORD dwKey)
+{
+ LPBYTE pbCompressed = NULL;
+ LPBYTE pbToRead = (LPBYTE)pvTable;
+ int nError = ERROR_SUCCESS;
+
+ // "interface.MPQ.part" in trial version of World of Warcraft
+ // has block table and hash table compressed.
+ if(dwCompressedSize < dwRealSize)
+ {
+ // Allocate temporary buffer for holding compressed data
+ pbCompressed = STORM_ALLOC(BYTE, dwCompressedSize);
+ if(pbCompressed == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Assign the temporary buffer as target for read operation
+ pbToRead = pbCompressed;
+ }
+
+ // Read the table
+ if(FileStream_Read(ha->pStream, &ByteOffset, pbToRead, dwCompressedSize))
+ {
+ // First of all, decrypt the table
+ if(dwKey != 0)
+ {
+ BSWAP_ARRAY32_UNSIGNED(pbToRead, dwCompressedSize);
+ DecryptMpqBlock(pbToRead, dwCompressedSize, dwKey);
+ BSWAP_ARRAY32_UNSIGNED(pbToRead, dwCompressedSize);
+ }
+
+ // If the table is compressed, decompress it
+ if(dwCompressedSize < dwRealSize)
+ {
+ int cbOutBuffer = (int)dwRealSize;
+ int cbInBuffer = (int)dwCompressedSize;
+
+ if(!SCompDecompress2((char *)pvTable, &cbOutBuffer, (char *)pbCompressed, cbInBuffer))
+ nError = GetLastError();
+
+ // Free the temporary buffer
+ STORM_FREE(pbCompressed);
+ }
+ }
+ else
+ {
+ nError = GetLastError();
+ }
+
+ BSWAP_ARRAY32_UNSIGNED(pvTable, dwRealSize);
+ return nError;
+}
+
+void CalculateRawSectorOffset(
+ ULONGLONG & RawFilePos,
+ TMPQFile * hf,
+ DWORD dwSectorOffset)
+{
+ //
+ // Some MPQ protectors place the sector offset table after the actual file data.
+ // Sector offsets in the sector offset table are negative. When added
+ // to MPQ file offset from the block table entry, the result is a correct
+ // position of the file data in the MPQ.
+ //
+ // The position of sector table must be always within the MPQ, however.
+ // When a negative sector offset is found, we make sure that we make the addition
+ // just in 32-bits, and then add the MPQ offset.
+ //
+
+ if(dwSectorOffset & 0x80000000)
+ {
+ RawFilePos = hf->ha->MpqPos + ((DWORD)hf->pFileEntry->ByteOffset + dwSectorOffset);
+ }
+ else
+ {
+ RawFilePos = hf->RawFilePos + dwSectorOffset;
+ }
+
+ // We also have to add patch header size, if patch header is present
+ if(hf->pPatchInfo != NULL)
+ RawFilePos += hf->pPatchInfo->dwLength;
+}
+
+unsigned char * AllocateMd5Buffer(
+ DWORD dwRawDataSize,
+ DWORD dwChunkSize,
+ LPDWORD pcbMd5Size)
+{
+ unsigned char * md5_array;
+ DWORD cbMd5Size;
+
+ // Sanity check
+ assert(dwRawDataSize != 0);
+ assert(dwChunkSize != 0);
+
+ // Calculate how many MD5's we will calculate
+ cbMd5Size = (((dwRawDataSize - 1) / dwChunkSize) + 1) * MD5_DIGEST_SIZE;
+
+ // Allocate space for array or MD5s
+ md5_array = STORM_ALLOC(BYTE, cbMd5Size);
+
+ // Give the size of the MD5 array
+ if(pcbMd5Size != NULL)
+ *pcbMd5Size = cbMd5Size;
+ return md5_array;
+}
+
+// Allocates sector buffer and sector offset table
+int AllocateSectorBuffer(TMPQFile * hf)
+{
+ TMPQArchive * ha = hf->ha;
+
+ // Caller of AllocateSectorBuffer must ensure these
+ assert(hf->pbFileSector == NULL);
+ assert(hf->pFileEntry != NULL);
+ assert(hf->ha != NULL);
+
+ // Don't allocate anything if the file has zero size
+ if(hf->pFileEntry->dwFileSize == 0 || hf->dwDataSize == 0)
+ return ERROR_SUCCESS;
+
+ // Determine the file sector size and allocate buffer for it
+ hf->dwSectorSize = (hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) ? hf->dwDataSize : ha->dwSectorSize;
+ hf->pbFileSector = STORM_ALLOC(BYTE, hf->dwSectorSize);
+ hf->dwSectorOffs = SFILE_INVALID_POS;
+
+ // Return result
+ return (hf->pbFileSector != NULL) ? (int)ERROR_SUCCESS : (int)ERROR_NOT_ENOUGH_MEMORY;
+}
+
+// Allocates sector offset table
+int AllocatePatchInfo(TMPQFile * hf, bool bLoadFromFile)
+{
+ TMPQArchive * ha = hf->ha;
+ DWORD dwLength = sizeof(TPatchInfo);
+
+ // The following conditions must be true
+ assert(hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE);
+ assert(hf->pPatchInfo == NULL);
+
+__AllocateAndLoadPatchInfo:
+
+ // Allocate space for patch header. Start with default size,
+ // and if its size if bigger, then we reload them
+ hf->pPatchInfo = (TPatchInfo *)STORM_ALLOC(BYTE, dwLength);
+ if(hf->pPatchInfo == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Do we have to load the patch header from the file ?
+ if(bLoadFromFile)
+ {
+ // Load the patch header
+ if(!FileStream_Read(ha->pStream, &hf->RawFilePos, hf->pPatchInfo, dwLength))
+ {
+ // Free the patch info
+ STORM_FREE(hf->pPatchInfo);
+ hf->pPatchInfo = NULL;
+ return GetLastError();
+ }
+
+ // Perform necessary swapping
+ hf->pPatchInfo->dwLength = BSWAP_INT32_UNSIGNED(hf->pPatchInfo->dwLength);
+ hf->pPatchInfo->dwFlags = BSWAP_INT32_UNSIGNED(hf->pPatchInfo->dwFlags);
+ hf->pPatchInfo->dwDataSize = BSWAP_INT32_UNSIGNED(hf->pPatchInfo->dwDataSize);
+
+ // Verify the size of the patch header
+ // If it's not default size, we have to reload them
+ if(hf->pPatchInfo->dwLength > dwLength)
+ {
+ // Free the patch info
+ dwLength = hf->pPatchInfo->dwLength;
+ STORM_FREE(hf->pPatchInfo);
+ hf->pPatchInfo = NULL;
+
+ // If the length is out of all possible ranges, fail the operation
+ if(dwLength > 0x400)
+ return ERROR_FILE_CORRUPT;
+ goto __AllocateAndLoadPatchInfo;
+ }
+
+ // Patch file data size according to the patch header
+ hf->dwDataSize = hf->pPatchInfo->dwDataSize;
+ }
+ else
+ {
+ memset(hf->pPatchInfo, 0, dwLength);
+ }
+
+ // Save the final length to the patch header
+ hf->pPatchInfo->dwLength = dwLength;
+ hf->pPatchInfo->dwFlags = 0x80000000;
+ return ERROR_SUCCESS;
+}
+
+// Allocates sector offset table
+int AllocateSectorOffsets(TMPQFile * hf, bool bLoadFromFile)
+{
+ TMPQArchive * ha = hf->ha;
+ TFileEntry * pFileEntry = hf->pFileEntry;
+ DWORD dwSectorOffsLen;
+ bool bSectorOffsetTableCorrupt = false;
+
+ // Caller of AllocateSectorOffsets must ensure these
+ assert(hf->SectorOffsets == NULL);
+ assert(hf->pFileEntry != NULL);
+ assert(hf->dwDataSize != 0);
+ assert(hf->ha != NULL);
+
+ // If the file is stored as single unit, just set number of sectors to 1
+ if(pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT)
+ {
+ hf->dwSectorCount = 1;
+ return ERROR_SUCCESS;
+ }
+
+ // Calculate the number of data sectors
+ // Note that this doesn't work if the file size is zero
+ hf->dwSectorCount = ((hf->dwDataSize - 1) / hf->dwSectorSize) + 1;
+
+ // Calculate the number of file sectors
+ dwSectorOffsLen = (hf->dwSectorCount + 1) * sizeof(DWORD);
+
+ // If MPQ_FILE_SECTOR_CRC flag is set, there will either be extra DWORD
+ // or an array of MD5's. Either way, we read at least 4 bytes more
+ // in order to save additional read from the file.
+ if(pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC)
+ dwSectorOffsLen += sizeof(DWORD);
+
+ // Only allocate and load the table if the file is compressed
+ if(pFileEntry->dwFlags & MPQ_FILE_COMPRESSED)
+ {
+ __LoadSectorOffsets:
+
+ // Allocate the sector offset table
+ hf->SectorOffsets = (DWORD *)STORM_ALLOC(BYTE, dwSectorOffsLen);
+ if(hf->SectorOffsets == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Only read from the file if we are supposed to do so
+ if(bLoadFromFile)
+ {
+ ULONGLONG RawFilePos = hf->RawFilePos;
+
+ if(hf->pPatchInfo != NULL)
+ RawFilePos += hf->pPatchInfo->dwLength;
+
+ // Load the sector offsets from the file
+ if(!FileStream_Read(ha->pStream, &RawFilePos, hf->SectorOffsets, dwSectorOffsLen))
+ {
+ // Free the sector offsets
+ STORM_FREE(hf->SectorOffsets);
+ hf->SectorOffsets = NULL;
+ return GetLastError();
+ }
+
+ // Swap the sector positions
+ BSWAP_ARRAY32_UNSIGNED(hf->SectorOffsets, dwSectorOffsLen);
+
+ // Decrypt loaded sector positions if necessary
+ if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
+ {
+ // If we don't know the file key, try to find it.
+ if(hf->dwFileKey == 0)
+ {
+ hf->dwFileKey = DetectFileKeyBySectorSize(hf->SectorOffsets, dwSectorOffsLen);
+ if(hf->dwFileKey == 0)
+ {
+ STORM_FREE(hf->SectorOffsets);
+ hf->SectorOffsets = NULL;
+ return ERROR_UNKNOWN_FILE_KEY;
+ }
+ }
+
+ // Decrypt sector positions
+ DecryptMpqBlock(hf->SectorOffsets, dwSectorOffsLen, hf->dwFileKey - 1);
+ }
+
+ //
+ // Validate the sector offset table
+ //
+ // Note: Some MPQ protectors put the actual file data before the sector offset table.
+ // In this case, the sector offsets are negative (> 0x80000000).
+ //
+
+ for(DWORD i = 0; i < hf->dwSectorCount; i++)
+ {
+ DWORD dwSectorOffset1 = hf->SectorOffsets[i+1];
+ DWORD dwSectorOffset0 = hf->SectorOffsets[i];
+
+ // Every following sector offset must be bigger than the previous one
+ if(dwSectorOffset1 <= dwSectorOffset0)
+ {
+ bSectorOffsetTableCorrupt = true;
+ break;
+ }
+
+ // The sector size must not be bigger than compressed file size
+ if((dwSectorOffset1 - dwSectorOffset0) > pFileEntry->dwCmpSize)
+ {
+ bSectorOffsetTableCorrupt = true;
+ break;
+ }
+ }
+
+ // If data corruption detected, free the sector offset table
+ if(bSectorOffsetTableCorrupt)
+ {
+ STORM_FREE(hf->SectorOffsets);
+ hf->SectorOffsets = NULL;
+ return ERROR_FILE_CORRUPT;
+ }
+
+ //
+ // There may be various extra DWORDs loaded after the sector offset table.
+ // They are mostly empty on WoW release MPQs, but on MPQs from PTR,
+ // they contain random non-zero data. Their meaning is unknown.
+ //
+ // These extra values are, however, include in the dwCmpSize in the file
+ // table. We cannot ignore them, because compacting archive would fail
+ //
+
+ if(hf->SectorOffsets[0] > dwSectorOffsLen)
+ {
+ dwSectorOffsLen = hf->SectorOffsets[0];
+ STORM_FREE(hf->SectorOffsets);
+ hf->SectorOffsets = NULL;
+ goto __LoadSectorOffsets;
+ }
+ }
+ else
+ {
+ memset(hf->SectorOffsets, 0, dwSectorOffsLen);
+ hf->SectorOffsets[0] = dwSectorOffsLen;
+ }
+ }
+
+ return ERROR_SUCCESS;
+}
+
+int AllocateSectorChecksums(TMPQFile * hf, bool bLoadFromFile)
+{
+ TMPQArchive * ha = hf->ha;
+ TFileEntry * pFileEntry = hf->pFileEntry;
+ ULONGLONG RawFilePos;
+ DWORD dwCompressedSize = 0;
+ DWORD dwExpectedSize;
+ DWORD dwCrcOffset; // Offset of the CRC table, relative to file offset in the MPQ
+ DWORD dwCrcSize;
+
+ // Caller of AllocateSectorChecksums must ensure these
+ assert(hf->SectorChksums == NULL);
+ assert(hf->SectorOffsets != NULL);
+ assert(hf->pFileEntry != NULL);
+ assert(hf->ha != NULL);
+
+ // Single unit files don't have sector checksums
+ if(pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT)
+ return ERROR_SUCCESS;
+
+ // Caller must ensure that we are only called when we have sector checksums
+ assert(pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC);
+
+ //
+ // Older MPQs store an array of CRC32's after
+ // the raw file data in the MPQ.
+ //
+ // In newer MPQs, the (since Cataclysm BETA) the (attributes) file
+ // contains additional 32-bit values beyond the sector table.
+ // Their number depends on size of the (attributes), but their
+ // meaning is unknown. They are usually zeroed in retail game files,
+ // but contain some sort of checksum in BETA MPQs
+ //
+
+ // Does the size of the file table match with the CRC32-based checksums?
+ dwExpectedSize = (hf->dwSectorCount + 2) * sizeof(DWORD);
+ if(hf->SectorOffsets[0] == dwExpectedSize)
+ {
+ // Is there valid size of the sector checksums?
+ if(hf->SectorOffsets[hf->dwSectorCount + 1] >= hf->SectorOffsets[hf->dwSectorCount])
+ dwCompressedSize = hf->SectorOffsets[hf->dwSectorCount + 1] - hf->SectorOffsets[hf->dwSectorCount];
+
+ // Ignore cases when the length is too small or too big.
+ if(dwCompressedSize < sizeof(DWORD) || dwCompressedSize > hf->dwSectorSize)
+ return ERROR_SUCCESS;
+
+ // Allocate the array for the sector checksums
+ hf->SectorChksums = STORM_ALLOC(DWORD, hf->dwSectorCount);
+ if(hf->SectorChksums == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // If we are not supposed to load it from the file, allocate empty buffer
+ if(bLoadFromFile == false)
+ {
+ memset(hf->SectorChksums, 0, hf->dwSectorCount * sizeof(DWORD));
+ return ERROR_SUCCESS;
+ }
+
+ // Calculate offset of the CRC table
+ dwCrcSize = hf->dwSectorCount * sizeof(DWORD);
+ dwCrcOffset = hf->SectorOffsets[hf->dwSectorCount];
+ CalculateRawSectorOffset(RawFilePos, hf, dwCrcOffset);
+
+ // Now read the table from the MPQ
+ return LoadMpqTable(ha, RawFilePos, hf->SectorChksums, dwCompressedSize, dwCrcSize, 0);
+ }
+
+ // If the size doesn't match, we ignore sector checksums
+// assert(false);
+ return ERROR_SUCCESS;
+}
+
+int WritePatchInfo(TMPQFile * hf)
+{
+ TMPQArchive * ha = hf->ha;
+ TPatchInfo * pPatchInfo = hf->pPatchInfo;
+
+ // The caller must make sure that this function is only called
+ // when the following is true.
+ assert(hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE);
+ assert(pPatchInfo != NULL);
+
+ BSWAP_ARRAY32_UNSIGNED(pPatchInfo, 3 * sizeof(DWORD));
+ if(!FileStream_Write(ha->pStream, &hf->RawFilePos, pPatchInfo, sizeof(TPatchInfo)))
+ return GetLastError();
+
+ return ERROR_SUCCESS;
+}
+
+int WriteSectorOffsets(TMPQFile * hf)
+{
+ TMPQArchive * ha = hf->ha;
+ TFileEntry * pFileEntry = hf->pFileEntry;
+ ULONGLONG RawFilePos = hf->RawFilePos;
+ DWORD dwSectorOffsLen;
+
+ // The caller must make sure that this function is only called
+ // when the following is true.
+ assert(hf->pFileEntry->dwFlags & MPQ_FILE_COMPRESSED);
+ assert(hf->SectorOffsets != NULL);
+ dwSectorOffsLen = hf->SectorOffsets[0];
+
+ // If file is encrypted, sector positions are also encrypted
+ if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
+ EncryptMpqBlock(hf->SectorOffsets, dwSectorOffsLen, hf->dwFileKey - 1);
+ BSWAP_ARRAY32_UNSIGNED(hf->SectorOffsets, dwSectorOffsLen);
+
+ // Adjust sector offset table position, if we also have patch info
+ if(hf->pPatchInfo != NULL)
+ RawFilePos += hf->pPatchInfo->dwLength;
+
+ // Write sector offsets to the archive
+ if(!FileStream_Write(ha->pStream, &RawFilePos, hf->SectorOffsets, dwSectorOffsLen))
+ return GetLastError();
+
+ // Not necessary, as the sector checksums
+ // are going to be freed when this is done.
+// BSWAP_ARRAY32_UNSIGNED(hf->SectorOffsets, dwSectorOffsLen);
+ return ERROR_SUCCESS;
+}
+
+
+int WriteSectorChecksums(TMPQFile * hf)
+{
+ TMPQArchive * ha = hf->ha;
+ ULONGLONG RawFilePos;
+ TFileEntry * pFileEntry = hf->pFileEntry;
+ LPBYTE pbCompressed;
+ DWORD dwCompressedSize = 0;
+ DWORD dwCrcSize;
+ int nOutSize;
+ int nError = ERROR_SUCCESS;
+
+ // The caller must make sure that this function is only called
+ // when the following is true.
+ assert(hf->pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC);
+ assert(hf->SectorOffsets != NULL);
+ assert(hf->SectorChksums != NULL);
+
+ // If the MPQ has MD5 of each raw data chunk,
+ // we leave sector offsets empty
+ if(ha->pHeader->dwRawChunkSize != 0)
+ {
+ hf->SectorOffsets[hf->dwSectorCount + 1] = hf->SectorOffsets[hf->dwSectorCount];
+ return ERROR_SUCCESS;
+ }
+
+ // Calculate size of the checksum array
+ dwCrcSize = hf->dwSectorCount * sizeof(DWORD);
+
+ // Allocate buffer for compressed sector CRCs.
+ pbCompressed = STORM_ALLOC(BYTE, dwCrcSize);
+ if(pbCompressed == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Perform the compression
+ BSWAP_ARRAY32_UNSIGNED(hf->SectorChksums, dwCrcSize);
+
+ nOutSize = (int)dwCrcSize;
+ SCompCompress((char *)pbCompressed, &nOutSize, (char *)hf->SectorChksums, (int)dwCrcSize, MPQ_COMPRESSION_ZLIB, 0, 0);
+ dwCompressedSize = (DWORD)nOutSize;
+
+ // Write the sector CRCs to the archive
+ RawFilePos = hf->RawFilePos + hf->SectorOffsets[hf->dwSectorCount];
+ if(hf->pPatchInfo != NULL)
+ RawFilePos += hf->pPatchInfo->dwLength;
+ if(!FileStream_Write(ha->pStream, &RawFilePos, pbCompressed, dwCompressedSize))
+ nError = GetLastError();
+
+ // Not necessary, as the sector checksums
+ // are going to be freed when this is done.
+// BSWAP_ARRAY32_UNSIGNED(hf->SectorChksums, dwCrcSize);
+
+ // Store the sector CRCs
+ hf->SectorOffsets[hf->dwSectorCount + 1] = hf->SectorOffsets[hf->dwSectorCount] + dwCompressedSize;
+ pFileEntry->dwCmpSize += dwCompressedSize;
+ STORM_FREE(pbCompressed);
+ return nError;
+}
+
+int WriteMemDataMD5(
+ TFileStream * pStream,
+ ULONGLONG RawDataOffs,
+ void * pvRawData,
+ DWORD dwRawDataSize,
+ DWORD dwChunkSize,
+ LPDWORD pcbTotalSize)
+{
+ unsigned char * md5_array;
+ unsigned char * md5;
+ LPBYTE pbRawData = (LPBYTE)pvRawData;
+ DWORD dwBytesRemaining = dwRawDataSize;
+ DWORD dwMd5ArraySize = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Allocate buffer for array of MD5
+ md5_array = md5 = AllocateMd5Buffer(dwRawDataSize, dwChunkSize, &dwMd5ArraySize);
+ if(md5_array == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // For every file chunk, calculate MD5
+ while(dwBytesRemaining != 0)
+ {
+ // Get the remaining number of bytes to read
+ dwChunkSize = STORMLIB_MIN(dwBytesRemaining, dwChunkSize);
+
+ // Calculate MD5
+ CalculateDataBlockHash(pbRawData, dwChunkSize, md5);
+ md5 += MD5_DIGEST_SIZE;
+
+ // Move offset and size
+ dwBytesRemaining -= dwChunkSize;
+ pbRawData += dwChunkSize;
+ }
+
+ // Write the array od MD5's to the file
+ RawDataOffs += dwRawDataSize;
+ if(!FileStream_Write(pStream, &RawDataOffs, md5_array, dwMd5ArraySize))
+ nError = GetLastError();
+
+ // Give the caller the size of the MD5 array
+ if(pcbTotalSize != NULL)
+ *pcbTotalSize = dwRawDataSize + dwMd5ArraySize;
+
+ // Free buffers and exit
+ STORM_FREE(md5_array);
+ return nError;
+}
+
+
+// Writes the MD5 for each chunk of the raw file data
+int WriteMpqDataMD5(
+ TFileStream * pStream,
+ ULONGLONG RawDataOffs,
+ DWORD dwRawDataSize,
+ DWORD dwChunkSize)
+{
+ unsigned char * md5_array;
+ unsigned char * md5;
+ LPBYTE pbFileChunk;
+ DWORD dwMd5ArraySize = 0;
+ DWORD dwToRead = dwRawDataSize;
+ int nError = ERROR_SUCCESS;
+
+ // Allocate buffer for array of MD5
+ md5_array = md5 = AllocateMd5Buffer(dwRawDataSize, dwChunkSize, &dwMd5ArraySize);
+ if(md5_array == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Allocate space for file chunk
+ pbFileChunk = STORM_ALLOC(BYTE, dwChunkSize);
+ if(pbFileChunk == NULL)
+ {
+ STORM_FREE(md5_array);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // For every file chunk, calculate MD5
+ while(dwRawDataSize != 0)
+ {
+ // Get the remaining number of bytes to read
+ dwToRead = STORMLIB_MIN(dwRawDataSize, dwChunkSize);
+
+ // Read the chunk
+ if(!FileStream_Read(pStream, &RawDataOffs, pbFileChunk, dwToRead))
+ {
+ nError = GetLastError();
+ break;
+ }
+
+ // Calculate MD5
+ CalculateDataBlockHash(pbFileChunk, dwToRead, md5);
+ md5 += MD5_DIGEST_SIZE;
+
+ // Move offset and size
+ RawDataOffs += dwToRead;
+ dwRawDataSize -= dwToRead;
+ }
+
+ // Write the array od MD5's to the file
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!FileStream_Write(pStream, NULL, md5_array, dwMd5ArraySize))
+ nError = GetLastError();
+ }
+
+ // Free buffers and exit
+ STORM_FREE(pbFileChunk);
+ STORM_FREE(md5_array);
+ return nError;
+}
+
+// Frees the structure for MPQ file
+void FreeMPQFile(TMPQFile *& hf)
+{
+ if(hf != NULL)
+ {
+ // If we have patch file attached to this one, free it first
+ if(hf->hfPatchFile != NULL)
+ FreeMPQFile(hf->hfPatchFile);
+
+ // Then free all buffers allocated in the file structure
+ if(hf->pPatchHeader != NULL)
+ STORM_FREE(hf->pPatchHeader);
+ if(hf->pbFileData != NULL)
+ STORM_FREE(hf->pbFileData);
+ if(hf->pPatchInfo != NULL)
+ STORM_FREE(hf->pPatchInfo);
+ if(hf->SectorOffsets != NULL)
+ STORM_FREE(hf->SectorOffsets);
+ if(hf->SectorChksums != NULL)
+ STORM_FREE(hf->SectorChksums);
+ if(hf->pbFileSector != NULL)
+ STORM_FREE(hf->pbFileSector);
+ FileStream_Close(hf->pStream);
+ STORM_FREE(hf);
+ hf = NULL;
+ }
+}
+
+// Frees the MPQ archive
+void FreeMPQArchive(TMPQArchive *& ha)
+{
+ if(ha != NULL)
+ {
+ // First of all, free the patch archive, if any
+ if(ha->haPatch != NULL)
+ FreeMPQArchive(ha->haPatch);
+
+ // Close the file stream
+ FileStream_Close(ha->pStream);
+ ha->pStream = NULL;
+
+ // Free the file names from the file table
+ if(ha->pFileTable != NULL)
+ {
+ for(DWORD i = 0; i < ha->dwFileTableSize; i++)
+ {
+ if(ha->pFileTable[i].szFileName != NULL)
+ STORM_FREE(ha->pFileTable[i].szFileName);
+ ha->pFileTable[i].szFileName = NULL;
+ }
+
+ // Then free all buffers allocated in the archive structure
+ STORM_FREE(ha->pFileTable);
+ }
+
+ if(ha->pBitmap != NULL)
+ STORM_FREE(ha->pBitmap);
+ if(ha->pHashTable != NULL)
+ STORM_FREE(ha->pHashTable);
+ if(ha->pHetTable != NULL)
+ FreeHetTable(ha->pHetTable);
+ STORM_FREE(ha);
+ ha = NULL;
+ }
+}
+
+const char * GetPlainFileNameA(const char * szFileName)
+{
+ const char * szPlainName = szFileName;
+
+ while(*szFileName != 0)
+ {
+ if(*szFileName == '\\' || *szFileName == '/')
+ szPlainName = szFileName + 1;
+ szFileName++;
+ }
+
+ return szPlainName;
+}
+
+const TCHAR * GetPlainFileNameT(const TCHAR * szFileName)
+{
+ const TCHAR * szPlainName = szFileName;
+
+ while(*szFileName != 0)
+ {
+ if(*szFileName == '\\' || *szFileName == '/')
+ szPlainName = szFileName + 1;
+ szFileName++;
+ }
+
+ return szPlainName;
+}
+
+bool IsInternalMpqFileName(const char * szFileName)
+{
+ if(szFileName != NULL && szFileName[0] == '(')
+ {
+ if(!_stricmp(szFileName, LISTFILE_NAME) ||
+ !_stricmp(szFileName, ATTRIBUTES_NAME) ||
+ !_stricmp(szFileName, SIGNATURE_NAME))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Verifies if the file name is a pseudo-name
+bool IsPseudoFileName(const char * szFileName, DWORD * pdwFileIndex)
+{
+ DWORD dwFileIndex = 0;
+
+ if(szFileName != NULL)
+ {
+ // Must be "File########.ext"
+ if(!_strnicmp(szFileName, "File", 4))
+ {
+ // Check 8 digits
+ for(int i = 4; i < 4+8; i++)
+ {
+ if(szFileName[i] < '0' || szFileName[i] > '9')
+ return false;
+ dwFileIndex = (dwFileIndex * 10) + (szFileName[i] - '0');
+ }
+
+ // An extension must follow
+ if(szFileName[12] == '.')
+ {
+ if(pdwFileIndex != NULL)
+ *pdwFileIndex = dwFileIndex;
+ return true;
+ }
+ }
+ }
+
+ // Not a pseudo-name
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Functions calculating and verifying the MD5 signature
+
+bool IsValidMD5(LPBYTE pbMd5)
+{
+ BYTE BitSummary = 0;
+
+ // The MD5 is considered invalid of it is zeroed
+ BitSummary |= pbMd5[0x00] | pbMd5[0x01] | pbMd5[0x02] | pbMd5[0x03] | pbMd5[0x04] | pbMd5[0x05] | pbMd5[0x06] | pbMd5[0x07];
+ BitSummary |= pbMd5[0x08] | pbMd5[0x09] | pbMd5[0x0A] | pbMd5[0x0B] | pbMd5[0x0C] | pbMd5[0x0D] | pbMd5[0x0E] | pbMd5[0x0F];
+ return (BitSummary != 0);
+}
+
+bool VerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5)
+{
+ hash_state md5_state;
+ BYTE md5_digest[MD5_DIGEST_SIZE];
+
+ // Don't verify the block if the MD5 is not valid.
+ if(!IsValidMD5(expected_md5))
+ return true;
+
+ // Calculate the MD5 of the data block
+ md5_init(&md5_state);
+ md5_process(&md5_state, (unsigned char *)pvDataBlock, cbDataBlock);
+ md5_done(&md5_state, md5_digest);
+
+ // Does the MD5's match?
+ return (memcmp(md5_digest, expected_md5, MD5_DIGEST_SIZE) == 0);
+}
+
+void CalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash)
+{
+ hash_state md5_state;
+
+ md5_init(&md5_state);
+ md5_process(&md5_state, (unsigned char *)pvDataBlock, cbDataBlock);
+ md5_done(&md5_state, md5_hash);
+}
+
+
+//-----------------------------------------------------------------------------
+// Swapping functions
+
+#ifndef PLATFORM_LITTLE_ENDIAN
+
+//
+// Note that those functions are implemented for Mac operating system,
+// as this is the only supported platform that uses big endian.
+//
+
+// Swaps a signed 16-bit integer
+int16_t SwapInt16(uint16_t data)
+{
+ return (int16_t)CFSwapInt16(data);
+}
+
+// Swaps an unsigned 16-bit integer
+uint16_t SwapUInt16(uint16_t data)
+{
+ return CFSwapInt16(data);
+}
+
+// Swaps signed 32-bit integer
+int32_t SwapInt32(uint32_t data)
+{
+ return (int32_t)CFSwapInt32(data);
+}
+
+// Swaps an unsigned 32-bit integer
+uint32_t SwapUInt32(uint32_t data)
+{
+ return CFSwapInt32(data);
+}
+
+// Swaps signed 64-bit integer
+int64_t SwapInt64(int64_t data)
+{
+ return (int64_t)CFSwapInt64(data);
+}
+
+// Swaps an unsigned 64-bit integer
+uint64_t SwapUInt64(uint64_t data)
+{
+ return CFSwapInt64(data);
+}
+
+// Swaps array of unsigned 16-bit integers
+void ConvertUInt16Buffer(void * ptr, size_t length)
+{
+ uint16_t * buffer = (uint16_t *)ptr;
+ uint32_t nElements = (uint32_t)(length / sizeof(uint16_t));
+
+ while(nElements-- > 0)
+ {
+ *buffer = SwapUInt16(*buffer);
+ buffer++;
+ }
+}
+
+// Swaps array of unsigned 32-bit integers
+void ConvertUInt32Buffer(void * ptr, size_t length)
+{
+ uint32_t * buffer = (uint32_t *)ptr;
+ uint32_t nElements = (uint32_t)(length / sizeof(uint32_t));
+
+ while(nElements-- > 0)
+ {
+ *buffer = SwapUInt32(*buffer);
+ buffer++;
+ }
+}
+
+// Swaps array of unsigned 64-bit integers
+void ConvertUInt64Buffer(void * ptr, size_t length)
+{
+ uint64_t * buffer = (uint64_t *)ptr;
+ uint32_t nElements = (uint32_t)(length / sizeof(uint64_t));
+
+ while(nElements-- > 0)
+ {
+ *buffer = SwapUInt64(*buffer);
+ buffer++;
+ }
+}
+
+// Swaps the TMPQUserData structure
+void ConvertTMPQUserData(void *userData)
+{
+ TMPQUserData * theData = (TMPQUserData *)userData;
+
+ theData->dwID = SwapUInt32(theData->dwID);
+ theData->cbUserDataSize = SwapUInt32(theData->cbUserDataSize);
+ theData->dwHeaderOffs = SwapUInt32(theData->dwHeaderOffs);
+ theData->cbUserDataHeader = SwapUInt32(theData->cbUserDataHeader);
+}
+
+// Swaps the TMPQHeader structure
+void ConvertTMPQHeader(void *header)
+{
+ TMPQHeader * theHeader = (TMPQHeader *)header;
+
+ theHeader->dwID = SwapUInt32(theHeader->dwID);
+ theHeader->dwHeaderSize = SwapUInt32(theHeader->dwHeaderSize);
+ theHeader->dwArchiveSize = SwapUInt32(theHeader->dwArchiveSize);
+ theHeader->wFormatVersion = SwapUInt16(theHeader->wFormatVersion);
+ theHeader->wSectorSize = SwapUInt16(theHeader->wSectorSize);
+ theHeader->dwHashTablePos = SwapUInt32(theHeader->dwHashTablePos);
+ theHeader->dwBlockTablePos = SwapUInt32(theHeader->dwBlockTablePos);
+ theHeader->dwHashTableSize = SwapUInt32(theHeader->dwHashTableSize);
+ theHeader->dwBlockTableSize = SwapUInt32(theHeader->dwBlockTableSize);
+
+ if(theHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2)
+ {
+ // Swap the hi-block table position
+ theHeader->HiBlockTablePos64 = SwapUInt64(theHeader->HiBlockTablePos64);
+
+ theHeader->wHashTablePosHi = SwapUInt16(theHeader->wHashTablePosHi);
+ theHeader->wBlockTablePosHi = SwapUInt16(theHeader->wBlockTablePosHi);
+
+ if(theHeader->wFormatVersion >= MPQ_FORMAT_VERSION_3)
+ {
+ theHeader->ArchiveSize64 = SwapUInt64(theHeader->ArchiveSize64);
+ theHeader->BetTablePos64 = SwapUInt64(theHeader->BetTablePos64);
+ theHeader->HetTablePos64 = SwapUInt64(theHeader->HetTablePos64);
+
+ if(theHeader->wFormatVersion >= MPQ_FORMAT_VERSION_4)
+ {
+ theHeader->HashTableSize64 = SwapUInt64(theHeader->HashTableSize64);
+ theHeader->BlockTableSize64 = SwapUInt64(theHeader->BlockTableSize64);
+ theHeader->HiBlockTableSize64 = SwapUInt64(theHeader->HiBlockTableSize64);
+ theHeader->HetTableSize64 = SwapUInt64(theHeader->HetTableSize64);
+ theHeader->BetTableSize64 = SwapUInt64(theHeader->BetTableSize64);
+ }
+ }
+ }
+}
+
+#endif // PLATFORM_LITTLE_ENDIAN
diff --git a/dep/StormLib/src/SBaseDumpData.cpp b/dep/StormLib/src/SBaseDumpData.cpp
new file mode 100644
index 00000000000..c9dcf0a3366
--- /dev/null
+++ b/dep/StormLib/src/SBaseDumpData.cpp
@@ -0,0 +1,144 @@
+/*****************************************************************************/
+/* SBaseDumpData.cpp Copyright (c) Ladislav Zezula 2011 */
+/*---------------------------------------------------------------------------*/
+/* Description : */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 26.01.11 1.00 Lad The first version of SBaseDumpData.cpp */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+#ifdef __STORMLIB_DUMP_DATA__
+
+void DumpMpqHeader(TMPQHeader * pHeader)
+{
+ printf("== MPQ Header =================================\n");
+ printf("DWORD dwID = %08X\n", pHeader->dwID);
+ printf("DWORD dwHeaderSize = %08X\n", pHeader->dwHeaderSize);
+ printf("DWORD dwArchiveSize = %08X\n", pHeader->dwArchiveSize);
+ printf("USHORT wFormatVersion = %04X\n", pHeader->wFormatVersion);
+ printf("USHORT wSectorSize = %04X\n", pHeader->wSectorSize);
+ printf("DWORD dwHashTablePos = %08X\n", pHeader->dwHashTablePos);
+ printf("DWORD dwBlockTablePos = %08X\n", pHeader->dwBlockTablePos);
+ printf("DWORD dwHashTableSize = %08X\n", pHeader->dwHashTableSize);
+ printf("DWORD dwBlockTableSize = %08X\n", pHeader->dwBlockTableSize);
+ printf("ULONGLONG HiBlockTablePos64 = %016llX\n", pHeader->HiBlockTablePos64);
+ printf("USHORT wHashTablePosHi = %04X\n", pHeader->wHashTablePosHi);
+ printf("USHORT wBlockTablePosHi = %04X\n", pHeader->wBlockTablePosHi);
+ printf("ULONGLONG ArchiveSize64 = %016llX\n", pHeader->ArchiveSize64);
+ printf("ULONGLONG BetTablePos64 = %016llX\n", pHeader->BetTablePos64);
+ printf("ULONGLONG HetTablePos64 = %016llX\n", pHeader->HetTablePos64);
+ printf("ULONGLONG HashTableSize64 = %016llX\n", pHeader->HashTableSize64);
+ printf("ULONGLONG BlockTableSize64 = %016llX\n", pHeader->BlockTableSize64);
+ printf("ULONGLONG HiBlockTableSize64 = %016llX\n", pHeader->HiBlockTableSize64);
+ printf("ULONGLONG HetTableSize64 = %016llX\n", pHeader->HetTableSize64);
+ printf("ULONGLONG BetTableSize64 = %016llX\n", pHeader->BetTableSize64);
+ printf("DWORD dwRawChunkSize = %08X\n", pHeader->dwRawChunkSize);
+ printf("-----------------------------------------------\n\n");
+}
+
+void DumpHetAndBetTable(TMPQHetTable * pHetTable, TMPQBetTable * pBetTable)
+{
+ DWORD i;
+
+ if(pHetTable == NULL || pBetTable == NULL)
+ return;
+
+ printf("== HET Header =================================\n");
+ printf("ULONGLONG AndMask64 = %016llX\n", pHetTable->AndMask64);
+ printf("ULONGLONG OrMask64 = %016llX\n", pHetTable->OrMask64);
+ printf("DWORD dwIndexSizeTotal = %08X\n", pHetTable->dwIndexSizeTotal);
+ printf("DWORD dwIndexSizeExtra = %08X\n", pHetTable->dwIndexSizeExtra);
+ printf("DWORD dwIndexSize = %08X\n", pHetTable->dwIndexSize);
+ printf("DWORD dwMaxFileCount = %08X\n", pHetTable->dwMaxFileCount);
+ printf("DWORD dwHashTableSize = %08X\n", pHetTable->dwHashTableSize);
+ printf("DWORD dwHashBitSize = %08X\n", pHetTable->dwHashBitSize);
+ printf("-----------------------------------------------\n\n");
+
+ printf("== BET Header =================================\n");
+ printf("DWORD dwTableEntrySize = %08X\n", pBetTable->dwTableEntrySize);
+ printf("DWORD dwBitIndex_FilePos = %08X\n", pBetTable->dwBitIndex_FilePos);
+ printf("DWORD dwBitIndex_FileSize = %08X\n", pBetTable->dwBitIndex_FileSize);
+ printf("DWORD dwBitIndex_CmpSize = %08X\n", pBetTable->dwBitIndex_CmpSize);
+ printf("DWORD dwBitIndex_FlagIndex = %08X\n", pBetTable->dwBitIndex_FlagIndex);
+ printf("DWORD dwBitIndex_Unknown = %08X\n", pBetTable->dwBitIndex_Unknown);
+ printf("DWORD dwBitCount_FilePos = %08X\n", pBetTable->dwBitCount_FilePos);
+ printf("DWORD dwBitCount_FileSize = %08X\n", pBetTable->dwBitCount_FileSize);
+ printf("DWORD dwBitCount_CmpSize = %08X\n", pBetTable->dwBitCount_CmpSize);
+ printf("DWORD dwBitCount_FlagIndex = %08X\n", pBetTable->dwBitCount_FlagIndex);
+ printf("DWORD dwBitCount_Unknown = %08X\n", pBetTable->dwBitCount_Unknown);
+ printf("DWORD dwBetHashSizeTotal = %08X\n", pBetTable->dwBetHashSizeTotal);
+ printf("DWORD dwBetHashSizeExtra = %08X\n", pBetTable->dwBetHashSizeExtra);
+ printf("DWORD dwBetHashSize = %08X\n", pBetTable->dwBetHashSize);
+ printf("DWORD dwMaxFileCount = %08X\n", pBetTable->dwMaxFileCount);
+ printf("DWORD dwFlagCount = %08X\n", pBetTable->dwFlagCount);
+ printf("-----------------------------------------------\n\n");
+
+ printf("== HET & Bet Table ======================================================================\n\n");
+ printf("HetIdx HetHash BetIdx BetHash ByteOffset FileSize CmpSize FlgIdx Flags \n");
+ printf("------ ------- ------ ---------------- ---------------- -------- -------- ------ --------\n");
+ for(i = 0; i < pHetTable->dwHashTableSize; i++)
+ {
+ ULONGLONG ByteOffset = 0;
+ ULONGLONG BetHash = 0;
+ DWORD dwFileSize = 0;
+ DWORD dwCmpSize = 0;
+ DWORD dwFlagIndex = 0;
+ DWORD dwFlags = 0;
+ DWORD dwBetIndex = 0;
+
+ pHetTable->pBetIndexes->GetBits(i * pHetTable->dwIndexSizeTotal,
+ pHetTable->dwIndexSize,
+ &dwBetIndex,
+ 4);
+
+ if(dwBetIndex < pHetTable->dwMaxFileCount)
+ {
+ DWORD dwEntryIndex = pBetTable->dwTableEntrySize * dwBetIndex;
+
+ pBetTable->pBetHashes->GetBits(dwBetIndex * pBetTable->dwBetHashSizeTotal,
+ pBetTable->dwBetHashSize,
+ &BetHash,
+ 8);
+
+ pBetTable->pFileTable->GetBits(dwEntryIndex + pBetTable->dwBitIndex_FilePos,
+ pBetTable->dwBitCount_FilePos,
+ &ByteOffset,
+ 8);
+
+ pBetTable->pFileTable->GetBits(dwEntryIndex + pBetTable->dwBitIndex_FileSize,
+ pBetTable->dwBitCount_FileSize,
+ &dwFileSize,
+ 4);
+
+ pBetTable->pFileTable->GetBits(dwEntryIndex + pBetTable->dwBitIndex_CmpSize,
+ pBetTable->dwBitCount_CmpSize,
+ &dwCmpSize,
+ 4);
+
+ pBetTable->pFileTable->GetBits(dwEntryIndex + pBetTable->dwBitIndex_FlagIndex,
+ pBetTable->dwBitCount_FlagIndex,
+ &dwFlagIndex,
+ 4);
+
+ dwFlags = pBetTable->pFileFlags[dwFlagIndex];
+ }
+
+ printf(" %04X %02lX %04X %016llX %016llX %08X %08X %04X %08X\n", i,
+ pHetTable->pHetHashes[i],
+ dwBetIndex,
+ BetHash,
+ ByteOffset,
+ dwFileSize,
+ dwCmpSize,
+ dwFlagIndex,
+ dwFlags);
+ }
+ printf("-----------------------------------------------------------------------------------------\n");
+}
+
+#endif // __STORMLIB_DUMP_DATA__
diff --git a/dep/StormLib/src/SBaseFileTable.cpp b/dep/StormLib/src/SBaseFileTable.cpp
new file mode 100644
index 00000000000..09379ca5da7
--- /dev/null
+++ b/dep/StormLib/src/SBaseFileTable.cpp
@@ -0,0 +1,2550 @@
+/*****************************************************************************/
+/* SBaseFileTable.cpp Copyright (c) Ladislav Zezula 2010 */
+/*---------------------------------------------------------------------------*/
+/* Description: Common handler for classic and new hash&block tables */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 06.09.10 1.00 Lad The first version of SBaseFileTable.cpp */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+//-----------------------------------------------------------------------------
+// Local defines
+
+#define INVALID_FLAG_VALUE 0xCCCCCCCC
+#define MAX_FLAG_INDEX 512
+
+//-----------------------------------------------------------------------------
+// Local structures
+
+// Structure for HET table header
+typedef struct _HET_TABLE_HEADER
+{
+ DWORD dwTableSize; // Size of the entire HET table, including HET_TABLE_HEADER (in bytes)
+ DWORD dwMaxFileCount; // Maximum number of files in the MPQ
+ DWORD dwHashTableSize; // Size of the hash table (in bytes)
+ DWORD dwHashEntrySize; // Effective size of the hash entry (in bits)
+ DWORD dwIndexSizeTotal; // Total size of file index (in bits)
+ DWORD dwIndexSizeExtra; // Extra bits in the file index
+ DWORD dwIndexSize; // Effective size of the file index (in bits)
+ DWORD dwIndexTableSize; // Size of the block index subtable (in bytes)
+
+} HET_TABLE_HEADER, *PHET_TABLE_HEADER;
+
+// Structure for BET table header
+typedef struct _BET_TABLE_HEADER
+{
+ DWORD dwTableSize; // Size of the entire BET table, including the header (in bytes)
+ DWORD dwFileCount; // Number of files in the BET table
+ DWORD dwUnknown08;
+ DWORD dwTableEntrySize; // Size of one table entry (in bits)
+ DWORD dwBitIndex_FilePos; // Bit index of the file position (within the entry record)
+ DWORD dwBitIndex_FileSize; // Bit index of the file size (within the entry record)
+ DWORD dwBitIndex_CmpSize; // Bit index of the compressed size (within the entry record)
+ DWORD dwBitIndex_FlagIndex; // Bit index of the flag index (within the entry record)
+ DWORD dwBitIndex_Unknown; // Bit index of the ??? (within the entry record)
+ DWORD dwBitCount_FilePos; // Bit size of file position (in the entry record)
+ DWORD dwBitCount_FileSize; // Bit size of file size (in the entry record)
+ DWORD dwBitCount_CmpSize; // Bit size of compressed file size (in the entry record)
+ DWORD dwBitCount_FlagIndex; // Bit size of flags index (in the entry record)
+ DWORD dwBitCount_Unknown; // Bit size of ??? (in the entry record)
+ DWORD dwBetHashSizeTotal; // Total size of the BET hash
+ DWORD dwBetHashSizeExtra; // Extra bits in the BET hash
+ DWORD dwBetHashSize; // Effective size of BET hash (in bits)
+ DWORD dwBetHashArraySize; // Size of BET hashes array, in bytes
+ DWORD dwFlagCount; // Number of flags in the following array
+
+} BET_TABLE_HEADER, *PBET_TABLE_HEADER;
+
+//-----------------------------------------------------------------------------
+// Support for calculating bit sizes
+
+static void InitFileFlagArray(LPDWORD FlagArray)
+{
+ for(DWORD dwFlagIndex = 0; dwFlagIndex < MAX_FLAG_INDEX; dwFlagIndex++)
+ FlagArray[dwFlagIndex] = INVALID_FLAG_VALUE;
+}
+
+static DWORD GetFileFlagIndex(LPDWORD FlagArray, DWORD dwFlags)
+{
+ // Find free or equal entry in the flag array
+ for(DWORD dwFlagIndex = 0; dwFlagIndex < MAX_FLAG_INDEX; dwFlagIndex++)
+ {
+ if(FlagArray[dwFlagIndex] == INVALID_FLAG_VALUE || FlagArray[dwFlagIndex] == dwFlags)
+ {
+ FlagArray[dwFlagIndex] = dwFlags;
+ return dwFlagIndex;
+ }
+ }
+
+ // This should never happen
+ assert(false);
+ return 0xFFFFFFFF;
+}
+
+static DWORD GetNecessaryBitCount(ULONGLONG MaxValue)
+{
+ DWORD dwBitCount = 0;
+
+ while(MaxValue > 0)
+ {
+ MaxValue >>= 1;
+ dwBitCount++;
+ }
+
+ return dwBitCount;
+}
+
+//-----------------------------------------------------------------------------
+// Support functions for BIT_ARRAY
+
+static USHORT SetBitsMask[] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF};
+
+static TBitArray * CreateBitArray(
+ DWORD NumberOfBits,
+ BYTE FillValue)
+{
+ TBitArray * pBitArray;
+ size_t nSize = sizeof(TBitArray) + (NumberOfBits + 7) / 8;
+
+ // Allocate the bit array
+ pBitArray = (TBitArray *)STORM_ALLOC(BYTE, nSize);
+ if(pBitArray != NULL)
+ {
+ memset(pBitArray, FillValue, nSize);
+ pBitArray->NumberOfBits = NumberOfBits;
+ }
+
+ return pBitArray;
+}
+
+void TBitArray::GetBits(
+ unsigned int nBitPosition,
+ unsigned int nBitLength,
+ void * pvBuffer,
+ int nResultByteSize)
+{
+ unsigned char * pbBuffer = (unsigned char *)pvBuffer;
+ unsigned int nBytePosition0 = (nBitPosition / 8);
+ unsigned int nBytePosition1 = nBytePosition0 + 1;
+ unsigned int nByteLength = (nBitLength / 8);
+ unsigned int nBitOffset = (nBitPosition & 0x07);
+ unsigned char BitBuffer;
+
+ // Keep compiler happy for platforms where nResultByteSize is not used
+ nResultByteSize = nResultByteSize;
+
+#ifdef _DEBUG
+ // Check if the target is properly zeroed
+ for(int i = 0; i < nResultByteSize; i++)
+ assert(pbBuffer[i] == 0);
+#endif
+
+#ifndef PLATFORM_LITTLE_ENDIAN
+ // Adjust the buffer pointer for big endian platforms
+ pbBuffer += (nResultByteSize - 1);
+#endif
+
+ // Copy whole bytes, if any
+ while(nByteLength > 0)
+ {
+ // Is the current position in the Elements byte-aligned?
+ if(nBitOffset != 0)
+ {
+ BitBuffer = (unsigned char)((Elements[nBytePosition0] >> nBitOffset) | (Elements[nBytePosition1] << (0x08 - nBitOffset)));
+ }
+ else
+ {
+ BitBuffer = Elements[nBytePosition0];
+ }
+
+#ifdef PLATFORM_LITTLE_ENDIAN
+ *pbBuffer++ = BitBuffer;
+#else
+ *pbBuffer-- = BitBuffer;
+#endif
+
+ // Move byte positions and lengths
+ nBytePosition1++;
+ nBytePosition0++;
+ nByteLength--;
+ }
+
+ // Get the rest of the bits
+ nBitLength = (nBitLength & 0x07);
+ if(nBitLength != 0)
+ {
+ *pbBuffer = (unsigned char)(Elements[nBytePosition0] >> nBitOffset);
+
+ if(nBitLength > (8 - nBitOffset))
+ *pbBuffer = (unsigned char)((Elements[nBytePosition1] << (8 - nBitOffset)) | (Elements[nBytePosition0] >> nBitOffset));
+
+ *pbBuffer &= (0x01 << nBitLength) - 1;
+ }
+}
+
+void TBitArray::SetBits(
+ unsigned int nBitPosition,
+ unsigned int nBitLength,
+ void * pvBuffer,
+ int nResultByteSize)
+{
+ unsigned char * pbBuffer = (unsigned char *)pvBuffer;
+ unsigned int nBytePosition = (nBitPosition / 8);
+ unsigned int nBitOffset = (nBitPosition & 0x07);
+ unsigned short BitBuffer = 0;
+ unsigned short AndMask = 0;
+ unsigned short OneByte = 0;
+
+ // Keep compiler happy for platforms where nResultByteSize is not used
+ nResultByteSize = nResultByteSize;
+
+#ifndef PLATFORM_LITTLE_ENDIAN
+ // Adjust the buffer pointer for big endian platforms
+ pbBuffer += (nResultByteSize - 1);
+#endif
+
+ // Copy whole bytes, if any
+ while(nBitLength > 8)
+ {
+ // Reload the bit buffer
+#ifdef PLATFORM_LITTLE_ENDIAN
+ OneByte = *pbBuffer++;
+#else
+ OneByte = *pbBuffer--;
+#endif
+ // Update the BitBuffer and AndMask for the bit array
+ BitBuffer = (BitBuffer >> 0x08) | (OneByte << nBitOffset);
+ AndMask = (AndMask >> 0x08) | (0x00FF << nBitOffset);
+
+ // Update the byte in the array
+ Elements[nBytePosition] = (BYTE)((Elements[nBytePosition] & ~AndMask) | BitBuffer);
+
+ // Move byte positions and lengths
+ nBytePosition++;
+ nBitLength -= 0x08;
+ }
+
+ if(nBitLength != 0)
+ {
+ // Reload the bit buffer
+ OneByte = *pbBuffer;
+
+ // Update the AND mask for the last bit
+ BitBuffer = (BitBuffer >> 0x08) | (OneByte << nBitOffset);
+ AndMask = (AndMask >> 0x08) | (SetBitsMask[nBitLength] << nBitOffset);
+
+ // Update the byte in the array
+ Elements[nBytePosition] = (BYTE)((Elements[nBytePosition] & ~AndMask) | BitBuffer);
+
+ // Update the next byte, if needed
+ if(AndMask & 0xFF00)
+ {
+ nBytePosition++;
+ BitBuffer >>= 0x08;
+ AndMask >>= 0x08;
+
+ Elements[nBytePosition] = (BYTE)((Elements[nBytePosition] & ~AndMask) | BitBuffer);
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Support for hash table
+
+// Returns a hash table entry in the following order:
+// 1) A hash table entry with the neutral locale
+// 2) A hash table entry with any other locale
+// 3) NULL
+static TMPQHash * GetHashEntryAny(TMPQArchive * ha, const char * szFileName)
+{
+ TMPQHash * pHashNeutral = NULL;
+ TMPQHash * pFirstHash = GetFirstHashEntry(ha, szFileName);
+ TMPQHash * pHashAny = NULL;
+ TMPQHash * pHash = pFirstHash;
+
+ // Parse the found hashes
+ while(pHash != NULL)
+ {
+ // If we found neutral hash, remember it
+ if(pHash->lcLocale == 0)
+ pHashNeutral = pHash;
+ if(pHashAny == NULL)
+ pHashAny = pHash;
+
+ // Get the next hash entry for that file
+ pHash = GetNextHashEntry(ha, pFirstHash, pHash);
+ }
+
+ // At the end, return neutral hash (if found), otherwise NULL
+ return (pHashNeutral != NULL) ? pHashNeutral : pHashAny;
+}
+
+// Returns a hash table entry in the following order:
+// 1) A hash table entry with the preferred locale
+// 2) A hash table entry with the neutral locale
+// 3) NULL
+static TMPQHash * GetHashEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale)
+{
+ TMPQHash * pHashNeutral = NULL;
+ TMPQHash * pFirstHash = GetFirstHashEntry(ha, szFileName);
+ TMPQHash * pHash = pFirstHash;
+
+ // Parse the found hashes
+ while(pHash != NULL)
+ {
+ // If the locales match, return it
+ if(pHash->lcLocale == lcLocale)
+ return pHash;
+
+ // If we found neutral hash, remember it
+ if(pHash->lcLocale == 0)
+ pHashNeutral = pHash;
+
+ // Get the next hash entry for that file
+ pHash = GetNextHashEntry(ha, pFirstHash, pHash);
+ }
+
+ // At the end, return neutral hash (if found), otherwise NULL
+ return pHashNeutral;
+}
+
+// Returns a hash table entry in the following order:
+// 1) A hash table entry with the preferred locale
+// 2) NULL
+static TMPQHash * GetHashEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcLocale)
+{
+ TMPQHash * pFirstHash = GetFirstHashEntry(ha, szFileName);
+ TMPQHash * pHash = pFirstHash;
+
+ // Parse the found hashes
+ while(pHash != NULL)
+ {
+ // If the locales match, return it
+ if(pHash->lcLocale == lcLocale)
+ return pHash;
+
+ // Get the next hash entry for that file
+ pHash = GetNextHashEntry(ha, pFirstHash, pHash);
+ }
+
+ // Not found
+ return NULL;
+}
+
+static TMPQHash * TranslateHashTable(
+ TMPQArchive * ha,
+ ULONGLONG * pcbTableSize)
+{
+ TMPQHash * pHashTable;
+ size_t HashTableSize;
+
+ // Allocate copy of the hash table
+ pHashTable = STORM_ALLOC(TMPQHash, ha->pHeader->dwHashTableSize);
+ if(pHashTable != NULL)
+ {
+ // Copy the hash table
+ HashTableSize = sizeof(TMPQHash) * ha->pHeader->dwHashTableSize;
+ memcpy(pHashTable, ha->pHashTable, HashTableSize);
+
+ // Give the size to the caller
+ if(pcbTableSize != NULL)
+ {
+ *pcbTableSize = (ULONGLONG)HashTableSize;
+ }
+ }
+
+ return pHashTable;
+}
+
+static TMPQBlock * TranslateBlockTable(
+ TMPQArchive * ha,
+ ULONGLONG * pcbTableSize,
+ bool * pbNeedHiBlockTable)
+{
+ TFileEntry * pFileEntry = ha->pFileTable;
+ TMPQBlock * pBlockTable;
+ TMPQBlock * pBlock;
+ size_t BlockTableSize;
+ bool bNeedHiBlockTable = false;
+
+ // Allocate copy of the hash table
+ pBlockTable = pBlock = STORM_ALLOC(TMPQBlock, ha->dwFileTableSize);
+ if(pBlockTable != NULL)
+ {
+ // Copy the block table
+ BlockTableSize = sizeof(TMPQBlock) * ha->dwFileTableSize;
+ for(DWORD i = 0; i < ha->dwFileTableSize; i++)
+ {
+ bNeedHiBlockTable = (pFileEntry->ByteOffset >> 32) ? true : false;
+ pBlock->dwFilePos = (DWORD)pFileEntry->ByteOffset;
+ pBlock->dwFSize = pFileEntry->dwFileSize;
+ pBlock->dwCSize = pFileEntry->dwCmpSize;
+ pBlock->dwFlags = pFileEntry->dwFlags;
+
+ pFileEntry++;
+ pBlock++;
+ }
+
+ // Give the size to the caller
+ if(pcbTableSize != NULL)
+ *pcbTableSize = (ULONGLONG)BlockTableSize;
+
+ if(pbNeedHiBlockTable != NULL)
+ *pbNeedHiBlockTable = bNeedHiBlockTable;
+ }
+
+ return pBlockTable;
+}
+
+static USHORT * TranslateHiBlockTable(
+ TMPQArchive * ha,
+ ULONGLONG * pcbTableSize)
+{
+ TFileEntry * pFileEntry = ha->pFileTable;
+ USHORT * pHiBlockTable;
+ USHORT * pHiBlock;
+ size_t HiBlockTableSize;
+
+ // Allocate copy of the hash table
+ pHiBlockTable = pHiBlock = STORM_ALLOC(USHORT, ha->dwFileTableSize);
+ if(pHiBlockTable != NULL)
+ {
+ // Copy the block table
+ HiBlockTableSize = sizeof(USHORT) * ha->dwFileTableSize;
+ for(DWORD i = 0; i < ha->dwFileTableSize; i++)
+ pHiBlock[i] = (USHORT)(pFileEntry[i].ByteOffset >> 0x20);
+
+ // Give the size to the caller
+ if(pcbTableSize != NULL)
+ *pcbTableSize = (ULONGLONG)HiBlockTableSize;
+ }
+
+ return pHiBlockTable;
+}
+
+//-----------------------------------------------------------------------------
+// General EXT table functions
+
+TMPQExtTable * LoadExtTable(
+ TMPQArchive * ha,
+ ULONGLONG ByteOffset,
+ size_t Size,
+ DWORD dwSignature,
+ DWORD dwKey)
+{
+ TMPQExtTable * pCompressed = NULL; // Compressed table
+ TMPQExtTable * pExtTable = NULL; // Uncompressed table
+
+ // Do nothing if the size is zero
+ if(ByteOffset != 0 && Size != 0)
+ {
+ // Allocate size for the compressed table
+ pExtTable = (TMPQExtTable *)STORM_ALLOC(BYTE, Size);
+ if(pExtTable != NULL)
+ {
+ // Load the table from the MPQ
+ ByteOffset += ha->MpqPos;
+ if(!FileStream_Read(ha->pStream, &ByteOffset, pExtTable, (DWORD)Size))
+ {
+ STORM_FREE(pExtTable);
+ return NULL;
+ }
+
+ // Swap the ext table header
+ BSWAP_ARRAY32_UNSIGNED(pExtTable, sizeof(TMPQExtTable));
+ if(pExtTable->dwSignature != dwSignature)
+ {
+ STORM_FREE(pExtTable);
+ return NULL;
+ }
+
+ // Decrypt the block
+ BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize);
+ DecryptMpqBlock(pExtTable + 1, (DWORD)(Size - sizeof(TMPQExtTable)), dwKey);
+ BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize);
+
+ // If the table is compressed, decompress it
+ if((pExtTable->dwDataSize + sizeof(TMPQExtTable)) > Size)
+ {
+ pCompressed = pExtTable;
+ pExtTable = (TMPQExtTable *)STORM_ALLOC(BYTE, sizeof(TMPQExtTable) + pCompressed->dwDataSize);
+ if(pExtTable != NULL)
+ {
+ int cbOutBuffer = (int)pCompressed->dwDataSize;
+ int cbInBuffer = (int)Size;
+
+ // Decompress the extended table
+ pExtTable->dwSignature = pCompressed->dwSignature;
+ pExtTable->dwVersion = pCompressed->dwVersion;
+ pExtTable->dwDataSize = pCompressed->dwDataSize;
+ if(!SCompDecompress2((char *)(pExtTable + 1), &cbOutBuffer, (char *)(pCompressed + 1), cbInBuffer))
+ {
+ STORM_FREE(pExtTable);
+ pExtTable = NULL;
+ }
+ }
+
+ // Free the compressed block
+ STORM_FREE(pCompressed);
+ }
+ }
+ }
+
+ // Return the decompressed table to the caller
+ return pExtTable;
+}
+
+// Used in MPQ Editor
+void FreeMpqBuffer(void * pvBuffer)
+{
+ STORM_FREE(pvBuffer);
+}
+
+static int SaveMpqTable(
+ TMPQArchive * ha,
+ void * pMpqTable,
+ ULONGLONG ByteOffset,
+ size_t Size,
+ unsigned char * md5,
+ DWORD dwKey,
+ bool bCompress)
+{
+ ULONGLONG FileOffset;
+ void * pCompressed = NULL;
+ int nError = ERROR_SUCCESS;
+
+ // Do we have to compress the table?
+ if(bCompress)
+ {
+ int cbOutBuffer = (int)Size;
+ int cbInBuffer = (int)Size;
+
+ // Allocate extra space for compressed table
+ pCompressed = STORM_ALLOC(BYTE, Size);
+ if(pCompressed == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Compress the table
+ SCompCompress((char *)pCompressed, &cbOutBuffer, (char *)pMpqTable, cbInBuffer, MPQ_COMPRESSION_ZLIB, 0, 0);
+
+ // If the compression failed, revert it. Otherwise, swap the tables
+ if(cbOutBuffer >= cbInBuffer)
+ {
+ STORM_FREE(pCompressed);
+ pCompressed = NULL;
+ }
+ else
+ {
+ pMpqTable = pCompressed;
+ }
+ }
+
+ // Encrypt the table
+ if(dwKey != 0)
+ {
+ BSWAP_ARRAY32_UNSIGNED(pMpqTable, Size);
+ EncryptMpqBlock(pMpqTable, (DWORD)Size, dwKey);
+ BSWAP_ARRAY32_UNSIGNED(pMpqTable, Size);
+ }
+
+ // Calculate the MD5
+ if(md5 != NULL)
+ {
+ CalculateDataBlockHash(pMpqTable, (DWORD)Size, md5);
+ }
+
+ // Save the table to the MPQ
+ BSWAP_ARRAY32_UNSIGNED(pMpqTable, Size);
+ FileOffset = ha->MpqPos + ByteOffset;
+ if(!FileStream_Write(ha->pStream, &FileOffset, pMpqTable, (DWORD)Size))
+ nError = GetLastError();
+
+ // Free the compressed table, if any
+ if(pCompressed != NULL)
+ STORM_FREE(pCompressed);
+ return nError;
+}
+
+static int SaveExtTable(
+ TMPQArchive * ha,
+ TMPQExtTable * pExtTable,
+ ULONGLONG ByteOffset,
+ DWORD dwTableSize,
+ unsigned char * md5,
+ DWORD dwKey,
+ bool bCompress,
+ LPDWORD pcbTotalSize)
+{
+ ULONGLONG FileOffset;
+ TMPQExtTable * pCompressed = NULL;
+ DWORD cbTotalSize = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Do we have to compress the table?
+ if(bCompress)
+ {
+ int cbOutBuffer = (int)dwTableSize;
+ int cbInBuffer = (int)dwTableSize;
+
+ // Allocate extra space for compressed table
+ pCompressed = (TMPQExtTable *)STORM_ALLOC(BYTE, dwTableSize);
+ if(pCompressed == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Compress the table
+ pCompressed->dwSignature = pExtTable->dwSignature;
+ pCompressed->dwVersion = pExtTable->dwVersion;
+ pCompressed->dwDataSize = pExtTable->dwDataSize;
+ SCompCompress((char *)(pCompressed + 1), &cbOutBuffer, (char *)(pExtTable + 1), cbInBuffer, MPQ_COMPRESSION_ZLIB, 0, 0);
+
+ // If the compression failed, revert it. Otherwise, swap the tables
+ if(cbOutBuffer >= cbInBuffer)
+ {
+ STORM_FREE(pCompressed);
+ pCompressed = NULL;
+ }
+ else
+ {
+ pExtTable = pCompressed;
+ }
+ }
+
+ // Encrypt the table
+ if(dwKey != 0)
+ {
+ BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize);
+ EncryptMpqBlock(pExtTable + 1, (DWORD)(dwTableSize - sizeof(TMPQExtTable)), dwKey);
+ BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize);
+ }
+
+ // Calculate the MD5 of the table after
+ if(md5 != NULL)
+ {
+ CalculateDataBlockHash(pExtTable, dwTableSize, md5);
+ }
+
+ // Save the table to the MPQ
+ FileOffset = ha->MpqPos + ByteOffset;
+ if(FileStream_Write(ha->pStream, &FileOffset, pExtTable, dwTableSize))
+ cbTotalSize += dwTableSize;
+ else
+ nError = GetLastError();
+
+ // We have to write raw data MD5
+ if(nError == ERROR_SUCCESS && ha->pHeader->dwRawChunkSize != 0)
+ {
+ nError = WriteMemDataMD5(ha->pStream,
+ FileOffset,
+ pExtTable,
+ dwTableSize,
+ ha->pHeader->dwRawChunkSize,
+ &cbTotalSize);
+ }
+
+ // Give the total written size, if needed
+ if(pcbTotalSize != NULL)
+ *pcbTotalSize = cbTotalSize;
+
+ // Free the compressed table, if any
+ if(pCompressed != NULL)
+ STORM_FREE(pCompressed);
+ return nError;
+}
+
+//-----------------------------------------------------------------------------
+// Support for HET table
+
+static void CreateHetHeader(
+ TMPQHetTable * pHetTable,
+ PHET_TABLE_HEADER pHetHeader)
+{
+ // Fill the BET header
+ pHetHeader->dwMaxFileCount = pHetTable->dwMaxFileCount;
+ pHetHeader->dwHashTableSize = pHetTable->dwHashTableSize;
+ pHetHeader->dwHashEntrySize = pHetTable->dwHashBitSize;
+ pHetHeader->dwIndexSizeTotal = GetNecessaryBitCount(pHetTable->dwMaxFileCount);
+ pHetHeader->dwIndexSizeExtra = 0;
+ pHetHeader->dwIndexSize = pHetHeader->dwIndexSizeTotal;
+ pHetHeader->dwIndexTableSize = ((pHetHeader->dwIndexSizeTotal * pHetTable->dwHashTableSize) + 7) / 8;
+
+ // Calculate the total size needed for holding HET table
+ pHetHeader->dwTableSize = sizeof(HET_TABLE_HEADER) +
+ pHetHeader->dwHashTableSize +
+ pHetHeader->dwIndexTableSize;
+}
+
+TMPQHetTable * CreateHetTable(DWORD dwMaxFileCount, DWORD dwHashBitSize, bool bCreateEmpty)
+{
+ TMPQHetTable * pHetTable;
+
+ pHetTable = STORM_ALLOC(TMPQHetTable, 1);
+ if(pHetTable != NULL)
+ {
+ pHetTable->dwIndexSizeTotal = 0;
+ pHetTable->dwIndexSizeExtra = 0;
+ pHetTable->dwIndexSize = pHetTable->dwIndexSizeTotal;
+ pHetTable->dwMaxFileCount = dwMaxFileCount;
+ pHetTable->dwHashTableSize = (dwMaxFileCount * 4 / 3);
+ pHetTable->dwHashBitSize = dwHashBitSize;
+
+ // Size of one index is calculated from max file count
+ pHetTable->dwIndexSizeTotal = GetNecessaryBitCount(dwMaxFileCount);
+ pHetTable->dwIndexSizeExtra = 0;
+ pHetTable->dwIndexSize = pHetTable->dwIndexSizeTotal;
+
+ // Allocate hash table
+ pHetTable->pHetHashes = STORM_ALLOC(BYTE, pHetTable->dwHashTableSize);
+ memset(pHetTable->pHetHashes, 0, pHetTable->dwHashTableSize);
+
+ // If we shall create empty HET table, we have to allocate empty block index table as well
+ if(bCreateEmpty)
+ pHetTable->pBetIndexes = CreateBitArray(pHetTable->dwHashTableSize * pHetTable->dwIndexSizeTotal, 0xFF);
+
+ // Calculate masks
+ pHetTable->AndMask64 = 0;
+ if(dwHashBitSize != 0x40)
+ pHetTable->AndMask64 = (ULONGLONG)1 << dwHashBitSize;
+ pHetTable->AndMask64--;
+
+ pHetTable->OrMask64 = (ULONGLONG)1 << (dwHashBitSize - 1);
+ }
+
+ return pHetTable;
+}
+
+static TMPQHetTable * TranslateHetTable(TMPQExtTable * pExtTable)
+{
+ HET_TABLE_HEADER HetHeader;
+ TMPQHetTable * pHetTable = NULL;
+ LPBYTE pbSrcData = (LPBYTE)(pExtTable + 1);
+
+ // Sanity check
+ assert(pExtTable->dwSignature == HET_TABLE_SIGNATURE);
+ assert(pExtTable->dwVersion == 1);
+
+ // Verify size of the HET table
+ if(pExtTable != NULL && pExtTable->dwDataSize >= sizeof(HET_TABLE_HEADER))
+ {
+ // Copy the table header in order to have it aligned and swapped
+ memcpy(&HetHeader, pbSrcData, sizeof(HET_TABLE_HEADER));
+ BSWAP_ARRAY32_UNSIGNED(&HetHeader, sizeof(HET_TABLE_HEADER));
+ pbSrcData += sizeof(HET_TABLE_HEADER);
+
+ // Verify the size of the table in the header
+ if(HetHeader.dwTableSize == pExtTable->dwDataSize)
+ {
+ // Create translated table
+ pHetTable = CreateHetTable(HetHeader.dwMaxFileCount, HetHeader.dwHashEntrySize, false);
+ if(pHetTable != NULL)
+ {
+ // Copy the hash table size, index size and extra bits from the HET header
+ pHetTable->dwHashTableSize = HetHeader.dwHashTableSize;
+ pHetTable->dwIndexSizeTotal = HetHeader.dwIndexSizeTotal;
+ pHetTable->dwIndexSizeExtra = HetHeader.dwIndexSizeExtra;
+
+ // Fill the hash table
+ if(pHetTable->pHetHashes != NULL)
+ memcpy(pHetTable->pHetHashes, pbSrcData, pHetTable->dwHashTableSize);
+ pbSrcData += pHetTable->dwHashTableSize;
+
+ // Copy the block index table
+ pHetTable->pBetIndexes = CreateBitArray(HetHeader.dwIndexTableSize * 8, 0xFF);
+ if(pHetTable->pBetIndexes != NULL)
+ memcpy(pHetTable->pBetIndexes->Elements, pbSrcData, HetHeader.dwIndexTableSize);
+ pbSrcData += HetHeader.dwIndexTableSize;
+ }
+ }
+ }
+
+ return pHetTable;
+}
+
+static TMPQExtTable * TranslateHetTable(TMPQHetTable * pHetTable, ULONGLONG * pcbHetTable)
+{
+ TMPQExtTable * pExtTable = NULL;
+ HET_TABLE_HEADER HetHeader;
+ LPBYTE pbLinearTable = NULL;
+ LPBYTE pbTrgData;
+ size_t HetTableSize;
+
+ // Prepare header of the HET table
+ CreateHetHeader(pHetTable, &HetHeader);
+
+ // Calculate the total size needed for holding the encrypted HET table
+ HetTableSize = HetHeader.dwTableSize;
+
+ // Allocate space for the linear table
+ pbLinearTable = STORM_ALLOC(BYTE, sizeof(TMPQExtTable) + HetTableSize);
+ if(pbLinearTable != NULL)
+ {
+ // Create the common ext table header
+ pExtTable = (TMPQExtTable *)pbLinearTable;
+ pExtTable->dwSignature = HET_TABLE_SIGNATURE;
+ pExtTable->dwVersion = 1;
+ pExtTable->dwDataSize = (DWORD)HetTableSize;
+ pbTrgData = (LPBYTE)(pExtTable + 1);
+
+ // Copy the HET table header
+ memcpy(pbTrgData, &HetHeader, sizeof(HET_TABLE_HEADER));
+ BSWAP_ARRAY32_UNSIGNED(pbTrgData, sizeof(HET_TABLE_HEADER));
+ pbTrgData += sizeof(HET_TABLE_HEADER);
+
+ // Copy the array of HET hashes
+ memcpy(pbTrgData, pHetTable->pHetHashes, pHetTable->dwHashTableSize);
+ pbTrgData += pHetTable->dwHashTableSize;
+
+ // Copy the bit array of BET indexes
+ memcpy(pbTrgData, pHetTable->pBetIndexes->Elements, HetHeader.dwIndexTableSize);
+
+ // Calculate the total size of the table, including the TMPQExtTable
+ if(pcbHetTable != NULL)
+ {
+ *pcbHetTable = (ULONGLONG)(sizeof(TMPQExtTable) + HetTableSize);
+ }
+ }
+
+ return pExtTable;
+}
+
+DWORD GetFileIndex_Het(TMPQArchive * ha, const char * szFileName)
+{
+ TMPQHetTable * pHetTable = ha->pHetTable;
+ ULONGLONG FileNameHash;
+ ULONGLONG AndMask64;
+ ULONGLONG OrMask64;
+ ULONGLONG BetHash;
+ DWORD StartIndex;
+ DWORD Index;
+ BYTE HetHash; // Upper 8 bits of the masked file name hash
+
+ // Do nothing if the MPQ has no HET table
+ assert(ha->pHetTable != NULL);
+
+ // Calculate 64-bit hash of the file name
+ AndMask64 = pHetTable->AndMask64;
+ OrMask64 = pHetTable->OrMask64;
+ FileNameHash = (HashStringJenkins(szFileName) & AndMask64) | OrMask64;
+
+ // Split the file name hash into two parts:
+ // Part 1: The highest 8 bits of the name hash
+ // Part 2: The rest of the name hash (without the highest 8 bits)
+ HetHash = (BYTE)(FileNameHash >> (pHetTable->dwHashBitSize - 8));
+ BetHash = FileNameHash & (AndMask64 >> 0x08);
+
+ // Calculate the starting index to the hash table
+ StartIndex = Index = (DWORD)(FileNameHash % pHetTable->dwHashTableSize);
+
+ // Go through HET table until we find a terminator
+ while(pHetTable->pHetHashes[Index] != HET_ENTRY_FREE)
+ {
+ // Did we find match ?
+ if(pHetTable->pHetHashes[Index] == HetHash)
+ {
+ DWORD dwFileIndex = 0;
+
+ // Get the index of the BetHash
+ pHetTable->pBetIndexes->GetBits(pHetTable->dwIndexSizeTotal * Index,
+ pHetTable->dwIndexSize,
+ &dwFileIndex,
+ 4);
+
+ //
+ // TODO: This condition only happens when we are opening a MPQ
+ // where some files were deleted by StormLib. Perhaps
+ // we should not allow shrinking of the file table in MPQs v 4.0?
+ // assert(dwFileIndex <= ha->dwFileTableSize);
+ //
+
+ // Verify the BetHash against the entry in the table of BET hashes
+ if(dwFileIndex <= ha->dwFileTableSize && ha->pFileTable[dwFileIndex].BetHash == BetHash)
+ return dwFileIndex;
+ }
+
+ // Move to the next entry in the primary search table
+ // If we came to the start index again, we are done
+ Index = (Index + 1) % pHetTable->dwHashTableSize;
+ if(Index == StartIndex)
+ break;
+ }
+
+ // File not found
+ return HASH_ENTRY_FREE;
+}
+
+DWORD AllocateHetEntry(
+ TMPQArchive * ha,
+ TFileEntry * pFileEntry)
+{
+ TMPQHetTable * pHetTable = ha->pHetTable;
+ ULONGLONG FileNameHash;
+ ULONGLONG AndMask64;
+ ULONGLONG OrMask64;
+ ULONGLONG BetHash;
+ DWORD FreeHetIndex = HASH_ENTRY_FREE;
+ DWORD dwFileIndex;
+ DWORD StartIndex;
+ DWORD Index;
+ BYTE HetHash; // Upper 8 bits of the masked file name hash
+
+ // Do nothing if the MPQ has no HET table
+ assert(ha->pHetTable != NULL);
+
+ // Calculate 64-bit hash of the file name
+ AndMask64 = pHetTable->AndMask64;
+ OrMask64 = pHetTable->OrMask64;
+ FileNameHash = (HashStringJenkins(pFileEntry->szFileName) & AndMask64) | OrMask64;
+
+ // Calculate the starting index to the hash table
+ StartIndex = Index = (DWORD)(FileNameHash % pHetTable->dwHashTableSize);
+
+ // Split the file name hash into two parts:
+ // Part 1: The highest 8 bits of the name hash
+ // Part 2: The rest of the name hash (without the highest 8 bits)
+ HetHash = (BYTE)(FileNameHash >> (pHetTable->dwHashBitSize - 8));
+ BetHash = FileNameHash & (AndMask64 >> 0x08);
+
+ // Go through HET table until we find a terminator
+ for(;;)
+ {
+ // Check for entries that might have been deleted
+ if(pHetTable->pHetHashes[Index] == HET_ENTRY_DELETED)
+ {
+ DWORD dwInvalidBetIndex = (1 << pHetTable->dwIndexSizeTotal) - 1;
+ DWORD dwBetIndex = 0;
+
+ // Verify the BET index. If it's really free, we can use it
+ dwFileIndex = (DWORD)(pFileEntry - ha->pFileTable);
+ pHetTable->pBetIndexes->GetBits(pHetTable->dwIndexSizeTotal * Index,
+ pHetTable->dwIndexSize,
+ &dwBetIndex,
+ 4);
+
+ if(dwBetIndex == dwInvalidBetIndex)
+ {
+ FreeHetIndex = Index;
+ break;
+ }
+ }
+
+ // Is that entry free ?
+ if(pHetTable->pHetHashes[Index] == HET_ENTRY_FREE)
+ {
+ FreeHetIndex = Index;
+ break;
+ }
+
+ // Move to the next entry in the primary search table
+ // If we came to the start index again, we are done
+ Index = (Index + 1) % pHetTable->dwHashTableSize;
+ if(Index == StartIndex)
+ return HASH_ENTRY_FREE;
+ }
+
+ // Fill the HET table entry
+ dwFileIndex = (DWORD)(pFileEntry - ha->pFileTable);
+ pHetTable->pHetHashes[FreeHetIndex] = HetHash;
+ pHetTable->pBetIndexes->SetBits(pHetTable->dwIndexSizeTotal * FreeHetIndex,
+ pHetTable->dwIndexSize,
+ &dwFileIndex,
+ 4);
+ // Fill the file entry
+ pFileEntry->BetHash = BetHash;
+ pFileEntry->dwHetIndex = FreeHetIndex;
+ return FreeHetIndex;
+}
+
+void FreeHetTable(TMPQHetTable * pHetTable)
+{
+ if(pHetTable != NULL)
+ {
+ if(pHetTable->pHetHashes != NULL)
+ STORM_FREE(pHetTable->pHetHashes);
+ if(pHetTable->pBetIndexes != NULL)
+ STORM_FREE(pHetTable->pBetIndexes);
+
+ STORM_FREE(pHetTable);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Support for BET table
+
+static void CreateBetHeader(
+ TMPQArchive * ha,
+ PBET_TABLE_HEADER pBetHeader)
+{
+ TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
+ TFileEntry * pFileEntry;
+ ULONGLONG MaxByteOffset = 0;
+ DWORD FlagArray[MAX_FLAG_INDEX];
+ DWORD dwMaxFlagIndex = 0;
+ DWORD dwMaxFileSize = 0;
+ DWORD dwMaxCmpSize = 0;
+ DWORD dwFlagIndex;
+
+ // Initialize array of flag combinations
+ InitFileFlagArray(FlagArray);
+
+ // Get the maximum values for the BET table
+ for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
+ {
+ // Highest file position in the MPQ
+ if(pFileEntry->ByteOffset > MaxByteOffset)
+ MaxByteOffset = pFileEntry->ByteOffset;
+
+ // Biggest file size
+ if(pFileEntry->dwFileSize > dwMaxFileSize)
+ dwMaxFileSize = pFileEntry->dwFileSize;
+
+ // Biggest compressed size
+ if(pFileEntry->dwCmpSize > dwMaxCmpSize)
+ dwMaxCmpSize = pFileEntry->dwCmpSize;
+
+ // Check if this flag was there before
+ dwFlagIndex = GetFileFlagIndex(FlagArray, pFileEntry->dwFlags);
+ if(dwFlagIndex > dwMaxFlagIndex)
+ dwMaxFlagIndex = dwFlagIndex;
+ }
+
+ // Now save bit count for every piece of file information
+ pBetHeader->dwBitIndex_FilePos = 0;
+ pBetHeader->dwBitCount_FilePos = GetNecessaryBitCount(MaxByteOffset);
+
+ pBetHeader->dwBitIndex_FileSize = pBetHeader->dwBitIndex_FilePos + pBetHeader->dwBitCount_FilePos;
+ pBetHeader->dwBitCount_FileSize = GetNecessaryBitCount(dwMaxFileSize);
+
+ pBetHeader->dwBitIndex_CmpSize = pBetHeader->dwBitIndex_FileSize + pBetHeader->dwBitCount_FileSize;
+ pBetHeader->dwBitCount_CmpSize = GetNecessaryBitCount(dwMaxCmpSize);
+
+ pBetHeader->dwBitIndex_FlagIndex = pBetHeader->dwBitIndex_CmpSize + pBetHeader->dwBitCount_CmpSize;
+ pBetHeader->dwBitCount_FlagIndex = GetNecessaryBitCount(dwMaxFlagIndex + 1);
+
+ pBetHeader->dwBitIndex_Unknown = pBetHeader->dwBitIndex_FlagIndex + pBetHeader->dwBitCount_FlagIndex;
+ pBetHeader->dwBitCount_Unknown = 0;
+
+ // Calculate the total size of one entry
+ pBetHeader->dwTableEntrySize = pBetHeader->dwBitCount_FilePos +
+ pBetHeader->dwBitCount_FileSize +
+ pBetHeader->dwBitCount_CmpSize +
+ pBetHeader->dwBitCount_FlagIndex +
+ pBetHeader->dwBitCount_Unknown;
+
+ // Save the file count and flag count
+ pBetHeader->dwFileCount = ha->dwFileTableSize;
+ pBetHeader->dwFlagCount = dwMaxFlagIndex + 1;
+ pBetHeader->dwUnknown08 = 0x10;
+
+ // Save the total size of the BET hash
+ pBetHeader->dwBetHashSizeTotal = ha->pHetTable->dwHashBitSize - 0x08;
+ pBetHeader->dwBetHashSizeExtra = 0;
+ pBetHeader->dwBetHashSize = pBetHeader->dwBetHashSizeTotal;
+ pBetHeader->dwBetHashArraySize = ((pBetHeader->dwBetHashSizeTotal * pBetHeader->dwFileCount) + 7) / 8;
+
+ // Save the total table size
+ pBetHeader->dwTableSize = sizeof(BET_TABLE_HEADER) +
+ pBetHeader->dwFlagCount * sizeof(DWORD) +
+ ((pBetHeader->dwTableEntrySize * pBetHeader->dwFileCount) + 7) / 8 +
+ pBetHeader->dwBetHashArraySize;
+}
+
+TMPQBetTable * CreateBetTable(DWORD dwFileCount)
+{
+ TMPQBetTable * pBetTable;
+
+ // Allocate BET table
+ pBetTable = STORM_ALLOC(TMPQBetTable, 1);
+ if(pBetTable != NULL)
+ {
+ memset(pBetTable, 0, sizeof(TMPQBetTable));
+ pBetTable->dwFileCount = dwFileCount;
+ }
+
+ return pBetTable;
+}
+
+static TMPQBetTable * TranslateBetTable(
+ TMPQArchive * ha,
+ TMPQExtTable * pExtTable)
+{
+ BET_TABLE_HEADER BetHeader;
+ TMPQBetTable * pBetTable = NULL;
+ LPBYTE pbSrcData = (LPBYTE)(pExtTable + 1);
+ DWORD LengthInBytes;
+
+ // Sanity check
+ assert(pExtTable->dwSignature == BET_TABLE_SIGNATURE);
+ assert(pExtTable->dwVersion == 1);
+ assert(ha->pHetTable != NULL);
+ ha = ha;
+
+ // Verify size of the HET table
+ if(pExtTable != NULL && pExtTable->dwDataSize >= sizeof(BET_TABLE_HEADER))
+ {
+ // Copy the table header in order to have it aligned and swapped
+ memcpy(&BetHeader, pbSrcData, sizeof(BET_TABLE_HEADER));
+ BSWAP_ARRAY32_UNSIGNED(&BetHeader, sizeof(BET_TABLE_HEADER));
+ pbSrcData += sizeof(BET_TABLE_HEADER);
+
+ // Some MPQs affected by a bug in StormLib have pBetTable->dwFileCount
+ // greater than ha->dwMaxFileCount
+ if(BetHeader.dwFileCount > ha->dwMaxFileCount)
+ return NULL;
+
+ // Verify the size of the table in the header
+ if(BetHeader.dwTableSize == pExtTable->dwDataSize)
+ {
+ // Create translated table
+ pBetTable = CreateBetTable(BetHeader.dwFileCount);
+ if(pBetTable != NULL)
+ {
+ // Copy the variables from the header to the BetTable
+ pBetTable->dwTableEntrySize = BetHeader.dwTableEntrySize;
+ pBetTable->dwBitIndex_FilePos = BetHeader.dwBitIndex_FilePos;
+ pBetTable->dwBitIndex_FileSize = BetHeader.dwBitIndex_FileSize;
+ pBetTable->dwBitIndex_CmpSize = BetHeader.dwBitIndex_CmpSize;
+ pBetTable->dwBitIndex_FlagIndex = BetHeader.dwBitIndex_FlagIndex;
+ pBetTable->dwBitIndex_Unknown = BetHeader.dwBitIndex_Unknown;
+ pBetTable->dwBitCount_FilePos = BetHeader.dwBitCount_FilePos;
+ pBetTable->dwBitCount_FileSize = BetHeader.dwBitCount_FileSize;
+ pBetTable->dwBitCount_CmpSize = BetHeader.dwBitCount_CmpSize;
+ pBetTable->dwBitCount_FlagIndex = BetHeader.dwBitCount_FlagIndex;
+ pBetTable->dwBitCount_Unknown = BetHeader.dwBitCount_Unknown;
+
+ // Since we don't know what the "unknown" is, we'll assert when it's nonzero
+ assert(pBetTable->dwBitCount_Unknown == 0);
+
+ // Allocate array for flags
+ if(BetHeader.dwFlagCount != 0)
+ {
+ // Allocate array for file flags and load it
+ pBetTable->pFileFlags = STORM_ALLOC(DWORD, BetHeader.dwFlagCount);
+ if(pBetTable->pFileFlags != NULL)
+ {
+ LengthInBytes = BetHeader.dwFlagCount * sizeof(DWORD);
+ memcpy(pBetTable->pFileFlags, pbSrcData, LengthInBytes);
+ BSWAP_ARRAY32_UNSIGNED(pBetTable->pFileFlags, LengthInBytes);
+ pbSrcData += LengthInBytes;
+ }
+
+ // Save the number of flags
+ pBetTable->dwFlagCount = BetHeader.dwFlagCount;
+ }
+
+ // Load the bit-based file table
+ pBetTable->pFileTable = CreateBitArray(pBetTable->dwTableEntrySize * BetHeader.dwFileCount, 0);
+ LengthInBytes = (pBetTable->pFileTable->NumberOfBits + 7) / 8;
+ if(pBetTable->pFileTable != NULL)
+ memcpy(pBetTable->pFileTable->Elements, pbSrcData, LengthInBytes);
+ pbSrcData += LengthInBytes;
+
+ // Fill the sizes of BET hash
+ pBetTable->dwBetHashSizeTotal = BetHeader.dwBetHashSizeTotal;
+ pBetTable->dwBetHashSizeExtra = BetHeader.dwBetHashSizeExtra;
+ pBetTable->dwBetHashSize = BetHeader.dwBetHashSize;
+
+ // Create and load the array of BET hashes
+ pBetTable->pBetHashes = CreateBitArray(pBetTable->dwBetHashSizeTotal * BetHeader.dwFileCount, 0);
+ LengthInBytes = (pBetTable->pBetHashes->NumberOfBits + 7) / 8;
+ if(pBetTable->pBetHashes != NULL)
+ memcpy(pBetTable->pBetHashes->Elements, pbSrcData, LengthInBytes);
+ pbSrcData += BetHeader.dwBetHashArraySize;
+
+ // Dump both tables
+// DumpHetAndBetTable(ha->pHetTable, pBetTable);
+ }
+ }
+ }
+
+ return pBetTable;
+}
+
+TMPQExtTable * TranslateBetTable(
+ TMPQArchive * ha,
+ ULONGLONG * pcbBetTable)
+{
+ TMPQExtTable * pExtTable = NULL;
+ BET_TABLE_HEADER BetHeader;
+ TBitArray * pBitArray = NULL;
+ LPBYTE pbLinearTable = NULL;
+ LPBYTE pbTrgData;
+ size_t BetTableSize;
+ DWORD LengthInBytes;
+ DWORD FlagArray[MAX_FLAG_INDEX];
+ DWORD i;
+
+ // Calculate the bit sizes of various entries
+ InitFileFlagArray(FlagArray);
+ CreateBetHeader(ha, &BetHeader);
+
+ // Calculate the size of the BET table
+ BetTableSize = sizeof(BET_TABLE_HEADER) +
+ BetHeader.dwFlagCount * sizeof(DWORD) +
+ ((BetHeader.dwTableEntrySize * BetHeader.dwFileCount) + 7) / 8 +
+ BetHeader.dwBetHashArraySize;
+
+ // Allocate space
+ pbLinearTable = STORM_ALLOC(BYTE, sizeof(TMPQExtTable) + BetTableSize);
+ if(pbLinearTable != NULL)
+ {
+ // Create the common ext table header
+ pExtTable = (TMPQExtTable *)pbLinearTable;
+ pExtTable->dwSignature = BET_TABLE_SIGNATURE;
+ pExtTable->dwVersion = 1;
+ pExtTable->dwDataSize = (DWORD)BetTableSize;
+ pbTrgData = (LPBYTE)(pExtTable + 1);
+
+ // Copy the BET table header
+ memcpy(pbTrgData, &BetHeader, sizeof(BET_TABLE_HEADER));
+ BSWAP_ARRAY32_UNSIGNED(pbTrgData, sizeof(BET_TABLE_HEADER));
+ pbTrgData += sizeof(BET_TABLE_HEADER);
+
+ // Save the bit-based block table
+ pBitArray = CreateBitArray(BetHeader.dwFileCount * BetHeader.dwTableEntrySize, 0);
+ if(pBitArray != NULL)
+ {
+ TFileEntry * pFileEntry = ha->pFileTable;
+ DWORD dwFlagIndex = 0;
+ DWORD nBitOffset = 0;
+
+ // Construct the array of flag values and bit-based file table
+ for(i = 0; i < BetHeader.dwFileCount; i++, pFileEntry++)
+ {
+ //
+ // Note: Blizzard MPQs contain valid values even for non-existant files
+ // (FilePos, FileSize, CmpSize and FlagIndex)
+ // Note: If flags is zero, it must be in the flag table too !!!
+ //
+
+ // Save the byte offset
+ pBitArray->SetBits(nBitOffset + BetHeader.dwBitIndex_FilePos,
+ BetHeader.dwBitCount_FilePos,
+ &pFileEntry->ByteOffset,
+ 8);
+ pBitArray->SetBits(nBitOffset + BetHeader.dwBitIndex_FileSize,
+ BetHeader.dwBitCount_FileSize,
+ &pFileEntry->dwFileSize,
+ 4);
+ pBitArray->SetBits(nBitOffset + BetHeader.dwBitIndex_CmpSize,
+ BetHeader.dwBitCount_CmpSize,
+ &pFileEntry->dwCmpSize,
+ 4);
+
+ // Save the flag index
+ dwFlagIndex = GetFileFlagIndex(FlagArray, pFileEntry->dwFlags);
+ pBitArray->SetBits(nBitOffset + BetHeader.dwBitIndex_FlagIndex,
+ BetHeader.dwBitCount_FlagIndex,
+ &dwFlagIndex,
+ 4);
+
+ // Move the bit offset
+ nBitOffset += BetHeader.dwTableEntrySize;
+ }
+
+ // Write the array of flags
+ LengthInBytes = BetHeader.dwFlagCount * sizeof(DWORD);
+ memcpy(pbTrgData, FlagArray, LengthInBytes);
+ BSWAP_ARRAY32_UNSIGNED(pbTrgData, LengthInBytes);
+ pbTrgData += LengthInBytes;
+
+ // Write the bit-based block table
+ LengthInBytes = (pBitArray->NumberOfBits + 7) / 8;
+ memcpy(pbTrgData, pBitArray->Elements, LengthInBytes);
+ pbTrgData += LengthInBytes;
+
+ // Free the bit array
+ STORM_FREE(pBitArray);
+ }
+
+ // Create bit array for BET hashes
+ pBitArray = CreateBitArray(BetHeader.dwBetHashSizeTotal * BetHeader.dwFileCount, 0);
+ if(pBitArray != NULL)
+ {
+ TFileEntry * pFileEntry = ha->pFileTable;
+ ULONGLONG AndMask64 = ha->pHetTable->AndMask64;
+ ULONGLONG OrMask64 = ha->pHetTable->OrMask64;
+
+ for(i = 0; i < BetHeader.dwFileCount; i++)
+ {
+ ULONGLONG FileNameHash = 0;
+
+ // Calculate 64-bit hash of the file name
+ if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) && pFileEntry->szFileName != NULL)
+ {
+ FileNameHash = (HashStringJenkins(pFileEntry->szFileName) & AndMask64) | OrMask64;
+ FileNameHash = FileNameHash & (AndMask64 >> 0x08);
+ }
+
+ // Insert the name hash to the bit array
+ pBitArray->SetBits(BetHeader.dwBetHashSizeTotal * i,
+ BetHeader.dwBetHashSize,
+ &FileNameHash,
+ 8);
+
+ // Move to the next file entry
+ pFileEntry++;
+ }
+
+ // Write the array of BET hashes
+ LengthInBytes = (pBitArray->NumberOfBits + 7) / 8;
+ memcpy(pbTrgData, pBitArray->Elements, LengthInBytes);
+ pbTrgData += LengthInBytes;
+
+ // Free the bit array
+ STORM_FREE(pBitArray);
+ }
+
+ // Write the size of the BET table in the MPQ
+ if(pcbBetTable != NULL)
+ {
+ *pcbBetTable = (ULONGLONG)(sizeof(TMPQExtTable) + BetTableSize);
+ }
+ }
+
+ return pExtTable;
+}
+
+void FreeBetTable(TMPQBetTable * pBetTable)
+{
+ if(pBetTable != NULL)
+ {
+ if(pBetTable->pFileTable != NULL)
+ STORM_FREE(pBetTable->pFileTable);
+ if(pBetTable->pFileFlags != NULL)
+ STORM_FREE(pBetTable->pFileFlags);
+ if(pBetTable->pBetHashes != NULL)
+ STORM_FREE(pBetTable->pBetHashes);
+
+ STORM_FREE(pBetTable);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Support for file table
+
+TFileEntry * GetFileEntryAny(TMPQArchive * ha, const char * szFileName)
+{
+ TMPQHash * pHash;
+ DWORD dwFileIndex;
+
+ // If we have HET table in the MPQ, try to find the file in HET table
+ if(ha->pHetTable != NULL)
+ {
+ dwFileIndex = GetFileIndex_Het(ha, szFileName);
+ if(dwFileIndex != HASH_ENTRY_FREE)
+ return ha->pFileTable + dwFileIndex;
+ }
+
+ // Otherwise, perform the file search in the classic hash table
+ if(ha->pHashTable != NULL)
+ {
+ pHash = GetHashEntryAny(ha, szFileName);
+ if(pHash != NULL && pHash->dwBlockIndex < ha->dwFileTableSize)
+ return ha->pFileTable + pHash->dwBlockIndex;
+ }
+
+ // Not found
+ return NULL;
+}
+
+TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale)
+{
+ TMPQHash * pHash;
+ DWORD dwFileIndex;
+
+ // If we have HET table in the MPQ, try to find the file in HET table
+ if(ha->pHetTable != NULL)
+ {
+ dwFileIndex = GetFileIndex_Het(ha, szFileName);
+ if(dwFileIndex != HASH_ENTRY_FREE)
+ return ha->pFileTable + dwFileIndex;
+ }
+
+ // Otherwise, perform the file search in the classic hash table
+ if(ha->pHashTable != NULL)
+ {
+ pHash = GetHashEntryLocale(ha, szFileName, lcLocale);
+ if(pHash != NULL && pHash->dwBlockIndex < ha->dwFileTableSize)
+ return ha->pFileTable + pHash->dwBlockIndex;
+ }
+
+ // Not found
+ return NULL;
+}
+
+TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcLocale)
+{
+ TMPQHash * pHash;
+ DWORD dwFileIndex;
+
+ // If we have HET table in the MPQ, try to find the file in HET table
+ if(ha->pHetTable != NULL)
+ {
+ dwFileIndex = GetFileIndex_Het(ha, szFileName);
+ if(dwFileIndex != HASH_ENTRY_FREE)
+ return ha->pFileTable + dwFileIndex;
+ }
+
+ // Otherwise, perform the file search in the classic hash table
+ if(ha->pHashTable != NULL)
+ {
+ pHash = GetHashEntryExact(ha, szFileName, lcLocale);
+ if(pHash != NULL && pHash->dwBlockIndex < ha->dwFileTableSize)
+ return ha->pFileTable + pHash->dwBlockIndex;
+ }
+
+ // Not found
+ return NULL;
+}
+
+TFileEntry * GetFileEntryByIndex(TMPQArchive * ha, DWORD dwIndex)
+{
+ // For MPQs with classic hash table
+ if(dwIndex < ha->dwFileTableSize)
+ return ha->pFileTable + dwIndex;
+ return NULL;
+}
+
+void AllocateFileName(TFileEntry * pFileEntry, const char * szFileName)
+{
+ // Sanity check
+ assert(pFileEntry != NULL);
+
+ // If the file name is pseudo file name, free it at this point
+ if(IsPseudoFileName(pFileEntry->szFileName, NULL))
+ {
+ if(pFileEntry->szFileName != NULL)
+ STORM_FREE(pFileEntry->szFileName);
+ pFileEntry->szFileName = NULL;
+ }
+
+ // Only allocate new file name if it's not there yet
+ if(pFileEntry->szFileName == NULL)
+ {
+ pFileEntry->szFileName = STORM_ALLOC(char, strlen(szFileName) + 1);
+ if(pFileEntry->szFileName != NULL)
+ strcpy(pFileEntry->szFileName, szFileName);
+ }
+}
+
+
+// Finds a free file entry. Does NOT increment table size.
+TFileEntry * FindFreeFileEntry(TMPQArchive * ha)
+{
+ TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
+ TFileEntry * pFreeEntry = NULL;
+ TFileEntry * pFileEntry;
+
+ // Try to find a free entry
+ for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
+ {
+ // If that entry is free, we reuse it
+ if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0)
+ {
+ pFreeEntry = pFileEntry;
+ break;
+ }
+
+ //
+ // Note: Files with "delete marker" are not deleted.
+ // Don't consider them free entries
+ //
+ }
+
+ // Do we have a deleted entry?
+ if(pFreeEntry != NULL)
+ {
+ ClearFileEntry(ha, pFreeEntry);
+ return pFreeEntry;
+ }
+
+ // If no file entry within the existing file table is free,
+ // we try the reserve space after current file table
+ if(ha->dwFileTableSize < ha->dwMaxFileCount)
+ return ha->pFileTable + ha->dwFileTableSize;
+
+ // If we reached maximum file count, we cannot add more files to the MPQ
+ assert(ha->dwFileTableSize == ha->dwMaxFileCount);
+ return NULL;
+}
+
+
+TFileEntry * AllocateFileEntry(TMPQArchive * ha, const char * szFileName, LCID lcLocale)
+{
+ TFileEntry * pFileEntry = NULL;
+ TMPQHash * pHash;
+ DWORD dwHashIndex;
+ DWORD dwFileIndex;
+ bool bHashEntryExists = false;
+ bool bHetEntryExists = false;
+
+ // If the archive has classic hash table, we try to
+ // find the file in the hash table
+ if(ha->pHashTable != NULL)
+ {
+ // If the hash entry is already there, we reuse the file entry
+ pHash = GetHashEntryExact(ha, szFileName, lcLocale);
+ if(pHash != NULL)
+ {
+ pFileEntry = ha->pFileTable + pHash->dwBlockIndex;
+ bHashEntryExists = true;
+ }
+ }
+
+ // If the archive has HET table, try to use it for
+ // finding the file
+ if(ha->pHetTable != NULL)
+ {
+ dwFileIndex = GetFileIndex_Het(ha, szFileName);
+ if(dwFileIndex != HASH_ENTRY_FREE)
+ {
+ pFileEntry = ha->pFileTable + dwFileIndex;
+ bHetEntryExists = true;
+ }
+ }
+
+ // If still haven't found the file entry, we allocate new one
+ if(pFileEntry == NULL)
+ {
+ pFileEntry = FindFreeFileEntry(ha);
+ if(pFileEntry == NULL)
+ return NULL;
+ }
+
+ // Fill the rest of the file entry
+ pFileEntry->ByteOffset = 0;
+ pFileEntry->FileTime = 0;
+ pFileEntry->dwFileSize = 0;
+ pFileEntry->dwCmpSize = 0;
+ pFileEntry->dwFlags = 0;
+ pFileEntry->lcLocale = 0;
+ pFileEntry->wPlatform = 0;
+ pFileEntry->dwCrc32 = 0;
+ memset(pFileEntry->md5, 0, MD5_DIGEST_SIZE);
+
+ // Allocate space for file name, if it's not there yet
+ AllocateFileName(pFileEntry, szFileName);
+
+ // If the free file entry is at the end of the file table,
+ // we have to increment file table size
+ if(pFileEntry == ha->pFileTable + ha->dwFileTableSize)
+ {
+ assert(ha->dwFileTableSize < ha->dwMaxFileCount);
+ ha->pHeader->dwBlockTableSize++;
+ ha->dwFileTableSize++;
+ }
+
+ // If the MPQ has hash table, we have to insert the new entry into the hash table
+ if(ha->pHashTable != NULL && bHashEntryExists == false)
+ {
+ dwHashIndex = AllocateHashEntry(ha, pFileEntry);
+ assert(dwHashIndex != HASH_ENTRY_FREE);
+ }
+
+ // If the MPQ has HET table, we have to insert it to the HET table as well
+ if(ha->pHetTable != NULL && bHetEntryExists == false)
+ {
+ // TODO: Does HET table even support locales?
+ // Most probably, Blizzard gave up that silly idea long ago.
+ dwHashIndex = AllocateHetEntry(ha, pFileEntry);
+ assert(dwHashIndex != HASH_ENTRY_FREE);
+ }
+
+ // Return the file entry
+ return pFileEntry;
+}
+
+int RenameFileEntry(
+ TMPQArchive * ha,
+ TFileEntry * pFileEntry,
+ const char * szNewFileName)
+{
+ TMPQHash * pHash;
+ DWORD dwFileIndex;
+ int nError = ERROR_SUCCESS;
+
+ // If the MPQ has classic hash table, clear the entry there
+ if(ha->pHashTable != NULL)
+ {
+ assert(pFileEntry->dwHashIndex < ha->pHeader->dwHashTableSize);
+
+ pHash = ha->pHashTable + pFileEntry->dwHashIndex;
+ memset(pHash, 0xFF, sizeof(TMPQHash));
+ pHash->dwBlockIndex = HASH_ENTRY_DELETED;
+ }
+
+ // If the MPQ has HET table, clear the entry there as well
+ if(ha->pHetTable != NULL)
+ {
+ TMPQHetTable * pHetTable = ha->pHetTable;
+ DWORD dwInvalidFileIndex = (1 << pHetTable->dwIndexSizeTotal) - 1;
+
+ assert(pFileEntry->dwHetIndex < pHetTable->dwHashTableSize);
+
+ // Clear the entry in the HET hash array
+ pHetTable->pHetHashes[pFileEntry->dwHetIndex] = HET_ENTRY_DELETED;
+
+ // Set the BET index to invalid index
+ pHetTable->pBetIndexes->SetBits(pHetTable->dwIndexSizeTotal * pFileEntry->dwHetIndex,
+ pHetTable->dwIndexSize,
+ &dwInvalidFileIndex,
+ 4);
+ }
+
+ // Free the old file name
+ if(pFileEntry->szFileName != NULL)
+ STORM_FREE(pFileEntry->szFileName);
+ pFileEntry->szFileName = NULL;
+
+ // Allocate new file name
+ AllocateFileName(pFileEntry, szNewFileName);
+
+ // Now find a hash entry for the new file name
+ if(ha->pHashTable != NULL)
+ {
+ // Try to find the hash table entry for the new file name
+ // Note: If this fails, we leave the MPQ in a corrupt state
+ dwFileIndex = AllocateHashEntry(ha, pFileEntry);
+ if(dwFileIndex == HASH_ENTRY_FREE)
+ nError = ERROR_FILE_CORRUPT;
+ }
+
+ // If the archive has HET table, we have to allocate HET table for the file as well
+ // finding the file
+ if(ha->pHetTable != NULL)
+ {
+ dwFileIndex = AllocateHetEntry(ha, pFileEntry);
+ if(dwFileIndex == HASH_ENTRY_FREE)
+ nError = ERROR_FILE_CORRUPT;
+ }
+
+ // Invalidate the entries for (listfile) and (attributes)
+ // After we are done with MPQ changes, we need to re-create them
+ InvalidateInternalFiles(ha);
+ return nError;
+}
+
+void ClearFileEntry(
+ TMPQArchive * ha,
+ TFileEntry * pFileEntry)
+{
+ TMPQHash * pHash = NULL;
+
+ // If the MPQ has classic hash table, clear the entry there
+ if(ha->pHashTable != NULL)
+ {
+ assert(pFileEntry->dwHashIndex < ha->pHeader->dwHashTableSize);
+
+ pHash = ha->pHashTable + pFileEntry->dwHashIndex;
+ memset(pHash, 0xFF, sizeof(TMPQHash));
+ pHash->dwBlockIndex = HASH_ENTRY_DELETED;
+ }
+
+ // If the MPQ has HET table, clear the entry there as well
+ if(ha->pHetTable != NULL)
+ {
+ TMPQHetTable * pHetTable = ha->pHetTable;
+ DWORD dwInvalidFileIndex = (1 << pHetTable->dwIndexSizeTotal) - 1;
+
+ assert(pFileEntry->dwHetIndex < pHetTable->dwHashTableSize);
+
+ // Clear the entry in the HET hash array
+ pHetTable->pHetHashes[pFileEntry->dwHetIndex] = HET_ENTRY_DELETED;
+
+ // Set the BET index to invalid index
+ pHetTable->pBetIndexes->SetBits(pHetTable->dwIndexSizeTotal * pFileEntry->dwHetIndex,
+ pHetTable->dwIndexSize,
+ &dwInvalidFileIndex,
+ 4);
+ }
+
+ // Free the file name, and set the file entry as deleted
+ if(pFileEntry->szFileName != NULL)
+ STORM_FREE(pFileEntry->szFileName);
+
+ // Invalidate the file entry
+ memset(pFileEntry, 0, sizeof(TFileEntry));
+}
+
+int FreeFileEntry(
+ TMPQArchive * ha,
+ TFileEntry * pFileEntry)
+{
+ TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
+ TFileEntry * pTempEntry;
+ int nError = ERROR_SUCCESS;
+
+ //
+ // If we have HET table, we cannot just get rid of the file
+ // Doing so would lead to empty gaps in the HET table
+ // We have to keep BET hash, hash index, HET index, locale, platform and file name
+ //
+
+ if(ha->pHetTable == NULL)
+ {
+ TFileEntry * pLastFileEntry = ha->pFileTable + ha->dwFileTableSize - 1;
+ TFileEntry * pLastUsedEntry = pLastFileEntry;
+
+ // Zero the file entry
+ ClearFileEntry(ha, pFileEntry);
+
+ // Now there is a chance that we created a chunk of free
+ // file entries at the end of the file table. We check this
+ // and eventually free all deleted file entries at the end
+ for(pTempEntry = ha->pFileTable; pTempEntry < pFileTableEnd; pTempEntry++)
+ {
+ // Is that an occupied file entry?
+ if(pTempEntry->dwFlags & MPQ_FILE_EXISTS)
+ pLastUsedEntry = pTempEntry;
+ }
+
+ // Can we free some entries at the end?
+ if(pLastUsedEntry < pLastFileEntry)
+ {
+ // Fix the size of the file table entry
+ ha->dwFileTableSize = (DWORD)(pLastUsedEntry - ha->pFileTable) + 1;
+ ha->pHeader->dwBlockTableSize = ha->dwFileTableSize;
+ }
+ }
+ else
+ {
+ // Note: Deleted entries in Blizzard MPQs version 4.0
+ // normally contain valid byte offset and length
+ pFileEntry->dwFlags &= ~MPQ_FILE_EXISTS;
+ nError = ERROR_SUCCESS;
+ }
+
+ return nError;
+}
+
+void InvalidateInternalFiles(TMPQArchive * ha)
+{
+ TFileEntry * pFileEntry;
+
+ // Invalidate the (listfile), if not done yet
+ if(!(ha->dwFlags & MPQ_FLAG_INV_LISTFILE))
+ {
+ pFileEntry = GetFileEntryExact(ha, LISTFILE_NAME, LANG_NEUTRAL);
+ if(pFileEntry != NULL)
+ FreeFileEntry(ha, pFileEntry);
+ ha->dwFlags |= MPQ_FLAG_INV_LISTFILE;
+ }
+
+ // Invalidate the (attributes), if not done yet
+ if(!(ha->dwFlags & MPQ_FLAG_INV_ATTRIBUTES))
+ {
+ pFileEntry = GetFileEntryExact(ha, ATTRIBUTES_NAME, LANG_NEUTRAL);
+ if(pFileEntry != NULL)
+ FreeFileEntry(ha, pFileEntry);
+ ha->dwFlags |= MPQ_FLAG_INV_ATTRIBUTES;
+ }
+
+ // Remember that the MPQ has been changed and it will be necessary
+ // to update the tables
+ ha->dwFlags |= MPQ_FLAG_CHANGED;
+}
+
+//-----------------------------------------------------------------------------
+// Functions that loads and verify MPQ data bitmap
+
+int LoadMpqDataBitmap(TMPQArchive * ha, ULONGLONG FileSize, bool * pbFileIsComplete)
+{
+ TMPQBitmap * pBitmap = NULL;
+ TMPQBitmap DataBitmap;
+ ULONGLONG BitmapOffset;
+ ULONGLONG EndOfMpq;
+ DWORD DataBlockCount = 0;
+ DWORD BitmapByteSize;
+ DWORD WholeByteCount;
+ DWORD ExtraBitsCount;
+
+ // Is there enough space for a MPQ bitmap?
+ EndOfMpq = ha->MpqPos + ha->pHeader->ArchiveSize64;
+ FileSize = FileSize - sizeof(TMPQBitmap);
+ if(FileSize > EndOfMpq)
+ {
+ // Try to load the data bitmap from the end of the file
+ if(FileStream_Read(ha->pStream, &FileSize, &DataBitmap, sizeof(TMPQBitmap)))
+ {
+ // Is it a valid data bitmap?
+ BSWAP_ARRAY32_UNSIGNED((LPDWORD)(&DataBitmap), sizeof(TMPQBitmap));
+ if(DataBitmap.dwSignature == MPQ_DATA_BITMAP_SIGNATURE)
+ {
+ // We assume that MPQs with data bitmap begin at position 0
+ assert(ha->MpqPos == 0);
+
+ // Calculate the number of extra bytes for data bitmap
+ DataBlockCount = (DWORD)(((ha->pHeader->ArchiveSize64 - 1) / DataBitmap.dwBlockSize) + 1);
+ BitmapByteSize = ((DataBlockCount - 1) / 8) + 1;
+
+ // Verify the data block size
+ BitmapOffset = ((ULONGLONG)DataBitmap.dwMapOffsetHi << 32) | DataBitmap.dwMapOffsetLo;
+ assert((DWORD)(FileSize - BitmapOffset) == BitmapByteSize);
+
+ // Allocate space for the data bitmap
+ pBitmap = (TMPQBitmap *)STORM_ALLOC(BYTE, sizeof(TMPQBitmap) + BitmapByteSize);
+ if(pBitmap != NULL)
+ {
+ // Copy the bitmap header
+ memcpy(pBitmap, &DataBitmap, sizeof(TMPQBitmap));
+
+ // Read the remaining part
+ if(!FileStream_Read(ha->pStream, &BitmapOffset, (pBitmap + 1), BitmapByteSize))
+ {
+ STORM_FREE(pBitmap);
+ pBitmap = NULL;
+ }
+ }
+ }
+ }
+ }
+
+ // If the caller asks for file completeness, check it
+ if(pBitmap != NULL && pbFileIsComplete != NULL)
+ {
+ LPBYTE pbBitmap = (LPBYTE)(pBitmap + 1);
+ DWORD i;
+ bool bFileIsComplete = true;
+
+ // Calculate the number of whole bytes and extra bits of the bitmap
+ WholeByteCount = (DataBlockCount / 8);
+ ExtraBitsCount = (DataBlockCount & 7);
+
+ // Verify the whole bytes - their value must be 0xFF
+ for(i = 0; i < WholeByteCount; i++)
+ {
+ if(pbBitmap[i] != 0xFF)
+ bFileIsComplete = false;
+ }
+
+ // If there are extra bits, calculate the mask
+ if(ExtraBitsCount != 0)
+ {
+ BYTE ExpectedValue = (BYTE)((1 << ExtraBitsCount) - 1);
+
+ if(pbBitmap[i] != ExpectedValue)
+ bFileIsComplete = false;
+ }
+
+ // Give the result to the caller
+ *pbFileIsComplete = bFileIsComplete;
+ }
+
+ ha->pBitmap = pBitmap;
+ return ERROR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// Support for file tables - hash table, block table, hi-block table
+
+int CreateHashTable(TMPQArchive * ha, DWORD dwHashTableSize)
+{
+ TMPQHash * pHashTable;
+
+ // Sanity checks
+ assert((dwHashTableSize & (dwHashTableSize - 1)) == 0);
+ assert(ha->pHashTable == NULL);
+
+ // Create the hash table
+ pHashTable = STORM_ALLOC(TMPQHash, dwHashTableSize);
+ if(pHashTable == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Fill it
+ memset(pHashTable, 0xFF, dwHashTableSize * sizeof(TMPQHash));
+ ha->pHashTable = pHashTable;
+
+ // Set the max file count, if needed
+ if(ha->pHetTable == NULL)
+ ha->dwMaxFileCount = dwHashTableSize;
+ return ERROR_SUCCESS;
+}
+
+TMPQHash * LoadHashTable(TMPQArchive * ha)
+{
+ TMPQHeader * pHeader = ha->pHeader;
+ ULONGLONG ByteOffset;
+ TMPQHash * pHashTable;
+ DWORD dwTableSize;
+ DWORD dwCmpSize;
+ int nError;
+
+ // If the MPQ has no hash table, do nothing
+ if(pHeader->dwHashTablePos == 0 && pHeader->wHashTablePosHi == 0)
+ return NULL;
+
+ // If the hash table size is zero, do nothing
+ if(pHeader->dwHashTableSize == 0)
+ return NULL;
+
+ // Allocate buffer for the hash table
+ dwTableSize = pHeader->dwHashTableSize * sizeof(TMPQHash);
+ pHashTable = STORM_ALLOC(TMPQHash, pHeader->dwHashTableSize);
+ if(pHashTable == NULL)
+ return NULL;
+
+ // Compressed size of the hash table
+ dwCmpSize = (DWORD)pHeader->HashTableSize64;
+
+ //
+ // Load the table from the MPQ, with decompression
+ //
+ // Note: We will NOT check if the hash table is properly decrypted.
+ // Some MPQ protectors corrupt the hash table by rewriting part of it.
+ // Hash table, the way how it works, allows arbitrary values for unused entries.
+ //
+
+ ByteOffset = ha->MpqPos + MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos);
+ nError = LoadMpqTable(ha, ByteOffset, pHashTable, dwCmpSize, dwTableSize, MPQ_KEY_HASH_TABLE);
+ if(nError != ERROR_SUCCESS)
+ {
+ STORM_FREE(pHashTable);
+ pHashTable = NULL;
+ }
+
+ // Return the hash table
+ return pHashTable;
+}
+
+static void FixBlockTableSize(
+ TMPQArchive * ha,
+ TMPQBlock * pBlockTable,
+ DWORD dwClaimedSize)
+{
+ TMPQHeader * pHeader = ha->pHeader;
+ ULONGLONG BlockTableStart;
+ ULONGLONG BlockTableEnd;
+ ULONGLONG FileDataStart;
+
+ // Only perform this check on MPQs version 1.0
+ if(pHeader->dwHeaderSize == MPQ_HEADER_SIZE_V1)
+ {
+ // Calculate claimed block table begin and end
+ BlockTableStart = ha->MpqPos + MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
+ BlockTableEnd = BlockTableStart + (pHeader->dwBlockTableSize * sizeof(TMPQBlock));
+
+ for(DWORD i = 0; i < dwClaimedSize; i++)
+ {
+ // If the block table end goes into that file, fix the block table end
+ FileDataStart = ha->MpqPos + pBlockTable[i].dwFilePos;
+ if(BlockTableStart < FileDataStart && BlockTableEnd > FileDataStart)
+ {
+ dwClaimedSize = (DWORD)((FileDataStart - BlockTableStart) / sizeof(TMPQBlock));
+ BlockTableEnd = FileDataStart;
+ }
+ }
+ }
+
+ // Fix the block table size
+ pHeader->BlockTableSize64 = dwClaimedSize * sizeof(TMPQBlock);
+ pHeader->dwBlockTableSize = dwClaimedSize;
+}
+
+TMPQBlock * LoadBlockTable(TMPQArchive * ha, ULONGLONG FileSize)
+{
+ TMPQHeader * pHeader = ha->pHeader;
+ TMPQBlock * pBlockTable;
+ ULONGLONG ByteOffset;
+ DWORD dwTableSize;
+ DWORD dwCmpSize;
+ int nError;
+
+ // Do nothing if the block table position is zero
+ if(pHeader->dwBlockTablePos == 0 && pHeader->wBlockTablePosHi == 0)
+ return NULL;
+
+ // Do nothing if the block table size is zero
+ if(pHeader->dwBlockTableSize == 0)
+ return NULL;
+
+ // Sanity check, enforced by LoadAnyHashTable
+ assert(ha->dwMaxFileCount >= pHeader->dwBlockTableSize);
+
+ // Calculate sizes of both tables
+ ByteOffset = ha->MpqPos + MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
+ dwTableSize = pHeader->dwBlockTableSize * sizeof(TMPQBlock);
+ dwCmpSize = (DWORD)pHeader->BlockTableSize64;
+
+ // Allocate space for the block table
+ // Note: pHeader->dwBlockTableSize can be zero !!!
+ pBlockTable = STORM_ALLOC(TMPQBlock, ha->dwMaxFileCount);
+ if(pBlockTable == NULL)
+ return NULL;
+
+ // Fill the block table with zeros
+ memset(pBlockTable, 0, dwTableSize);
+
+ // I found a MPQ which claimed 0x200 entries in the block table,
+ // but the file was cut and there was only 0x1A0 entries.
+ // We will handle this case properly.
+ if(dwTableSize == dwCmpSize && (ByteOffset + dwTableSize) > FileSize)
+ {
+ pHeader->dwBlockTableSize = (DWORD)((FileSize - ByteOffset) / sizeof(TMPQBlock));
+ pHeader->BlockTableSize64 = pHeader->dwBlockTableSize * sizeof(TMPQBlock);
+ dwTableSize = dwCmpSize = pHeader->dwBlockTableSize * sizeof(TMPQBlock);
+ }
+
+ //
+ // One of the first cracked versions of Diablo I had block table unencrypted
+ // StormLib does NOT support such MPQs anymore, as they are incompatible
+ // with compressed block table feature
+ //
+
+ // Load the block table
+ nError = LoadMpqTable(ha, ByteOffset, pBlockTable, dwCmpSize, dwTableSize, MPQ_KEY_BLOCK_TABLE);
+ if(nError != ERROR_SUCCESS)
+ {
+ // Failed, sorry
+ STORM_FREE(pBlockTable);
+ return NULL;
+ }
+
+ // Defense against MPQs that claim block table to be bigger than it really is
+ FixBlockTableSize(ha, pBlockTable, pHeader->dwBlockTableSize);
+ return pBlockTable;
+}
+
+int LoadHetTable(TMPQArchive * ha)
+{
+ TMPQExtTable * pExtTable;
+ TMPQHeader * pHeader = ha->pHeader;
+ int nError = ERROR_SUCCESS;
+
+ // If the HET table position is not NULL, we expect
+ // both HET and BET tables to be present.
+ if(pHeader->HetTablePos64 != 0)
+ {
+ // Attempt to load the HET table (Hash Extended Table)
+ pExtTable = LoadExtTable(ha, pHeader->HetTablePos64, (size_t)pHeader->HetTableSize64, HET_TABLE_SIGNATURE, MPQ_KEY_HASH_TABLE);
+ if(pExtTable != NULL)
+ {
+ // If succeeded, we have to limit the maximum file count
+ // to the values saved in the HET table
+ // If loading HET table fails, we ignore the result.
+ ha->pHetTable = TranslateHetTable(pExtTable);
+ if(ha->pHetTable != NULL)
+ ha->dwMaxFileCount = ha->pHetTable->dwMaxFileCount;
+
+ STORM_FREE(pExtTable);
+ }
+
+ // If the HET hable failed to load, it's corrupt.
+ if(ha->pHetTable == NULL)
+ nError = ERROR_FILE_CORRUPT;
+ }
+
+ return nError;
+}
+
+TMPQBetTable * LoadBetTable(TMPQArchive * ha)
+{
+ TMPQExtTable * pExtTable;
+ TMPQBetTable * pBetTable = NULL;
+ TMPQHeader * pHeader = ha->pHeader;
+
+ // If the HET table position is not NULL, we expect
+ // both HET and BET tables to be present.
+ if(pHeader->BetTablePos64 != 0)
+ {
+ // Attempt to load the HET table (Hash Extended Table)
+ pExtTable = LoadExtTable(ha, pHeader->BetTablePos64, (size_t)pHeader->BetTableSize64, BET_TABLE_SIGNATURE, MPQ_KEY_BLOCK_TABLE);
+ if(pExtTable != NULL)
+ {
+ // If succeeded, we translate the BET table
+ // to more readable form
+ pBetTable = TranslateBetTable(ha, pExtTable);
+ STORM_FREE(pExtTable);
+ }
+ }
+
+ return pBetTable;
+}
+
+int LoadAnyHashTable(TMPQArchive * ha)
+{
+ TMPQHeader * pHeader = ha->pHeader;
+
+ // If the MPQ archive is empty, don't bother trying to load anything
+ if(pHeader->dwHashTableSize == 0 && pHeader->HetTableSize64 == 0)
+ return CreateHashTable(ha, HASH_TABLE_SIZE_DEFAULT);
+
+ // Try to load HET and/or classic hash table
+ LoadHetTable(ha);
+
+ // Load the HASH table
+ ha->pHashTable = LoadHashTable(ha);
+
+ // Set the maximum file count to the size of the hash table
+ // In case there is HET table, we have to keep the file limit
+ if(ha->pHetTable == NULL)
+ ha->dwMaxFileCount = pHeader->dwHashTableSize;
+
+ // Did at least one succeed?
+ if(ha->pHetTable == NULL && ha->pHashTable == NULL)
+ return ERROR_FILE_CORRUPT;
+
+ // In theory, a MPQ could have bigger block table than hash table
+ if(ha->pHeader->dwBlockTableSize > ha->dwMaxFileCount)
+ {
+ ha->dwMaxFileCount = ha->pHeader->dwBlockTableSize;
+ ha->dwFlags |= MPQ_FLAG_READ_ONLY;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+int BuildFileTable_Classic(
+ TMPQArchive * ha,
+ TFileEntry * pFileTable,
+ ULONGLONG FileSize)
+{
+ TFileEntry * pFileEntry;
+ TMPQHeader * pHeader = ha->pHeader;
+ TMPQBlock * pBlockTable;
+ TMPQBlock * pBlock;
+ int nError = ERROR_SUCCESS;
+
+ // Sanity checks
+ assert(ha->pHashTable != NULL);
+
+ // Load the block table
+ pBlockTable = LoadBlockTable(ha, FileSize);
+ if(pBlockTable != NULL)
+ {
+ TMPQHash * pHashEnd = ha->pHashTable + pHeader->dwHashTableSize;
+ TMPQHash * pHash;
+
+ // If we don't have HET table, we build the file entries from the hash&block tables
+ if(ha->pHetTable == NULL)
+ {
+ for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++)
+ {
+ if(pHash->dwBlockIndex < pHeader->dwBlockTableSize)
+ {
+ pFileEntry = pFileTable + pHash->dwBlockIndex;
+ pBlock = pBlockTable + pHash->dwBlockIndex;
+
+ //
+ // Yet another silly map protector: For each valid file,
+ // there are 4 items in the hash table, that appears to be valid:
+ //
+ // a6d79af0 e61a0932 001e0000 0000770b <== Fake valid
+ // a6d79af0 e61a0932 0000d761 0000dacb <== Fake valid
+ // a6d79af0 e61a0932 00000000 0000002f <== Real file entry
+ // a6d79af0 e61a0932 00005a4f 000093bc <== Fake valid
+ //
+
+ if(!(pBlock->dwFlags & ~MPQ_FILE_VALID_FLAGS) && (pBlock->dwFlags & MPQ_FILE_EXISTS))
+ {
+ // Fill the entry
+ pFileEntry->ByteOffset = pBlock->dwFilePos;
+ pFileEntry->dwHashIndex = (DWORD)(pHash - ha->pHashTable);
+ pFileEntry->dwFileSize = pBlock->dwFSize;
+ pFileEntry->dwCmpSize = pBlock->dwCSize;
+ pFileEntry->dwFlags = pBlock->dwFlags;
+ pFileEntry->lcLocale = pHash->lcLocale;
+ pFileEntry->wPlatform = pHash->wPlatform;
+ }
+ else
+ {
+ // If the hash table entry doesn't point to the valid file item,
+ // we invalidate the entire hash table entry
+ pHash->dwName1 = 0xFFFFFFFF;
+ pHash->dwName2 = 0xFFFFFFFF;
+ pHash->lcLocale = 0xFFFF;
+ pHash->wPlatform = 0xFFFF;
+ pHash->dwBlockIndex = HASH_ENTRY_DELETED;
+ }
+ }
+ }
+ }
+ else
+ {
+ for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++)
+ {
+ if(pHash->dwBlockIndex < ha->dwFileTableSize)
+ {
+ pFileEntry = pFileTable + pHash->dwBlockIndex;
+ if(pFileEntry->dwFlags & MPQ_FILE_EXISTS)
+ {
+ pFileEntry->dwHashIndex = (DWORD)(pHash - ha->pHashTable);
+ pFileEntry->lcLocale = pHash->lcLocale;
+ pFileEntry->wPlatform = pHash->wPlatform;
+ }
+ }
+ }
+ }
+
+ // Free the block table
+ STORM_FREE(pBlockTable);
+ }
+ else
+ {
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Load the hi-block table
+ if(nError == ERROR_SUCCESS && pHeader->HiBlockTablePos64 != 0)
+ {
+ ULONGLONG ByteOffset;
+ USHORT * pHiBlockTable = NULL;
+ DWORD dwTableSize = pHeader->dwBlockTableSize * sizeof(USHORT);
+
+ // Allocate space for the hi-block table
+ // Note: pHeader->dwBlockTableSize can be zero !!!
+ pHiBlockTable = STORM_ALLOC(USHORT, pHeader->dwBlockTableSize + 1);
+ if(pHiBlockTable != NULL)
+ {
+ // Load the hi-block table. It is not encrypted, nor compressed
+ ByteOffset = ha->MpqPos + pHeader->HiBlockTablePos64;
+ if(!FileStream_Read(ha->pStream, &ByteOffset, pHiBlockTable, dwTableSize))
+ nError = GetLastError();
+
+ // Now merge the hi-block table to the file table
+ if(nError == ERROR_SUCCESS)
+ {
+ pFileEntry = pFileTable;
+
+ // Add the high file offset to the base file offset.
+ // We also need to swap it during the process.
+ for(DWORD i = 0; i < pHeader->dwBlockTableSize; i++)
+ {
+ pFileEntry->ByteOffset |= ((ULONGLONG)BSWAP_INT16_UNSIGNED(pHiBlockTable[i]) << 32);
+ pFileEntry++;
+ }
+ }
+
+ // Free the hi-block table
+ STORM_FREE(pHiBlockTable);
+ }
+ else
+ {
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+
+ // Set the current size of the file table
+ ha->dwFileTableSize = pHeader->dwBlockTableSize;
+ return nError;
+}
+
+int BuildFileTable_HetBet(
+ TMPQArchive * ha,
+ TFileEntry * pFileTable)
+{
+ TMPQHetTable * pHetTable = ha->pHetTable;
+ TMPQBetTable * pBetTable;
+ TFileEntry * pFileEntry = pFileTable;
+ TBitArray * pBitArray;
+ DWORD dwBitPosition = 0;
+ DWORD i;
+ int nError = ERROR_FILE_CORRUPT;
+
+ // Load the BET table from the MPQ
+ pBetTable = LoadBetTable(ha);
+ if(pBetTable != NULL)
+ {
+ // Step one: Fill the indexes to the HET table
+ for(i = 0; i < pHetTable->dwHashTableSize; i++)
+ {
+ DWORD dwFileIndex = 0;
+
+ // Is the entry in the HET table occupied?
+ if(pHetTable->pHetHashes[i] != 0)
+ {
+ // Load the index to the BET table
+ pHetTable->pBetIndexes->GetBits(pHetTable->dwIndexSizeTotal * i,
+ pHetTable->dwIndexSize,
+ &dwFileIndex,
+ 4);
+ // Overflow test
+ if(dwFileIndex < pBetTable->dwFileCount)
+ {
+ // Get the file entry and save HET index
+ pFileEntry = pFileTable + dwFileIndex;
+ pFileEntry->dwHetIndex = i;
+
+ // Load the BET hash
+ pBetTable->pBetHashes->GetBits(pBetTable->dwBetHashSizeTotal * dwFileIndex,
+ pBetTable->dwBetHashSize,
+ &pFileEntry->BetHash,
+ 8);
+ }
+ }
+ }
+
+ // Go through the entire BET table and convert it to the file table.
+ pFileEntry = pFileTable;
+ pBitArray = pBetTable->pFileTable;
+ for(i = 0; i < pBetTable->dwFileCount; i++)
+ {
+ DWORD dwFlagIndex = 0;
+
+ // Read the file position
+ pBitArray->GetBits(dwBitPosition + pBetTable->dwBitIndex_FilePos,
+ pBetTable->dwBitCount_FilePos,
+ &pFileEntry->ByteOffset,
+ 8);
+
+ // Read the file size
+ pBitArray->GetBits(dwBitPosition + pBetTable->dwBitIndex_FileSize,
+ pBetTable->dwBitCount_FileSize,
+ &pFileEntry->dwFileSize,
+ 4);
+
+ // Read the compressed size
+ pBitArray->GetBits(dwBitPosition + pBetTable->dwBitIndex_CmpSize,
+ pBetTable->dwBitCount_CmpSize,
+ &pFileEntry->dwCmpSize,
+ 4);
+
+
+ // Read the flag index
+ if(pBetTable->dwFlagCount != 0)
+ {
+ pBitArray->GetBits(dwBitPosition + pBetTable->dwBitIndex_FlagIndex,
+ pBetTable->dwBitCount_FlagIndex,
+ &dwFlagIndex,
+ 4);
+
+ pFileEntry->dwFlags = pBetTable->pFileFlags[dwFlagIndex];
+ }
+
+ //
+ // TODO: Locale (?)
+ //
+
+ // Move the current bit position
+ dwBitPosition += pBetTable->dwTableEntrySize;
+ pFileEntry++;
+ }
+
+ // Set the current size of the file table
+ ha->dwFileTableSize = pBetTable->dwFileCount;
+ FreeBetTable(pBetTable);
+ nError = ERROR_SUCCESS;
+ }
+ else
+ {
+ nError = ERROR_FILE_CORRUPT;
+ }
+
+ return nError;
+}
+
+int BuildFileTable(TMPQArchive * ha, ULONGLONG FileSize)
+{
+ TFileEntry * pFileTable;
+ bool bFileTableCreated = false;
+
+ // Sanity checks
+ assert(ha->dwFileTableSize == 0);
+ assert(ha->dwMaxFileCount != 0);
+
+ // Allocate the file table with size determined before
+ pFileTable = STORM_ALLOC(TFileEntry, ha->dwMaxFileCount);
+ if(pFileTable == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Fill the table with zeros
+ memset(pFileTable, 0, ha->dwMaxFileCount * sizeof(TFileEntry));
+
+ // If we have HET table, we load file table from the BET table
+ // Note: If BET table is corrupt or missing, we set the archive as read only
+ if(ha->pHetTable != NULL)
+ {
+ if(BuildFileTable_HetBet(ha, pFileTable) != ERROR_SUCCESS)
+ ha->dwFlags |= MPQ_FLAG_READ_ONLY;
+ else
+ bFileTableCreated = true;
+ }
+
+ // If we have hash table, we load the file table from the block table
+ // Note: If block table is corrupt or missing, we set the archive as read only
+ if(ha->pHashTable != NULL)
+ {
+ if(BuildFileTable_Classic(ha, pFileTable, FileSize) != ERROR_SUCCESS)
+ ha->dwFlags |= MPQ_FLAG_READ_ONLY;
+ else
+ bFileTableCreated = true;
+ }
+
+ // If something failed, we free the file table entry
+ if(bFileTableCreated == false)
+ {
+ STORM_FREE(pFileTable);
+ return ERROR_FILE_CORRUPT;
+ }
+
+ // Assign it to the archive structure
+ ha->pFileTable = pFileTable;
+ return ERROR_SUCCESS;
+}
+
+// Saves MPQ header, hash table, block table and hi-block table.
+int SaveMPQTables(TMPQArchive * ha)
+{
+ TMPQExtTable * pHetTable = NULL;
+ TMPQExtTable * pBetTable = NULL;
+ TMPQHeader * pHeader = ha->pHeader;
+ TMPQBlock * pBlockTable = NULL;
+ TMPQHash * pHashTable = NULL;
+ ULONGLONG HetTableSize64 = 0;
+ ULONGLONG BetTableSize64 = 0;
+ ULONGLONG HashTableSize64 = 0;
+ ULONGLONG BlockTableSize64 = 0;
+ ULONGLONG HiBlockTableSize64 = 0;
+ ULONGLONG TablePos = 0; // A table position, relative to the begin of the MPQ
+ USHORT * pHiBlockTable = NULL;
+ DWORD cbTotalSize;
+ bool bNeedHiBlockTable = false;
+ int nError = ERROR_SUCCESS;
+
+ // We expect this function to be called only when tables have been changed
+ assert(ha->dwFlags & MPQ_FLAG_CHANGED);
+
+ // Find the space where the MPQ tables will be saved
+ FindFreeMpqSpace(ha, &TablePos);
+
+ // If the MPQ has HET table, we prepare a ready-to-save version
+ if(nError == ERROR_SUCCESS && ha->pHetTable != NULL)
+ {
+ pHetTable = TranslateHetTable(ha->pHetTable, &HetTableSize64);
+ if(pHetTable == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // If the MPQ has HET table, we also must create BET table to be saved
+ if(nError == ERROR_SUCCESS && ha->pHetTable != NULL)
+ {
+ pBetTable = TranslateBetTable(ha, &BetTableSize64);
+ if(pBetTable == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Now create hash table
+ if(nError == ERROR_SUCCESS && ha->pHashTable != NULL)
+ {
+ pHashTable = TranslateHashTable(ha, &HashTableSize64);
+ if(pHashTable == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Create block table
+ if(nError == ERROR_SUCCESS && ha->pHashTable != NULL)
+ {
+ pBlockTable = TranslateBlockTable(ha, &BlockTableSize64, &bNeedHiBlockTable);
+ if(pBlockTable == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Create hi-block table, if needed
+ if(nError == ERROR_SUCCESS && bNeedHiBlockTable)
+ {
+ pHiBlockTable = TranslateHiBlockTable(ha, &HiBlockTableSize64);
+ if(pHiBlockTable == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Write the HET table, if any
+ if(nError == ERROR_SUCCESS && pHetTable != NULL)
+ {
+ pHeader->HetTableSize64 = HetTableSize64;
+ pHeader->HetTablePos64 = TablePos;
+ nError = SaveExtTable(ha, pHetTable, TablePos, (DWORD)HetTableSize64, pHeader->MD5_HetTable, MPQ_KEY_HASH_TABLE, false, &cbTotalSize);
+ TablePos += cbTotalSize;
+ }
+
+ // Write the BET table, if any
+ if(nError == ERROR_SUCCESS && pBetTable != NULL)
+ {
+ pHeader->BetTableSize64 = BetTableSize64;
+ pHeader->BetTablePos64 = TablePos;
+ nError = SaveExtTable(ha, pBetTable, TablePos, (DWORD)BetTableSize64, pHeader->MD5_BetTable, MPQ_KEY_BLOCK_TABLE, false, &cbTotalSize);
+ TablePos += cbTotalSize;
+ }
+
+ // Write the hash table, if we have any
+ if(nError == ERROR_SUCCESS && pHashTable != NULL)
+ {
+ pHeader->HashTableSize64 = HashTableSize64;
+ pHeader->wHashTablePosHi = (USHORT)(TablePos >> 32);
+ pHeader->dwHashTableSize = (DWORD)(HashTableSize64 / sizeof(TMPQHash));
+ pHeader->dwHashTablePos = (DWORD)TablePos;
+ nError = SaveMpqTable(ha, pHashTable, TablePos, (size_t)HashTableSize64, pHeader->MD5_HashTable, MPQ_KEY_HASH_TABLE, false);
+ TablePos += HashTableSize64;
+ }
+
+ // Write the block table, if we have any
+ if(nError == ERROR_SUCCESS && pBlockTable != NULL)
+ {
+ pHeader->BlockTableSize64 = BlockTableSize64;
+ pHeader->wBlockTablePosHi = (USHORT)(TablePos >> 32);
+ pHeader->dwBlockTableSize = (DWORD)(BlockTableSize64 / sizeof(TMPQBlock));
+ pHeader->dwBlockTablePos = (DWORD)TablePos;
+ nError = SaveMpqTable(ha, pBlockTable, TablePos, (size_t)BlockTableSize64, pHeader->MD5_BlockTable, MPQ_KEY_BLOCK_TABLE, false);
+ TablePos += BlockTableSize64;
+ }
+
+ // Write the hi-block table, if we have any
+ if(nError == ERROR_SUCCESS && pHiBlockTable != NULL)
+ {
+ ULONGLONG ByteOffset = ha->MpqPos + TablePos;
+
+ pHeader->HiBlockTableSize64 = HiBlockTableSize64;
+ pHeader->HiBlockTablePos64 = TablePos;
+ BSWAP_ARRAY16_UNSIGNED(pHiBlockTable, HiBlockTableSize64);
+
+ if(!FileStream_Write(ha->pStream, &ByteOffset, pHiBlockTable, (DWORD)HiBlockTableSize64))
+ nError = GetLastError();
+ TablePos += HiBlockTableSize64;
+ }
+
+ // Cut the MPQ
+ if(nError == ERROR_SUCCESS)
+ {
+ ULONGLONG FileSize = ha->MpqPos + TablePos;
+
+ if(!FileStream_SetSize(ha->pStream, FileSize))
+ nError = GetLastError();
+ }
+
+ // Write the MPQ header
+ if(nError == ERROR_SUCCESS)
+ {
+ // Update the size of the archive
+ pHeader->ArchiveSize64 = TablePos;
+ pHeader->dwArchiveSize = (DWORD)TablePos;
+
+ // Update the MD5 of the archive header
+ CalculateDataBlockHash(pHeader, MPQ_HEADER_SIZE_V4 - MD5_DIGEST_SIZE, pHeader->MD5_MpqHeader);
+
+ // Write the MPQ header to the file
+ BSWAP_TMPQHEADER(pHeader);
+ if(!FileStream_Write(ha->pStream, &ha->MpqPos, pHeader, pHeader->dwHeaderSize))
+ nError = GetLastError();
+ BSWAP_TMPQHEADER(pHeader);
+ }
+
+ // Clear the changed flag
+ if(nError == ERROR_SUCCESS)
+ ha->dwFlags &= ~MPQ_FLAG_CHANGED;
+
+ // Cleanup and exit
+ if(pHetTable != NULL)
+ STORM_FREE(pHetTable);
+ if(pBetTable != NULL)
+ STORM_FREE(pBetTable);
+ if(pHashTable != NULL)
+ STORM_FREE(pHashTable);
+ if(pBlockTable != NULL)
+ STORM_FREE(pBlockTable);
+ if(pHiBlockTable != NULL)
+ STORM_FREE(pHiBlockTable);
+ return nError;
+}
diff --git a/dep/StormLib/src/SCompression.cpp b/dep/StormLib/src/SCompression.cpp
new file mode 100644
index 00000000000..5c7432248dc
--- /dev/null
+++ b/dep/StormLib/src/SCompression.cpp
@@ -0,0 +1,1135 @@
+/*****************************************************************************/
+/* SCompression.cpp Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* This module serves as a bridge between StormLib code and (de)compression */
+/* functions. All (de)compression calls go (and should only go) through this */
+/* module. No system headers should be included in this module to prevent */
+/* compile-time problems. */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 01.04.03 1.00 Lad The first version of SCompression.cpp */
+/* 19.11.03 1.01 Dan Big endian handling */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+//-----------------------------------------------------------------------------
+// Local structures
+
+// Information about the input and output buffers for pklib
+typedef struct
+{
+ char * pbInBuff; // Pointer to input data buffer
+ char * pbInBuffEnd; // End of the input buffer
+ char * pbOutBuff; // Pointer to output data buffer
+ char * pbOutBuffEnd; // Pointer to output data buffer
+} TDataInfo;
+
+// Prototype of the compression function
+// Function doesn't return an error. A success means that the size of compressed buffer
+// is lower than size of uncompressed buffer.
+typedef void (*COMPRESS)(
+ char * pbOutBuffer, // [out] Pointer to the buffer where the compressed data will be stored
+ int * pcbOutBuffer, // [in] Pointer to length of the buffer pointed by pbOutBuffer
+ // [out] Contains length of the compressed data
+ char * pbInBuffer, // [in] Pointer to the buffer with data to compress
+ int cbInBuffer, // [in] Length of the buffer pointer by pbInBuffer
+ int * pCmpType, // [in] Compression-method specific value. ADPCM Setups this for the following Huffman compression
+ int nCmpLevel); // [in] Compression specific value. ADPCM uses this. Should be set to zero.
+
+// Prototype of the decompression function
+// Returns 1 if success, 0 if failure
+typedef int (*DECOMPRESS)(
+ char * pbOutBuffer, // [out] Pointer to the buffer where to store decompressed data
+ int * pcbOutBuffer, // [in] Pointer to total size of the buffer pointed by pbOutBuffer
+ // [out] Contains length of the decompressed data
+ char * pbInBuffer, // [in] Pointer to data to be decompressed
+ int cbInBuffer); // [in] Length of the data to be decompressed
+
+// Table of compression functions
+typedef struct
+{
+ unsigned long uMask; // Compression mask
+ COMPRESS Compress; // Compression function
+} TCompressTable;
+
+// Table of decompression functions
+typedef struct
+{
+ unsigned long uMask; // Decompression bit
+ DECOMPRESS Decompress; // Decompression function
+} TDecompressTable;
+
+
+/*****************************************************************************/
+/* */
+/* Support for Huffman compression (0x01) */
+/* */
+/*****************************************************************************/
+
+// 1500F4C0
+void Compress_huff(
+ char * pbOutBuffer,
+ int * pcbOutBuffer,
+ char * pbInBuffer,
+ int cbInBuffer,
+ int * pCmpType,
+ int /* nCmpLevel */)
+{
+ THuffmannTree ht; // Huffmann tree for compression
+ TOutputStream os; // Output stream
+
+ // Initialize output stream
+ os.pbOutBuffer = (unsigned char *)pbOutBuffer;
+ os.cbOutSize = *pcbOutBuffer;
+ os.pbOutPos = (unsigned char *)pbOutBuffer;
+ os.dwBitBuff = 0;
+ os.nBits = 0;
+
+ // Initialize the Huffmann tree for compression
+ ht.InitTree(true);
+
+ *pcbOutBuffer = ht.DoCompression(&os, (unsigned char *)pbInBuffer, cbInBuffer, *pCmpType);
+
+ // The following code is not necessary to run, because it has no
+ // effect on the output data. It only clears the huffmann tree, but when
+ // the tree is on the stack, who cares ?
+// ht.UninitTree();
+}
+
+// 1500F5F0
+int Decompress_huff(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer)
+{
+ THuffmannTree ht;
+ TInputStream is;
+
+ // Initialize input stream
+ is.pbInBufferEnd = (unsigned char *)pbInBuffer + cbInBuffer;
+ is.pbInBuffer = (unsigned char *)pbInBuffer;
+ is.BitBuffer = 0;
+ is.BitCount = 0;
+
+ // Initialize the Huffmann tree for compression
+ ht.InitTree(false);
+ *pcbOutBuffer = ht.DoDecompression((unsigned char *)pbOutBuffer, *pcbOutBuffer, &is);
+ if(*pcbOutBuffer == 0)
+ return 0;
+
+ // The following code is not necessary to run, because it has no
+ // effect on the output data. It only clears the huffmann tree, but when
+ // the tree is on the stack, who cares ?
+// ht.UninitTree();
+ return 1;
+}
+
+/******************************************************************************/
+/* */
+/* Support for ZLIB compression (0x02) */
+/* */
+/******************************************************************************/
+
+void Compress_ZLIB(
+ char * pbOutBuffer,
+ int * pcbOutBuffer,
+ char * pbInBuffer,
+ int cbInBuffer,
+ int * /* pCmpType */,
+ int /* nCmpLevel */)
+{
+ z_stream z; // Stream information for zlib
+ int windowBits;
+ int nResult;
+
+ // Fill the stream structure for zlib
+ z.next_in = (Bytef *)pbInBuffer;
+ z.avail_in = (uInt)cbInBuffer;
+ z.total_in = cbInBuffer;
+ z.next_out = (Bytef *)pbOutBuffer;
+ z.avail_out = *pcbOutBuffer;
+ z.total_out = 0;
+ z.zalloc = NULL;
+ z.zfree = NULL;
+
+ // Determine the proper window bits (WoW.exe build 12694)
+ if(cbInBuffer <= 0x100)
+ windowBits = 8;
+ else if(cbInBuffer <= 0x200)
+ windowBits = 9;
+ else if(cbInBuffer <= 0x400)
+ windowBits = 10;
+ else if(cbInBuffer <= 0x800)
+ windowBits = 11;
+ else if(cbInBuffer <= 0x1000)
+ windowBits = 12;
+ else if(cbInBuffer <= 0x2000)
+ windowBits = 13;
+ else if(cbInBuffer <= 0x4000)
+ windowBits = 14;
+ else
+ windowBits = 15;
+
+ // Initialize the compression.
+ // Storm.dll uses zlib version 1.1.3
+ // Wow.exe uses zlib version 1.2.3
+ nResult = deflateInit2(&z,
+ 6, // Compression level used by WoW MPQs
+ Z_DEFLATED,
+ windowBits,
+ 8,
+ Z_DEFAULT_STRATEGY);
+ if(nResult == Z_OK)
+ {
+ // Call zlib to compress the data
+ nResult = deflate(&z, Z_FINISH);
+
+ if(nResult == Z_OK || nResult == Z_STREAM_END)
+ *pcbOutBuffer = z.total_out;
+
+ deflateEnd(&z);
+ }
+}
+
+int Decompress_ZLIB(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer)
+{
+ z_stream z; // Stream information for zlib
+ int nResult;
+
+ // Fill the stream structure for zlib
+ z.next_in = (Bytef *)pbInBuffer;
+ z.avail_in = (uInt)cbInBuffer;
+ z.total_in = cbInBuffer;
+ z.next_out = (Bytef *)pbOutBuffer;
+ z.avail_out = *pcbOutBuffer;
+ z.total_out = 0;
+ z.zalloc = NULL;
+ z.zfree = NULL;
+
+ // Initialize the decompression structure. Storm.dll uses zlib version 1.1.3
+ if((nResult = inflateInit(&z)) == 0)
+ {
+ // Call zlib to decompress the data
+ nResult = inflate(&z, Z_FINISH);
+ *pcbOutBuffer = z.total_out;
+ inflateEnd(&z);
+ }
+ return nResult;
+}
+
+/******************************************************************************/
+/* */
+/* Support functions for PKWARE Data Compression Library compression (0x08) */
+/* */
+/******************************************************************************/
+
+// Function loads data from the input buffer. Used by Pklib's "implode"
+// and "explode" function as user-defined callback
+// Returns number of bytes loaded
+//
+// char * buf - Pointer to a buffer where to store loaded data
+// unsigned int * size - Max. number of bytes to read
+// void * param - Custom pointer, parameter of implode/explode
+
+static unsigned int ReadInputData(char * buf, unsigned int * size, void * param)
+{
+ TDataInfo * pInfo = (TDataInfo *)param;
+ unsigned int nMaxAvail = (unsigned int)(pInfo->pbInBuffEnd - pInfo->pbInBuff);
+ unsigned int nToRead = *size;
+
+ // Check the case when not enough data available
+ if(nToRead > nMaxAvail)
+ nToRead = nMaxAvail;
+
+ // Load data and increment offsets
+ memcpy(buf, pInfo->pbInBuff, nToRead);
+ pInfo->pbInBuff += nToRead;
+ assert(pInfo->pbInBuff <= pInfo->pbInBuffEnd);
+ return nToRead;
+}
+
+// Function for store output data. Used by Pklib's "implode" and "explode"
+// as user-defined callback
+//
+// char * buf - Pointer to data to be written
+// unsigned int * size - Number of bytes to write
+// void * param - Custom pointer, parameter of implode/explode
+
+static void WriteOutputData(char * buf, unsigned int * size, void * param)
+{
+ TDataInfo * pInfo = (TDataInfo *)param;
+ unsigned int nMaxWrite = (unsigned int)(pInfo->pbOutBuffEnd - pInfo->pbOutBuff);
+ unsigned int nToWrite = *size;
+
+ // Check the case when not enough space in the output buffer
+ if(nToWrite > nMaxWrite)
+ nToWrite = nMaxWrite;
+
+ // Write output data and increments offsets
+ memcpy(pInfo->pbOutBuff, buf, nToWrite);
+ pInfo->pbOutBuff += nToWrite;
+ assert(pInfo->pbOutBuff <= pInfo->pbOutBuffEnd);
+}
+
+static void Compress_PKLIB(
+ char * pbOutBuffer,
+ int * pcbOutBuffer,
+ char * pbInBuffer,
+ int cbInBuffer,
+ int * /* pCmpType */,
+ int /* nCmpLevel */)
+{
+ TDataInfo Info; // Data information
+ char * work_buf = STORM_ALLOC(char, CMP_BUFFER_SIZE);// Pklib's work buffer
+ unsigned int dict_size; // Dictionary size
+ unsigned int ctype = CMP_BINARY; // Compression type
+
+ // Fill data information structure
+ memset(work_buf, 0, CMP_BUFFER_SIZE);
+ Info.pbInBuff = pbInBuffer;
+ Info.pbInBuffEnd = pbInBuffer + cbInBuffer;
+ Info.pbOutBuff = pbOutBuffer;
+ Info.pbOutBuffEnd = pbOutBuffer + *pcbOutBuffer;
+
+ //
+ // Set the dictionary size
+ //
+ // Diablo I ues fixed dictionary size of CMP_IMPLODE_DICT_SIZE3
+ // Starcraft uses the variable dictionary size based on algorithm below
+ //
+
+ if (cbInBuffer < 0x600)
+ dict_size = CMP_IMPLODE_DICT_SIZE1;
+ else if(0x600 <= cbInBuffer && cbInBuffer < 0xC00)
+ dict_size = CMP_IMPLODE_DICT_SIZE2;
+ else
+ dict_size = CMP_IMPLODE_DICT_SIZE3;
+
+ // Do the compression
+ if(implode(ReadInputData, WriteOutputData, work_buf, &Info, &ctype, &dict_size) == CMP_NO_ERROR)
+ *pcbOutBuffer = (int)(Info.pbOutBuff - pbOutBuffer);
+
+ STORM_FREE(work_buf);
+}
+
+static int Decompress_PKLIB(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer)
+{
+ TDataInfo Info; // Data information
+ char * work_buf = STORM_ALLOC(char, EXP_BUFFER_SIZE);// Pklib's work buffer
+
+ // Fill data information structure
+ memset(work_buf, 0, EXP_BUFFER_SIZE);
+ Info.pbInBuff = pbInBuffer;
+ Info.pbInBuffEnd = pbInBuffer + cbInBuffer;
+ Info.pbOutBuff = pbOutBuffer;
+ Info.pbOutBuffEnd = pbOutBuffer + *pcbOutBuffer;
+
+ // Do the decompression
+ explode(ReadInputData, WriteOutputData, work_buf, &Info);
+
+ // If PKLIB is unable to decompress the data, return 0;
+ if(Info.pbOutBuff == pbOutBuffer)
+ return 0;
+
+ // Give away the number of decompressed bytes
+ *pcbOutBuffer = (int)(Info.pbOutBuff - pbOutBuffer);
+ STORM_FREE(work_buf);
+ return 1;
+}
+
+/******************************************************************************/
+/* */
+/* Support for Bzip2 compression (0x10) */
+/* */
+/******************************************************************************/
+
+static void Compress_BZIP2(
+ char * pbOutBuffer,
+ int * pcbOutBuffer,
+ char * pbInBuffer,
+ int cbInBuffer,
+ int * /* pCmpType */,
+ int /* nCmpLevel */)
+{
+ bz_stream strm;
+ int blockSize100k = 9;
+ int workFactor = 30;
+ int bzError;
+
+ // Initialize the BZIP2 compression
+ strm.bzalloc = NULL;
+ strm.bzfree = NULL;
+
+ // Blizzard uses 9 as blockSize100k, (0x30 as workFactor)
+ // Last checked on Starcraft II
+ if(BZ2_bzCompressInit(&strm, blockSize100k, 0, workFactor) == BZ_OK)
+ {
+ strm.next_in = pbInBuffer;
+ strm.avail_in = cbInBuffer;
+ strm.next_out = pbOutBuffer;
+ strm.avail_out = *pcbOutBuffer;
+
+ // Perform the compression
+ for(;;)
+ {
+ bzError = BZ2_bzCompress(&strm, (strm.avail_in != 0) ? BZ_RUN : BZ_FINISH);
+ if(bzError == BZ_STREAM_END || bzError < 0)
+ break;
+ }
+
+ // Put the stream into idle state
+ BZ2_bzCompressEnd(&strm);
+
+ if(bzError > 0)
+ *pcbOutBuffer = strm.total_out_lo32;
+ }
+}
+
+static int Decompress_BZIP2(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer)
+{
+ bz_stream strm;
+ int nResult = BZ_OK;
+
+ // Initialize the BZIP2 decompression
+ strm.bzalloc = NULL;
+ strm.bzfree = NULL;
+ if(BZ2_bzDecompressInit(&strm, 0, 0) == BZ_OK)
+ {
+ strm.next_in = pbInBuffer;
+ strm.avail_in = cbInBuffer;
+ strm.next_out = pbOutBuffer;
+ strm.avail_out = *pcbOutBuffer;
+
+ // Perform the decompression
+ while(nResult != BZ_STREAM_END)
+ {
+ nResult = BZ2_bzDecompress(&strm);
+
+ // If any error there, break the loop
+ if(nResult < BZ_OK)
+ break;
+ }
+
+ // Put the stream into idle state
+ BZ2_bzDecompressEnd(&strm);
+
+ // If all succeeded, set the number of output bytes
+ if(nResult >= BZ_OK)
+ {
+ *pcbOutBuffer = strm.total_out_lo32;
+ return 1;
+ }
+ }
+
+ // Something failed, so set number of output bytes to zero
+ *pcbOutBuffer = 0;
+ return 1;
+}
+
+/******************************************************************************/
+/* */
+/* Support functions for LZMA compression (0x12) */
+/* */
+/******************************************************************************/
+
+#define LZMA_HEADER_SIZE (1 + LZMA_PROPS_SIZE + 8)
+
+static SRes LZMA_Callback_Progress(void * /* p */, UInt64 /* inSize */, UInt64 /* outSize */)
+{
+ return SZ_OK;
+}
+
+static void * LZMA_Callback_Alloc(void *p, size_t size)
+{
+ p = p;
+ return STORM_ALLOC(BYTE, size);
+}
+
+/* address can be 0 */
+static void LZMA_Callback_Free(void *p, void *address)
+{
+ p = p;
+ if(address != NULL)
+ STORM_FREE(address);
+}
+
+//
+// Note: So far, I haven't seen any files compressed by LZMA.
+// This code haven't been verified against code ripped from Starcraft II Beta,
+// but we know that Starcraft LZMA decompression code is able to decompress
+// the data compressed by StormLib.
+//
+
+/*static */ void Compress_LZMA(
+ char * pbOutBuffer,
+ int * pcbOutBuffer,
+ char * pbInBuffer,
+ int cbInBuffer,
+ int * /* pCmpType */,
+ int /* nCmpLevel */)
+{
+ ICompressProgress Progress;
+ CLzmaEncProps props;
+ ISzAlloc SzAlloc;
+ Byte * destBuffer;
+ SizeT destLen = *pcbOutBuffer;
+ SizeT srcLen = cbInBuffer;
+ Byte encodedProps[LZMA_PROPS_SIZE];
+ size_t encodedPropsSize = LZMA_PROPS_SIZE;
+ SRes nResult;
+
+ // Fill the callbacks in structures
+ Progress.Progress = LZMA_Callback_Progress;
+ SzAlloc.Alloc = LZMA_Callback_Alloc;
+ SzAlloc.Free = LZMA_Callback_Free;
+
+ // Initialize properties
+ LzmaEncProps_Init(&props);
+
+ // Perform compression
+ destBuffer = (Byte *)pbOutBuffer + LZMA_HEADER_SIZE;
+ destLen = *pcbOutBuffer - LZMA_HEADER_SIZE;
+ nResult = LzmaEncode(destBuffer,
+ &destLen,
+ (Byte *)pbInBuffer,
+ srcLen,
+ &props,
+ encodedProps,
+ &encodedPropsSize,
+ 0,
+ &Progress,
+ &SzAlloc,
+ &SzAlloc);
+ if(nResult != SZ_OK)
+ return;
+
+ // If we failed to compress the data
+ if(destLen >= (SizeT)(*pcbOutBuffer - LZMA_HEADER_SIZE))
+ return;
+
+ // Write "useFilter" variable. Blizzard MPQ must not use filter.
+ *pbOutBuffer++ = 0;
+
+ // Copy the encoded properties to the output buffer
+ memcpy(pbOutBuffer, encodedProps, encodedPropsSize);
+ pbOutBuffer += encodedPropsSize;
+
+ // Copy the size of the data
+ *pbOutBuffer++ = (unsigned char)(srcLen >> 0x00);
+ *pbOutBuffer++ = (unsigned char)(srcLen >> 0x08);
+ *pbOutBuffer++ = (unsigned char)(srcLen >> 0x10);
+ *pbOutBuffer++ = (unsigned char)(srcLen >> 0x18);
+ *pbOutBuffer++ = 0;
+ *pbOutBuffer++ = 0;
+ *pbOutBuffer++ = 0;
+ *pbOutBuffer++ = 0;
+
+ // Give the size of the data to the caller
+ *pcbOutBuffer = (unsigned int)(destLen + LZMA_HEADER_SIZE);
+}
+
+static int Decompress_LZMA(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer)
+{
+ ELzmaStatus LzmaStatus;
+ ISzAlloc SzAlloc;
+ Byte * destBuffer = (Byte *)pbOutBuffer;
+ Byte * srcBuffer = (Byte *)pbInBuffer;
+ SizeT destLen = *pcbOutBuffer;
+ SizeT srcLen = cbInBuffer;
+ SRes nResult;
+
+ // There must be at least 0x0E bytes in the buffer
+ if(srcLen <= LZMA_HEADER_SIZE)
+ return 0;
+
+ // We only accept blocks that have no filter used
+ if(*srcBuffer != 0)
+ return 0;
+
+ // Fill the callbacks in structures
+ SzAlloc.Alloc = LZMA_Callback_Alloc;
+ SzAlloc.Free = LZMA_Callback_Free;
+
+ // Perform compression
+ srcLen = cbInBuffer - LZMA_HEADER_SIZE;
+ nResult = LzmaDecode(destBuffer,
+ &destLen,
+ srcBuffer + LZMA_HEADER_SIZE,
+ &srcLen,
+ srcBuffer + 1,
+ LZMA_PROPS_SIZE,
+ LZMA_FINISH_END,
+ &LzmaStatus,
+ &SzAlloc);
+ if(nResult != SZ_OK)
+ return 0;
+
+ *pcbOutBuffer = (unsigned int)destLen;
+ return 1;
+}
+
+/******************************************************************************/
+/* */
+/* Support functions for SPARSE compression (0x20) */
+/* */
+/******************************************************************************/
+
+void Compress_SPARSE(
+ char * pbOutBuffer,
+ int * pcbOutBuffer,
+ char * pbInBuffer,
+ int cbInBuffer,
+ int * /* pCmpType */,
+ int /* nCmpLevel */)
+{
+ CompressSparse((unsigned char *)pbOutBuffer, pcbOutBuffer, (unsigned char *)pbInBuffer, cbInBuffer);
+}
+
+int Decompress_SPARSE(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer)
+{
+ return DecompressSparse((unsigned char *)pbOutBuffer, pcbOutBuffer, (unsigned char *)pbInBuffer, cbInBuffer);
+}
+
+/******************************************************************************/
+/* */
+/* Support for ADPCM mono compression (0x40) */
+/* */
+/******************************************************************************/
+
+static void Compress_ADPCM_mono(
+ char * pbOutBuffer,
+ int * pcbOutBuffer,
+ char * pbInBuffer,
+ int cbInBuffer,
+ int * pCmpType,
+ int nCmpLevel)
+{
+ // Prepare the compression level for Huffmann compression,
+ // which will be called as next step
+ if(0 < nCmpLevel && nCmpLevel <= 2)
+ {
+ nCmpLevel = 4;
+ *pCmpType = 6;
+ }
+ else if(nCmpLevel == 3)
+ {
+ nCmpLevel = 6;
+ *pCmpType = 8;
+ }
+ else
+ {
+ nCmpLevel = 5;
+ *pCmpType = 7;
+ }
+ *pcbOutBuffer = CompressADPCM((unsigned char *)pbOutBuffer, *pcbOutBuffer, (short *)pbInBuffer, cbInBuffer, 1, nCmpLevel);
+}
+
+static int Decompress_ADPCM_mono(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer)
+{
+ *pcbOutBuffer = DecompressADPCM((unsigned char *)pbOutBuffer, *pcbOutBuffer, (unsigned char *)pbInBuffer, cbInBuffer, 1);
+ return 1;
+}
+
+/******************************************************************************/
+/* */
+/* Support for ADPCM stereo compression (0x80) */
+/* */
+/******************************************************************************/
+
+static void Compress_ADPCM_stereo(
+ char * pbOutBuffer,
+ int * pcbOutBuffer,
+ char * pbInBuffer,
+ int cbInBuffer,
+ int * pCmpType,
+ int nCmpLevel)
+{
+ // Prepare the compression level for Huffmann compression,
+ // which will be called as next step
+ if(0 < nCmpLevel && nCmpLevel <= 2)
+ {
+ nCmpLevel = 4;
+ *pCmpType = 6;
+ }
+ else if(nCmpLevel == 3)
+ {
+ nCmpLevel = 6;
+ *pCmpType = 8;
+ }
+ else
+ {
+ nCmpLevel = 5;
+ *pCmpType = 7;
+ }
+ *pcbOutBuffer = CompressADPCM((unsigned char *)pbOutBuffer, *pcbOutBuffer, (short *)pbInBuffer, cbInBuffer, 2, nCmpLevel);
+}
+
+static int Decompress_ADPCM_stereo(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer)
+{
+ *pcbOutBuffer = DecompressADPCM((unsigned char *)pbOutBuffer, *pcbOutBuffer, (unsigned char *)pbInBuffer, cbInBuffer, 2);
+ return 1;
+}
+
+/*****************************************************************************/
+/* */
+/* SCompImplode */
+/* */
+/*****************************************************************************/
+
+int WINAPI SCompImplode(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer)
+{
+ int cbOutBuffer = *pcbOutBuffer;
+
+ // Check for valid parameters
+ if(!pcbOutBuffer || *pcbOutBuffer < cbInBuffer || !pbOutBuffer || !pbInBuffer)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ // Perform the compression
+ Compress_PKLIB(pbOutBuffer, &cbOutBuffer, pbInBuffer, cbInBuffer, NULL, 0);
+
+ // If the compression was unsuccessful, copy the data as-is
+ if(cbOutBuffer >= *pcbOutBuffer)
+ {
+ memcpy(pbOutBuffer, pbInBuffer, cbInBuffer);
+ cbOutBuffer = *pcbOutBuffer;
+ }
+
+ *pcbOutBuffer = cbOutBuffer;
+ return 1;
+}
+
+/*****************************************************************************/
+/* */
+/* SCompExplode */
+/* */
+/*****************************************************************************/
+
+int WINAPI SCompExplode(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer)
+{
+ int cbOutBuffer = *pcbOutBuffer;
+
+ // Check for valid parameters
+ if(!pcbOutBuffer || *pcbOutBuffer < cbInBuffer || !pbOutBuffer || !pbInBuffer)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ // If the input length is the same as output length, do nothing.
+ if(cbInBuffer == cbOutBuffer)
+ {
+ // If the buffers are equal, don't copy anything.
+ if(pbInBuffer == pbOutBuffer)
+ return 1;
+
+ memcpy(pbOutBuffer, pbInBuffer, cbInBuffer);
+ return 1;
+ }
+
+ // Perform decompression
+ if(!Decompress_PKLIB(pbOutBuffer, &cbOutBuffer, pbInBuffer, cbInBuffer))
+ {
+ SetLastError(ERROR_FILE_CORRUPT);
+ return false;
+ }
+
+ *pcbOutBuffer = cbOutBuffer;
+ return 1;
+}
+
+/*****************************************************************************/
+/* */
+/* SCompCompress */
+/* */
+/*****************************************************************************/
+
+// This table contains compress functions which can be applied to
+// uncompressed data. Each bit means the corresponding
+// compression method/function must be applied.
+//
+// WAVes compression Data compression
+// ------------------ -------------------
+// 1st sector - 0x08 0x08 (D, HF, W2, SC, D2)
+// Next sectors - 0x81 0x02 (W3)
+
+static TCompressTable cmp_table[] =
+{
+ {MPQ_COMPRESSION_SPARSE, Compress_SPARSE}, // Sparse compression
+ {MPQ_COMPRESSION_ADPCM_MONO, Compress_ADPCM_mono}, // IMA ADPCM mono compression
+ {MPQ_COMPRESSION_ADPCM_STEREO, Compress_ADPCM_stereo}, // IMA ADPCM stereo compression
+ {MPQ_COMPRESSION_HUFFMANN, Compress_huff}, // Huffmann compression
+ {MPQ_COMPRESSION_ZLIB, Compress_ZLIB}, // Compression with the "zlib" library
+ {MPQ_COMPRESSION_PKWARE, Compress_PKLIB}, // Compression with Pkware DCL
+ {MPQ_COMPRESSION_BZIP2, Compress_BZIP2} // Compression Bzip2 library
+};
+
+int WINAPI SCompCompress(
+ char * pbOutBuffer,
+ int * pcbOutBuffer,
+ char * pbInBuffer,
+ int cbInBuffer,
+ unsigned uCompressionMask,
+ int nCmpType,
+ int nCmpLevel)
+{
+ COMPRESS CompressFuncArray[0x10]; // Array of compression functions, applied sequentially
+ unsigned char CompressByte[0x10]; // CompressByte for each method in the CompressFuncArray array
+ char * pbWorkBuffer = NULL; // Temporary storage for decompressed data
+ char * pbOutput = pbOutBuffer; // Current output buffer
+ char * pbInput = pbInBuffer; // Current input buffer
+ int nCompressCount = 0;
+ int nCompressIndex = 0;
+ int nAtLeastOneCompressionDone = 0;
+ int cbOutBuffer = 0;
+ int cbInLength = cbInBuffer;
+ int nResult = 1;
+
+ // Check for valid parameters
+ if(!pcbOutBuffer || *pcbOutBuffer < cbInBuffer || !pbOutBuffer || !pbInBuffer)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ // Zero input length brings zero output length
+ if(cbInBuffer == 0)
+ {
+ *pcbOutBuffer = 0;
+ return true;
+ }
+
+ // Setup the compression function array
+ if(uCompressionMask == MPQ_COMPRESSION_LZMA)
+ {
+ CompressFuncArray[0] = Compress_LZMA;
+ CompressByte[0] = (char)uCompressionMask;
+ nCompressCount = 1;
+ }
+ else
+ {
+ // Fill the compressions array
+ for(size_t i = 0; i < (sizeof(cmp_table) / sizeof(TCompressTable)); i++)
+ {
+ // If the mask agrees, insert the compression function to the array
+ if(uCompressionMask & cmp_table[i].uMask)
+ {
+ CompressFuncArray[nCompressCount] = cmp_table[i].Compress;
+ CompressByte[nCompressCount] = (unsigned char)cmp_table[i].uMask;
+ uCompressionMask &= ~cmp_table[i].uMask;
+ nCompressCount++;
+ }
+ }
+
+ // If at least one of the compressions remaing unknown, return an error
+ if(uCompressionMask != 0)
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return 0;
+ }
+ }
+
+ // If there is at least one compression, do it
+ if(nCompressCount > 0)
+ {
+ // If we need to do more than 1 compression, allocate intermediate buffer
+ if(nCompressCount > 1)
+ {
+ pbWorkBuffer = STORM_ALLOC(char, *pcbOutBuffer);
+ if(pbWorkBuffer == NULL)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return 0;
+ }
+ }
+
+ // Get the current compression index
+ nCompressIndex = nCompressCount - 1;
+
+ // Perform all compressions in the array
+ for(int i = 0; i < nCompressCount; i++)
+ {
+ // Choose the proper output buffer
+ pbOutput = (nCompressIndex & 1) ? pbWorkBuffer : pbOutBuffer;
+ nCompressIndex--;
+
+ // Perform the (next) compression
+ // Note that if the compression method is unable to compress the input data block
+ // by at least 2 bytes, we consider it as failure and will use source data instead
+ cbOutBuffer = *pcbOutBuffer - 1;
+ CompressFuncArray[i](pbOutput + 1, &cbOutBuffer, pbInput, cbInLength, &nCmpType, nCmpLevel);
+
+ // If the compression failed, we copy the input buffer as-is.
+ // Note that there is one extra byte at the end of the intermediate buffer, so it should be OK
+ if(cbOutBuffer > (cbInLength - 2))
+ {
+ memcpy(pbOutput + nAtLeastOneCompressionDone, pbInput, cbInLength);
+ cbOutBuffer = cbInLength;
+ }
+ else
+ {
+ // Remember that we have done at least one compression
+ nAtLeastOneCompressionDone = 1;
+ uCompressionMask |= CompressByte[i];
+ }
+
+ // Now point input buffer to the output buffer
+ pbInput = pbOutput + nAtLeastOneCompressionDone;
+ cbInLength = cbOutBuffer;
+ }
+
+ // If at least one compression succeeded, put the compression
+ // mask to the begin of the output buffer
+ if(nAtLeastOneCompressionDone)
+ *pbOutBuffer = (char)uCompressionMask;
+ *pcbOutBuffer = cbOutBuffer + nAtLeastOneCompressionDone;
+ }
+ else
+ {
+ memcpy(pbOutBuffer, pbInBuffer, cbInBuffer);
+ *pcbOutBuffer = cbInBuffer;
+ }
+
+ // Cleanup and return
+ if(pbWorkBuffer != NULL)
+ STORM_FREE(pbWorkBuffer);
+ return nResult;
+}
+
+/*****************************************************************************/
+/* */
+/* SCompDecompress */
+/* */
+/*****************************************************************************/
+
+// This table contains decompress functions which can be applied to
+// uncompressed data. The compression mask is stored in the first byte
+// of compressed data
+static TDecompressTable dcmp_table[] =
+{
+ {MPQ_COMPRESSION_BZIP2, Decompress_BZIP2}, // Decompression with Bzip2 library
+ {MPQ_COMPRESSION_PKWARE, Decompress_PKLIB}, // Decompression with Pkware Data Compression Library
+ {MPQ_COMPRESSION_ZLIB, Decompress_ZLIB}, // Decompression with the "zlib" library
+ {MPQ_COMPRESSION_HUFFMANN, Decompress_huff}, // Huffmann decompression
+ {MPQ_COMPRESSION_ADPCM_STEREO, Decompress_ADPCM_stereo}, // IMA ADPCM stereo decompression
+ {MPQ_COMPRESSION_ADPCM_MONO, Decompress_ADPCM_mono}, // IMA ADPCM mono decompression
+ {MPQ_COMPRESSION_SPARSE, Decompress_SPARSE} // Sparse decompression
+};
+
+int WINAPI SCompDecompress(
+ char * pbOutBuffer,
+ int * pcbOutBuffer,
+ char * pbInBuffer,
+ int cbInBuffer)
+{
+ char * pbWorkBuffer = NULL; // Temporary storage for decompressed data
+ char * pbOutput = pbOutBuffer; // Where to store decompressed data
+ char * pbInput; // Where to store decompressed data
+ unsigned uCompressionMask; // Decompressions applied to the data
+ unsigned uCompressionCopy; // Decompressions applied to the data
+ int cbOutBuffer = *pcbOutBuffer; // Current size of the output buffer
+ int cbInLength; // Current size of the input buffer
+ int nCompressCount = 0; // Number of compressions to be applied
+ int nCompressIndex = 0;
+ int nResult = 1;
+
+ // Verify buffer sizes
+ if(cbOutBuffer < cbInBuffer || cbInBuffer < 1)
+ return 0;
+
+ // If the input length is the same as output length, do nothing.
+ if(cbOutBuffer == cbInBuffer)
+ {
+ // If the buffers are equal, don't copy anything.
+ if(pbInBuffer != pbOutBuffer)
+ memcpy(pbOutBuffer, pbInBuffer, cbInBuffer);
+ return 1;
+ }
+
+ // Get applied compression types and decrement data length
+ uCompressionMask = uCompressionCopy = (unsigned char)*pbInBuffer++;
+ cbInBuffer--;
+
+ // Get current compressed data and length of it
+ pbInput = pbInBuffer;
+ cbInLength = cbInBuffer;
+
+ // This compression function doesn't support LZMA
+ assert(uCompressionMask != MPQ_COMPRESSION_LZMA);
+
+ // Parse the compression mask
+ for(size_t i = 0; i < (sizeof(dcmp_table) / sizeof(TDecompressTable)); i++)
+ {
+ // If the mask agrees, insert the compression function to the array
+ if(uCompressionMask & dcmp_table[i].uMask)
+ {
+ uCompressionCopy &= ~dcmp_table[i].uMask;
+ nCompressCount++;
+ }
+ }
+
+ // If at least one of the compressions remaing unknown, return an error
+ if(nCompressCount == 0 || uCompressionCopy != 0)
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return 0;
+ }
+
+ // If there is more than one compression, we have to allocate extra buffer
+ if(nCompressCount > 1)
+ {
+ pbWorkBuffer = STORM_ALLOC(char, cbOutBuffer);
+ if(pbWorkBuffer == NULL)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return 0;
+ }
+ }
+
+ // Get the current compression index
+ nCompressIndex = nCompressCount - 1;
+
+ // Apply all decompressions
+ for(size_t i = 0; i < (sizeof(dcmp_table) / sizeof(TDecompressTable)); i++)
+ {
+ // Perform the (next) decompression
+ if(uCompressionMask & dcmp_table[i].uMask)
+ {
+ // Get the correct output buffer
+ pbOutput = (nCompressIndex & 1) ? pbWorkBuffer : pbOutBuffer;
+ nCompressIndex--;
+
+ // Perform the decompression
+ cbOutBuffer = *pcbOutBuffer;
+ nResult = dcmp_table[i].Decompress(pbOutput, &cbOutBuffer, pbInput, cbInLength);
+ if(nResult == 0 || cbOutBuffer == 0)
+ {
+ SetLastError(ERROR_FILE_CORRUPT);
+ nResult = 0;
+ break;
+ }
+
+ // Switch buffers
+ cbInLength = cbOutBuffer;
+ pbInput = pbOutput;
+ }
+ }
+
+ // Put the length of the decompressed data to the output buffer
+ *pcbOutBuffer = cbOutBuffer;
+
+ // Cleanup and return
+ if(pbWorkBuffer != NULL)
+ STORM_FREE(pbWorkBuffer);
+ return nResult;
+}
+
+int WINAPI SCompDecompress2(
+ char * pbOutBuffer,
+ int * pcbOutBuffer,
+ char * pbInBuffer,
+ int cbInBuffer)
+{
+ DECOMPRESS pfnDecompress1 = NULL;
+ DECOMPRESS pfnDecompress2 = NULL;
+ char * pbWorkBuffer = pbOutBuffer;
+ int cbWorkBuffer = *pcbOutBuffer;
+ int nResult;
+ char CompressionMethod;
+
+ // Verify buffer sizes
+ if(*pcbOutBuffer < cbInBuffer || cbInBuffer < 1)
+ return 0;
+
+ // If the outputbuffer is as big as input buffer, just copy the block
+ if(*pcbOutBuffer == cbInBuffer)
+ {
+ if(pbOutBuffer != pbInBuffer)
+ memcpy(pbOutBuffer, pbInBuffer, cbInBuffer);
+ return 1;
+ }
+
+ // Get the compression methods
+ CompressionMethod = *pbInBuffer++;
+ cbInBuffer--;
+
+ // We only recognize a fixed set of compression methods
+ switch((unsigned char)CompressionMethod)
+ {
+ case MPQ_COMPRESSION_ZLIB:
+ pfnDecompress1 = Decompress_ZLIB;
+ break;
+
+ case MPQ_COMPRESSION_PKWARE:
+ pfnDecompress1 = Decompress_PKLIB;
+ break;
+
+ case MPQ_COMPRESSION_BZIP2:
+ pfnDecompress1 = Decompress_BZIP2;
+ break;
+
+ case MPQ_COMPRESSION_LZMA:
+ pfnDecompress1 = Decompress_LZMA;
+ break;
+
+ case MPQ_COMPRESSION_SPARSE:
+ pfnDecompress1 = Decompress_SPARSE;
+ break;
+
+ case (MPQ_COMPRESSION_SPARSE | MPQ_COMPRESSION_ZLIB):
+ pfnDecompress1 = Decompress_ZLIB;
+ pfnDecompress2 = Decompress_SPARSE;
+ break;
+
+ case (MPQ_COMPRESSION_SPARSE | MPQ_COMPRESSION_BZIP2):
+ pfnDecompress1 = Decompress_BZIP2;
+ pfnDecompress2 = Decompress_SPARSE;
+ break;
+
+ //
+ // Note: Any combination including MPQ_COMPRESSION_ADPCM_MONO,
+ // MPQ_COMPRESSION_ADPCM_STEREO or MPQ_COMPRESSION_HUFFMANN
+ // is not supported by newer MPQs.
+ //
+
+ default:
+ SetLastError(ERROR_FILE_CORRUPT);
+ return 0;
+ }
+
+ // If we have to use two decompressions, allocate temporary buffer
+ if(pfnDecompress2 != NULL)
+ {
+ pbWorkBuffer = STORM_ALLOC(char, *pcbOutBuffer);
+ if(pbWorkBuffer == NULL)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return 0;
+ }
+ }
+
+ // Apply the first decompression method
+ nResult = pfnDecompress1(pbWorkBuffer, &cbWorkBuffer, pbInBuffer, cbInBuffer);
+
+ // Apply the second decompression method, if any
+ if(pfnDecompress2 != NULL && nResult != 0)
+ {
+ cbInBuffer = cbWorkBuffer;
+ cbWorkBuffer = *pcbOutBuffer;
+ nResult = pfnDecompress2(pbOutBuffer, &cbWorkBuffer, pbWorkBuffer, cbInBuffer);
+ }
+
+ // Supply the output buffer size
+ *pcbOutBuffer = cbWorkBuffer;
+
+ // Free temporary buffer
+ if(pbWorkBuffer != pbOutBuffer)
+ STORM_FREE(pbWorkBuffer);
+
+ if(nResult == 0)
+ SetLastError(ERROR_FILE_CORRUPT);
+ return nResult;
+}
diff --git a/dep/StormLib/src/SFileAddFile.cpp b/dep/StormLib/src/SFileAddFile.cpp
new file mode 100644
index 00000000000..dda47370bd1
--- /dev/null
+++ b/dep/StormLib/src/SFileAddFile.cpp
@@ -0,0 +1,1286 @@
+/*****************************************************************************/
+/* SFileAddFile.cpp Copyright (c) Ladislav Zezula 2010 */
+/*---------------------------------------------------------------------------*/
+/* MPQ Editing functions */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 27.03.10 1.00 Lad Splitted from SFileCreateArchiveEx.cpp */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+//-----------------------------------------------------------------------------
+// Local structures
+
+#define FILE_SIGNATURE_RIFF 0x46464952
+#define FILE_SIGNATURE_WAVE 0x45564157
+#define FILE_SIGNATURE_FMT 0x20746D66
+#define AUDIO_FORMAT_PCM 1
+
+typedef struct _WAVE_FILE_HEADER
+{
+ DWORD dwChunkId; // 0x52494646 ("RIFF")
+ DWORD dwChunkSize; // Size of that chunk, in bytes
+ DWORD dwFormat; // Must be 0x57415645 ("WAVE")
+
+ // Format sub-chunk
+ DWORD dwSubChunk1Id; // 0x666d7420 ("fmt ")
+ DWORD dwSubChunk1Size; // 0x16 for PCM
+ USHORT wAudioFormat; // 1 = PCM. Other value means some sort of compression
+ USHORT wChannels; // Number of channels
+ DWORD dwSampleRate; // 8000, 44100, etc.
+ DWORD dwBytesRate; // SampleRate * NumChannels * BitsPerSample/8
+ USHORT wBlockAlign; // NumChannels * BitsPerSample/8
+ USHORT wBitsPerSample; // 8 bits = 8, 16 bits = 16, etc.
+
+ // Followed by "data" sub-chunk (we don't care)
+} WAVE_FILE_HEADER, *PWAVE_FILE_HEADER;
+
+//-----------------------------------------------------------------------------
+// Local variables
+
+// Data compression for SFileAddFile
+// Kept here for compatibility with code that was created with StormLib version < 6.50
+static DWORD DefaultDataCompression = MPQ_COMPRESSION_PKWARE;
+
+static SFILE_ADDFILE_CALLBACK AddFileCB = NULL;
+static void * pvUserData = NULL;
+
+//-----------------------------------------------------------------------------
+// MPQ write data functions
+
+#define LOSSY_COMPRESSION_MASK (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN)
+
+static int IsWaveFile(
+ LPBYTE pbFileData,
+ DWORD cbFileData,
+ LPDWORD pdwChannels)
+{
+ PWAVE_FILE_HEADER pWaveHdr = (PWAVE_FILE_HEADER)pbFileData;
+
+ if(cbFileData > sizeof(WAVE_FILE_HEADER))
+ {
+ if(pWaveHdr->dwChunkId == FILE_SIGNATURE_RIFF && pWaveHdr->dwFormat == FILE_SIGNATURE_WAVE)
+ {
+ if(pWaveHdr->dwSubChunk1Id == FILE_SIGNATURE_FMT && pWaveHdr->wAudioFormat == AUDIO_FORMAT_PCM)
+ {
+ *pdwChannels = pWaveHdr->wChannels;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+static int WriteDataToMpqFile(
+ TMPQArchive * ha,
+ TMPQFile * hf,
+ LPBYTE pbFileData,
+ DWORD dwDataSize,
+ DWORD dwCompression)
+{
+ TFileEntry * pFileEntry = hf->pFileEntry;
+ ULONGLONG ByteOffset;
+ LPBYTE pbCompressed = NULL; // Compressed (target) data
+ LPBYTE pbToWrite = NULL; // Data to write to the file
+ int nCompressionLevel = -1; // ADPCM compression level (only used for wave files)
+ int nError = ERROR_SUCCESS;
+
+ // If the caller wants ADPCM compression, we will set wave compression level to 4,
+ // which corresponds to medium quality
+ if(dwCompression & LOSSY_COMPRESSION_MASK)
+ nCompressionLevel = 4;
+
+ // Make sure that the caller won't overrun the previously initiated file size
+ assert(hf->dwFilePos + dwDataSize <= pFileEntry->dwFileSize);
+ assert(hf->dwSectorCount != 0);
+ assert(hf->pbFileSector != NULL);
+ if((hf->dwFilePos + dwDataSize) > pFileEntry->dwFileSize)
+ return ERROR_DISK_FULL;
+ pbToWrite = hf->pbFileSector;
+
+ // Now write all data to the file sector buffer
+ if(nError == ERROR_SUCCESS)
+ {
+ DWORD dwBytesInSector = hf->dwFilePos % hf->dwSectorSize;
+ DWORD dwSectorIndex = hf->dwFilePos / hf->dwSectorSize;
+ DWORD dwBytesToCopy;
+
+ // Process all data.
+ while(dwDataSize != 0)
+ {
+ dwBytesToCopy = dwDataSize;
+
+ // Check for sector overflow
+ if(dwBytesToCopy > (hf->dwSectorSize - dwBytesInSector))
+ dwBytesToCopy = (hf->dwSectorSize - dwBytesInSector);
+
+ // Copy the data to the file sector
+ memcpy(hf->pbFileSector + dwBytesInSector, pbFileData, dwBytesToCopy);
+ dwBytesInSector += dwBytesToCopy;
+ pbFileData += dwBytesToCopy;
+ dwDataSize -= dwBytesToCopy;
+
+ // Update the file position
+ hf->dwFilePos += dwBytesToCopy;
+
+ // If the current sector is full, or if the file is already full,
+ // then write the data to the MPQ
+ if(dwBytesInSector >= hf->dwSectorSize || hf->dwFilePos >= pFileEntry->dwFileSize)
+ {
+ // Set the position in the file
+ ByteOffset = hf->RawFilePos + pFileEntry->dwCmpSize;
+
+ // Update CRC32 and MD5 of the file
+ md5_process((hash_state *)hf->hctx, hf->pbFileSector, dwBytesInSector);
+ hf->dwCrc32 = crc32(hf->dwCrc32, hf->pbFileSector, dwBytesInSector);
+
+ // Compress the file sector, if needed
+ if(pFileEntry->dwFlags & MPQ_FILE_COMPRESSED)
+ {
+ int nOutBuffer = (int)dwBytesInSector;
+ int nInBuffer = (int)dwBytesInSector;
+
+ // If the file is compressed, allocate buffer for the compressed data.
+ // Note that we allocate buffer that is a bit longer than sector size,
+ // for case if the compression method performs a buffer overrun
+ if(pbCompressed == NULL)
+ {
+ pbToWrite = pbCompressed = STORM_ALLOC(BYTE, hf->dwSectorSize + 0x100);
+ if(pbCompressed == NULL)
+ {
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+ }
+
+ //
+ // Note that both SCompImplode and SCompCompress give original buffer,
+ // if they are unable to comperss the data.
+ //
+
+ if(pFileEntry->dwFlags & MPQ_FILE_IMPLODE)
+ {
+ SCompImplode((char *)pbCompressed,
+ &nOutBuffer,
+ (char *)hf->pbFileSector,
+ nInBuffer);
+ }
+
+ if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS)
+ {
+ SCompCompress((char *)pbCompressed,
+ &nOutBuffer,
+ (char *)hf->pbFileSector,
+ nInBuffer,
+ (unsigned)dwCompression,
+ 0,
+ nCompressionLevel);
+ }
+
+ // Update sector positions
+ dwBytesInSector = nOutBuffer;
+ if(hf->SectorOffsets != NULL)
+ hf->SectorOffsets[dwSectorIndex+1] = hf->SectorOffsets[dwSectorIndex] + dwBytesInSector;
+
+ // We have to calculate sector CRC, if enabled
+ if(hf->SectorChksums != NULL)
+ hf->SectorChksums[dwSectorIndex] = adler32(0, pbCompressed, nOutBuffer);
+ }
+
+ // Encrypt the sector, if necessary
+ if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
+ {
+ BSWAP_ARRAY32_UNSIGNED(pbToWrite, dwBytesInSector);
+ EncryptMpqBlock(pbToWrite, dwBytesInSector, hf->dwFileKey + dwSectorIndex);
+ BSWAP_ARRAY32_UNSIGNED(pbToWrite, dwBytesInSector);
+ }
+
+ // Write the file sector
+ if(!FileStream_Write(ha->pStream, &ByteOffset, pbToWrite, dwBytesInSector))
+ {
+ nError = GetLastError();
+ break;
+ }
+
+ // Call the compact callback, if any
+ if(AddFileCB != NULL)
+ AddFileCB(pvUserData, hf->dwFilePos, hf->dwDataSize, false);
+
+ // Update the compressed file size
+ pFileEntry->dwCmpSize += dwBytesInSector;
+ dwBytesInSector = 0;
+ dwSectorIndex++;
+ }
+ }
+ }
+
+ // Cleanup
+ if(pbCompressed != NULL)
+ STORM_FREE(pbCompressed);
+ return nError;
+}
+
+//-----------------------------------------------------------------------------
+// Recrypts file data for file renaming
+
+static int RecryptFileData(
+ TMPQArchive * ha,
+ TMPQFile * hf,
+ const char * szFileName,
+ const char * szNewFileName)
+{
+ ULONGLONG RawFilePos;
+ TFileEntry * pFileEntry = hf->pFileEntry;
+ DWORD dwBytesToRecrypt = pFileEntry->dwCmpSize;
+ DWORD dwOldKey;
+ DWORD dwNewKey;
+ int nError = ERROR_SUCCESS;
+
+ // The file must be encrypted
+ assert(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED);
+
+ // File decryption key is calculated from the plain name
+ szNewFileName = GetPlainFileNameA(szNewFileName);
+ szFileName = GetPlainFileNameA(szFileName);
+
+ // Calculate both file keys
+ dwOldKey = DecryptFileKey(szFileName, pFileEntry->ByteOffset, pFileEntry->dwFileSize, pFileEntry->dwFlags);
+ dwNewKey = DecryptFileKey(szNewFileName, pFileEntry->ByteOffset, pFileEntry->dwFileSize, pFileEntry->dwFlags);
+
+ // Incase the keys are equal, don't recrypt the file
+ if(dwNewKey == dwOldKey)
+ return ERROR_SUCCESS;
+ hf->dwFileKey = dwOldKey;
+
+ // Calculate the raw position of the file in the archive
+ hf->MpqFilePos = pFileEntry->ByteOffset;
+ hf->RawFilePos = ha->MpqPos + hf->MpqFilePos;
+
+ // Allocate buffer for file transfer
+ nError = AllocateSectorBuffer(hf);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ // Also allocate buffer for sector offsets
+ // Note: Don't load sector checksums, we don't need to recrypt them
+ nError = AllocateSectorOffsets(hf, true);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ // If we have sector offsets, recrypt these as well
+ if(hf->SectorOffsets != NULL)
+ {
+ // Allocate secondary buffer for sectors copy
+ DWORD * SectorOffsetsCopy = (DWORD *)STORM_ALLOC(BYTE, hf->SectorOffsets[0]);
+ DWORD dwSectorOffsLen = hf->SectorOffsets[0];
+
+ if(SectorOffsetsCopy == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Recrypt the array of sector offsets
+ memcpy(SectorOffsetsCopy, hf->SectorOffsets, dwSectorOffsLen);
+ EncryptMpqBlock(SectorOffsetsCopy, dwSectorOffsLen, dwNewKey - 1);
+ BSWAP_ARRAY32_UNSIGNED(SectorOffsetsCopy, dwSectorOffsLen);
+
+ // Write the recrypted array back
+ if(!FileStream_Write(ha->pStream, &hf->RawFilePos, SectorOffsetsCopy, dwSectorOffsLen))
+ nError = GetLastError();
+ STORM_FREE(SectorOffsetsCopy);
+ }
+
+ // Now we have to recrypt all file sectors. We do it without
+ // recompression, because recompression is not necessary in this case
+ if(nError == ERROR_SUCCESS)
+ {
+ for(DWORD dwSector = 0; dwSector < hf->dwSectorCount; dwSector++)
+ {
+ DWORD dwRawDataInSector = hf->dwSectorSize;
+ DWORD dwRawByteOffset = dwSector * hf->dwSectorSize;
+
+ // Last sector: If there is not enough bytes remaining in the file, cut the raw size
+ if(dwRawDataInSector > dwBytesToRecrypt)
+ dwRawDataInSector = dwBytesToRecrypt;
+
+ // Fix the raw data length if the file is compressed
+ if(hf->SectorOffsets != NULL)
+ {
+ dwRawDataInSector = hf->SectorOffsets[dwSector+1] - hf->SectorOffsets[dwSector];
+ dwRawByteOffset = hf->SectorOffsets[dwSector];
+ }
+
+ // Calculate the raw file offset of the file sector
+ CalculateRawSectorOffset(RawFilePos, hf, dwRawByteOffset);
+
+ // Read the file sector
+ if(!FileStream_Read(ha->pStream, &RawFilePos, hf->pbFileSector, dwRawDataInSector))
+ {
+ nError = GetLastError();
+ break;
+ }
+
+ // If necessary, re-encrypt the sector
+ // Note: Recompression is not necessary here. Unlike encryption,
+ // the compression does not depend on the position of the file in MPQ.
+ BSWAP_ARRAY32_UNSIGNED(hf->pbFileSector, dwRawDataInSector);
+ DecryptMpqBlock(hf->pbFileSector, dwRawDataInSector, dwOldKey + dwSector);
+ EncryptMpqBlock(hf->pbFileSector, dwRawDataInSector, dwNewKey + dwSector);
+ BSWAP_ARRAY32_UNSIGNED(hf->pbFileSector, dwRawDataInSector);
+
+ // Write the sector back
+ if(!FileStream_Write(ha->pStream, &RawFilePos, hf->pbFileSector, dwRawDataInSector))
+ {
+ nError = GetLastError();
+ break;
+ }
+
+ // Decrement number of bytes remaining
+ dwBytesToRecrypt -= hf->dwSectorSize;
+ }
+ }
+
+ return nError;
+}
+
+//-----------------------------------------------------------------------------
+// Support functions for adding files to the MPQ
+
+int SFileAddFile_Init(
+ TMPQArchive * ha,
+ const char * szFileName,
+ ULONGLONG FileTime,
+ DWORD dwFileSize,
+ LCID lcLocale,
+ DWORD dwFlags,
+ TMPQFile ** phf)
+{
+ TFileEntry * pFileEntry = NULL;
+ ULONGLONG TempPos; // For various file offset calculations
+ TMPQFile * hf = NULL; // File structure for newly added file
+ int nError = ERROR_SUCCESS;
+
+ //
+ // Note: This is an internal function so no validity checks are done.
+ // It is the caller's responsibility to make sure that no invalid
+ // flags get to this point
+ //
+
+ // Sestor CRC is not allowed with single unit files
+ if(dwFlags & MPQ_FILE_SINGLE_UNIT)
+ dwFlags &= ~MPQ_FILE_SECTOR_CRC;
+
+ // Sector CRC is not allowed if the file is not compressed
+ if(!(dwFlags & MPQ_FILE_COMPRESSED))
+ dwFlags &= ~MPQ_FILE_SECTOR_CRC;
+
+ // Fix Key is not allowed if the file is not enrypted
+ if(!(dwFlags & MPQ_FILE_ENCRYPTED))
+ dwFlags &= ~MPQ_FILE_FIX_KEY;
+
+ // If the MPQ is of version 3.0 or higher, we ignore file locale.
+ // This is because HET and BET tables have no known support for it
+ if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_3)
+ lcLocale = 0;
+
+ // Allocate the TMPQFile entry for newly added file
+ hf = CreateMpqFile(ha);
+ if(hf == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+
+ // Find a free space in the MPQ, as well as free block table entry
+ if(nError == ERROR_SUCCESS)
+ {
+ // Find the position where the file will be stored
+ FindFreeMpqSpace(ha, &hf->MpqFilePos);
+ hf->RawFilePos = ha->MpqPos + hf->MpqFilePos;
+ hf->bIsWriteHandle = true;
+
+ // Sanity check: The MPQ must be marked as changed at this point
+ assert((ha->dwFlags & MPQ_FLAG_CHANGED) != 0);
+
+ // When format V1, the size of the archive cannot exceed 4 GB
+ if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1)
+ {
+ TempPos = hf->MpqFilePos + dwFileSize;
+ TempPos += ha->pHeader->dwHashTableSize * sizeof(TMPQHash);
+ TempPos += ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock);
+ TempPos += ha->pHeader->dwBlockTableSize * sizeof(USHORT);
+ if((TempPos >> 32) != 0)
+ nError = ERROR_DISK_FULL;
+ }
+ }
+
+ // Allocate file entry in the MPQ
+ if(nError == ERROR_SUCCESS)
+ {
+ // Check if the file already exists in the archive
+ pFileEntry = GetFileEntryExact(ha, szFileName, lcLocale);
+ if(pFileEntry == NULL)
+ {
+ pFileEntry = AllocateFileEntry(ha, szFileName, lcLocale);
+ if(pFileEntry == NULL)
+ nError = ERROR_DISK_FULL;
+ }
+ else
+ {
+ // If the file exists and "replace existing" is not set, fail it
+ if((dwFlags & MPQ_FILE_REPLACEEXISTING) == 0)
+ nError = ERROR_ALREADY_EXISTS;
+
+ // If the file entry already contains a file
+ // and it is a pseudo-name, replace it
+ if(nError == ERROR_SUCCESS)
+ {
+ AllocateFileName(pFileEntry, szFileName);
+ }
+ }
+ }
+
+ //
+ // At this point, the file name in file entry must be non-NULL
+ //
+
+ // Create key for file encryption
+ if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_ENCRYPTED))
+ {
+ hf->dwFileKey = DecryptFileKey(szFileName, hf->MpqFilePos, dwFileSize, dwFlags);
+ }
+
+ if(nError == ERROR_SUCCESS)
+ {
+ // Initialize the hash entry for the file
+ hf->pFileEntry = pFileEntry;
+ hf->dwDataSize = dwFileSize;
+
+ // Initialize the block table entry for the file
+ pFileEntry->ByteOffset = hf->MpqFilePos;
+ pFileEntry->dwFileSize = dwFileSize;
+ pFileEntry->dwCmpSize = 0;
+ pFileEntry->dwFlags = dwFlags | MPQ_FILE_EXISTS;
+ pFileEntry->lcLocale = (USHORT)lcLocale;
+
+ // Initialize the file time, CRC32 and MD5
+ assert(sizeof(hf->hctx) >= sizeof(hash_state));
+ memset(pFileEntry->md5, 0, MD5_DIGEST_SIZE);
+ md5_init((hash_state *)hf->hctx);
+ pFileEntry->dwCrc32 = crc32(0, Z_NULL, 0);
+
+ // If the caller gave us a file time, use it.
+ pFileEntry->FileTime = FileTime;
+
+ // Call the callback, if needed
+ if(AddFileCB != NULL)
+ AddFileCB(pvUserData, 0, hf->dwDataSize, false);
+ }
+
+ // If an error occured, remember it
+ if(nError != ERROR_SUCCESS)
+ hf->bErrorOccured = true;
+ *phf = hf;
+ return nError;
+}
+
+int SFileAddFile_Write(TMPQFile * hf, const void * pvData, DWORD dwSize, DWORD dwCompression)
+{
+ TMPQArchive * ha;
+ TFileEntry * pFileEntry;
+ int nError = ERROR_SUCCESS;
+
+ // Don't bother if the caller gave us zero size
+ if(pvData == NULL || dwSize == 0)
+ return ERROR_SUCCESS;
+
+ // Get pointer to the MPQ archive
+ pFileEntry = hf->pFileEntry;
+ ha = hf->ha;
+
+ // Allocate file buffers
+ if(hf->pbFileSector == NULL)
+ {
+ ULONGLONG RawFilePos = hf->RawFilePos;
+
+ // Allocate buffer for file sector
+ nError = AllocateSectorBuffer(hf);
+ if(nError != ERROR_SUCCESS)
+ {
+ hf->bErrorOccured = true;
+ return nError;
+ }
+
+ // Allocate patch info, if the data is patch
+ if(hf->pPatchInfo == NULL && IsIncrementalPatchFile(pvData, dwSize, &hf->dwPatchedFileSize))
+ {
+ // Set the MPQ_FILE_PATCH_FILE flag
+ hf->pFileEntry->dwFlags |= MPQ_FILE_PATCH_FILE;
+
+ // Allocate the patch info
+ nError = AllocatePatchInfo(hf, false);
+ if(nError != ERROR_SUCCESS)
+ {
+ hf->bErrorOccured = true;
+ return nError;
+ }
+ }
+
+ // Allocate sector offsets
+ if(hf->SectorOffsets == NULL)
+ {
+ nError = AllocateSectorOffsets(hf, false);
+ if(nError != ERROR_SUCCESS)
+ {
+ hf->bErrorOccured = true;
+ return nError;
+ }
+ }
+
+ // Create array of sector checksums
+ if(hf->SectorChksums == NULL && (pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC))
+ {
+ nError = AllocateSectorChecksums(hf, false);
+ if(nError != ERROR_SUCCESS)
+ {
+ hf->bErrorOccured = true;
+ return nError;
+ }
+ }
+
+ // Pre-save the patch info, if any
+ if(hf->pPatchInfo != NULL)
+ {
+ if(!FileStream_Write(ha->pStream, &RawFilePos, hf->pPatchInfo, hf->pPatchInfo->dwLength))
+ nError = GetLastError();
+
+ pFileEntry->dwCmpSize += hf->pPatchInfo->dwLength;
+ RawFilePos += hf->pPatchInfo->dwLength;
+ }
+
+ // Pre-save the sector offset table, just to reserve space in the file.
+ // Note that we dont need to swap the sector positions, nor encrypt the table
+ // at the moment, as it will be written again after writing all file sectors.
+ if(hf->SectorOffsets != NULL)
+ {
+ if(!FileStream_Write(ha->pStream, &RawFilePos, hf->SectorOffsets, hf->SectorOffsets[0]))
+ nError = GetLastError();
+
+ pFileEntry->dwCmpSize += hf->SectorOffsets[0];
+ RawFilePos += hf->SectorOffsets[0];
+ }
+ }
+
+ // Write the MPQ data to the file
+ if(nError == ERROR_SUCCESS)
+ nError = WriteDataToMpqFile(ha, hf, (LPBYTE)pvData, dwSize, dwCompression);
+
+ // If it succeeded and we wrote all the file data,
+ // we need to re-save sector offset table
+ if(nError == ERROR_SUCCESS)
+ {
+ if(hf->dwFilePos >= pFileEntry->dwFileSize)
+ {
+ // Finish calculating CRC32
+ hf->pFileEntry->dwCrc32 = hf->dwCrc32;
+
+ // Finish calculating MD5
+ md5_done((hash_state *)hf->hctx, hf->pFileEntry->md5);
+
+ // If we also have sector checksums, write them to the file
+ if(hf->SectorChksums != NULL)
+ {
+ nError = WriteSectorChecksums(hf);
+ if(nError != ERROR_SUCCESS)
+ hf->bErrorOccured = true;
+ }
+
+ // Now write patch info
+ if(hf->pPatchInfo != NULL)
+ {
+ memcpy(hf->pPatchInfo->md5, hf->pFileEntry->md5, MD5_DIGEST_SIZE);
+ hf->pPatchInfo->dwDataSize = hf->pFileEntry->dwFileSize;
+ hf->pFileEntry->dwFileSize = hf->dwPatchedFileSize;
+ nError = WritePatchInfo(hf);
+ if(nError != ERROR_SUCCESS)
+ hf->bErrorOccured = true;
+ }
+
+ // Now write sector offsets to the file
+ if(hf->SectorOffsets != NULL)
+ {
+ nError = WriteSectorOffsets(hf);
+ if(nError != ERROR_SUCCESS)
+ hf->bErrorOccured = true;
+ }
+
+ // Write the MD5 hashes of each file chunk, if required
+ if(ha->pHeader->dwRawChunkSize != 0)
+ {
+ nError = WriteMpqDataMD5(ha->pStream,
+ ha->MpqPos + hf->pFileEntry->ByteOffset,
+ hf->pFileEntry->dwCmpSize,
+ ha->pHeader->dwRawChunkSize);
+ if(nError != ERROR_SUCCESS)
+ hf->bErrorOccured = true;
+ }
+ }
+ }
+ else
+ {
+ hf->bErrorOccured = true;
+ }
+
+ return nError;
+}
+
+int SFileAddFile_Finish(TMPQFile * hf)
+{
+ TMPQArchive * ha = hf->ha;
+ TFileEntry * pFileEntry = hf->pFileEntry;
+ int nError = ERROR_SUCCESS;
+
+ // If all previous operations succeeded, we can update the MPQ
+ if(!hf->bErrorOccured)
+ {
+ // Verify if the caller wrote the file properly
+ if(hf->pPatchInfo == NULL)
+ {
+ assert(pFileEntry != NULL);
+ if(hf->dwFilePos != pFileEntry->dwFileSize)
+ {
+ nError = ERROR_CAN_NOT_COMPLETE;
+ hf->bErrorOccured = true;
+ }
+ }
+ else
+ {
+ if(hf->dwFilePos != hf->pPatchInfo->dwDataSize)
+ {
+ nError = ERROR_CAN_NOT_COMPLETE;
+ hf->bErrorOccured = true;
+ }
+ }
+ }
+
+ if(!hf->bErrorOccured)
+ {
+ // Call the user callback, if any
+ if(AddFileCB != NULL)
+ AddFileCB(pvUserData, hf->dwDataSize, hf->dwDataSize, true);
+
+ // Update the size of the block table
+ ha->pHeader->dwBlockTableSize = ha->dwFileTableSize;
+ }
+ else
+ {
+ // Free the file entry in MPQ tables
+ if(pFileEntry != NULL)
+ FreeFileEntry(ha, pFileEntry);
+ }
+
+ // Clear the add file callback
+ FreeMPQFile(hf);
+ pvUserData = NULL;
+ AddFileCB = NULL;
+ return nError;
+}
+
+//-----------------------------------------------------------------------------
+// Adds data as file to the archive
+
+bool WINAPI SFileCreateFile(
+ HANDLE hMpq,
+ const char * szArchivedName,
+ ULONGLONG FileTime,
+ DWORD dwFileSize,
+ LCID lcLocale,
+ DWORD dwFlags,
+ HANDLE * phFile)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ int nError = ERROR_SUCCESS;
+
+ // Check valid parameters
+ if(!IsValidMpqHandle(ha))
+ nError = ERROR_INVALID_HANDLE;
+ if(szArchivedName == NULL || *szArchivedName == 0)
+ nError = ERROR_INVALID_PARAMETER;
+ if(phFile == NULL)
+ nError = ERROR_INVALID_PARAMETER;
+
+ // Don't allow to add file if the MPQ is open for read only
+ if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
+ nError = ERROR_ACCESS_DENIED;
+
+ // Don't allow to add a file under pseudo-file name
+ if(IsPseudoFileName(szArchivedName, NULL))
+ nError = ERROR_INVALID_PARAMETER;
+
+ // Don't allow to add any of the internal files
+ if(IsInternalMpqFileName(szArchivedName))
+ nError = ERROR_INTERNAL_FILE;
+
+ // Perform validity check of the MPQ flags
+ if(nError == ERROR_SUCCESS)
+ {
+ // Mask all unsupported flags out
+ dwFlags &= MPQ_FILE_VALID_FLAGS;
+
+ // Check for valid flag combinations
+ if((dwFlags & (MPQ_FILE_IMPLODE | MPQ_FILE_COMPRESS)) == (MPQ_FILE_IMPLODE | MPQ_FILE_COMPRESS))
+ nError = ERROR_INVALID_PARAMETER;
+ }
+
+ // Create the file in MPQ
+ if(nError == ERROR_SUCCESS)
+ {
+ // Invalidate the entries for (listfile) and (attributes)
+ // After we are done with MPQ changes, we need to re-create them anyway
+ InvalidateInternalFiles(ha);
+
+ // Initiate the add file operation
+ nError = SFileAddFile_Init(ha, szArchivedName, FileTime, dwFileSize, lcLocale, dwFlags, (TMPQFile **)phFile);
+ }
+
+ // Deal with the errors
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return (nError == ERROR_SUCCESS);
+}
+
+bool WINAPI SFileWriteFile(
+ HANDLE hFile,
+ const void * pvData,
+ DWORD dwSize,
+ DWORD dwCompression)
+{
+ TMPQFile * hf = (TMPQFile *)hFile;
+ int nError = ERROR_SUCCESS;
+
+ // Check the proper parameters
+ if(!IsValidFileHandle(hf))
+ nError = ERROR_INVALID_HANDLE;
+ if(hf->bIsWriteHandle == false)
+ nError = ERROR_INVALID_HANDLE;
+
+ // Special checks for single unit files
+ if(nError == ERROR_SUCCESS && (hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT))
+ {
+ //
+ // Note: Blizzard doesn't support single unit files
+ // that are stored as encrypted or imploded. We will allow them here,
+ // the calling application must ensure that such flag combination doesn't get here
+ //
+
+// if(dwFlags & MPQ_FILE_IMPLODE)
+// nError = ERROR_INVALID_PARAMETER;
+//
+// if(dwFlags & MPQ_FILE_ENCRYPTED)
+// nError = ERROR_INVALID_PARAMETER;
+
+ // Lossy compression is not allowed on single unit files
+ if(dwCompression & LOSSY_COMPRESSION_MASK)
+ nError = ERROR_INVALID_PARAMETER;
+ }
+
+
+ // Write the data to the file
+ if(nError == ERROR_SUCCESS)
+ nError = SFileAddFile_Write(hf, pvData, dwSize, dwCompression);
+
+ // Deal with errors
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return (nError == ERROR_SUCCESS);
+}
+
+bool WINAPI SFileFinishFile(HANDLE hFile)
+{
+ TMPQFile * hf = (TMPQFile *)hFile;
+ int nError = ERROR_SUCCESS;
+
+ // Check the proper parameters
+ if(!IsValidFileHandle(hf))
+ nError = ERROR_INVALID_HANDLE;
+ if(hf->bIsWriteHandle == false)
+ nError = ERROR_INVALID_HANDLE;
+
+ // Finish the file
+ if(nError == ERROR_SUCCESS)
+ nError = SFileAddFile_Finish(hf);
+
+ // Deal with errors
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return (nError == ERROR_SUCCESS);
+}
+
+//-----------------------------------------------------------------------------
+// Adds a file to the archive
+
+bool WINAPI SFileAddFileEx(
+ HANDLE hMpq,
+ const TCHAR * szFileName,
+ const char * szArchivedName,
+ DWORD dwFlags,
+ DWORD dwCompression, // Compression of the first sector
+ DWORD dwCompressionNext) // Compression of next sectors
+{
+ ULONGLONG FileSize = 0;
+ ULONGLONG FileTime = 0;
+ TFileStream * pStream = NULL;
+ HANDLE hMpqFile = NULL;
+ LPBYTE pbFileData = NULL;
+ DWORD dwBytesRemaining = 0;
+ DWORD dwBytesToRead;
+ DWORD dwSectorSize = 0x1000;
+ DWORD dwChannels = 0;
+ bool bIsAdpcmCompression = false;
+ bool bIsFirstSector = true;
+ int nError = ERROR_SUCCESS;
+
+ // Check parameters
+ if(szFileName == NULL || *szFileName == 0)
+ nError = ERROR_INVALID_PARAMETER;
+
+ // Open added file
+ if(nError == ERROR_SUCCESS)
+ {
+ pStream = FileStream_OpenFile(szFileName, STREAM_FLAG_READ_ONLY | STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE);
+ if(pStream == NULL)
+ nError = GetLastError();
+ }
+
+ // Get the file size and file time
+ if(nError == ERROR_SUCCESS)
+ {
+ FileStream_GetTime(pStream, &FileTime);
+ FileStream_GetSize(pStream, FileSize);
+
+ // Files bigger than 4GB cannot be added to MPQ
+ if(FileSize >> 32)
+ nError = ERROR_DISK_FULL;
+ }
+
+ // Allocate data buffer for reading from the source file
+ if(nError == ERROR_SUCCESS)
+ {
+ dwBytesRemaining = (DWORD)FileSize;
+ pbFileData = STORM_ALLOC(BYTE, dwSectorSize);
+ if(pbFileData == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Deal with various combination of compressions
+ if(nError == ERROR_SUCCESS)
+ {
+ // When the compression for next blocks is set to default,
+ // we will copy the compression for the first sector
+ if(dwCompressionNext == MPQ_COMPRESSION_NEXT_SAME)
+ dwCompressionNext = dwCompression;
+
+ // If the caller wants ADPCM compression, we make sure
+ // that the first sector is not compressed with lossy compression
+ if(dwCompressionNext & (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO))
+ {
+ // The first compression must not be WAVE
+ if(dwCompression & (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO))
+ dwCompression = MPQ_COMPRESSION_PKWARE;
+
+ dwCompressionNext &= ~(MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO);
+ bIsAdpcmCompression = true;
+ }
+
+ // Initiate adding file to the MPQ
+ if(!SFileCreateFile(hMpq, szArchivedName, FileTime, (DWORD)FileSize, lcFileLocale, dwFlags, &hMpqFile))
+ nError = GetLastError();
+ }
+
+ // Write the file data to the MPQ
+ while(nError == ERROR_SUCCESS && dwBytesRemaining != 0)
+ {
+ // Get the number of bytes remaining in the source file
+ dwBytesToRead = dwBytesRemaining;
+ if(dwBytesToRead > dwSectorSize)
+ dwBytesToRead = dwSectorSize;
+
+ // Read data from the local file
+ if(!FileStream_Read(pStream, NULL, pbFileData, dwBytesToRead))
+ {
+ nError = GetLastError();
+ break;
+ }
+
+ // If the file being added is a WAVE file, we check number of channels
+ if(bIsFirstSector && bIsAdpcmCompression)
+ {
+ // The file must really be a wave file, otherwise it's data corruption
+ if(!IsWaveFile(pbFileData, dwBytesToRead, &dwChannels))
+ {
+ nError = ERROR_BAD_FORMAT;
+ break;
+ }
+
+ // Setup the compression according to number of channels
+ dwCompressionNext |= (dwChannels == 1) ? MPQ_COMPRESSION_ADPCM_MONO : MPQ_COMPRESSION_ADPCM_STEREO;
+ bIsFirstSector = false;
+ }
+
+ // Add the file sectors to the MPQ
+ if(!SFileWriteFile(hMpqFile, pbFileData, dwBytesToRead, dwCompression))
+ {
+ nError = GetLastError();
+ break;
+ }
+
+ // Set the next data compression
+ dwBytesRemaining -= dwBytesToRead;
+ dwCompression = dwCompressionNext;
+ }
+
+ // Finish the file writing
+ if(hMpqFile != NULL)
+ {
+ if(!SFileFinishFile(hMpqFile))
+ nError = GetLastError();
+ }
+
+ // Cleanup and exit
+ if(pbFileData != NULL)
+ STORM_FREE(pbFileData);
+ if(pStream != NULL)
+ FileStream_Close(pStream);
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return (nError == ERROR_SUCCESS);
+}
+
+// Adds a data file into the archive
+bool WINAPI SFileAddFile(HANDLE hMpq, const TCHAR * szFileName, const char * szArchivedName, DWORD dwFlags)
+{
+ return SFileAddFileEx(hMpq,
+ szFileName,
+ szArchivedName,
+ dwFlags,
+ DefaultDataCompression,
+ DefaultDataCompression);
+}
+
+// Adds a WAVE file into the archive
+bool WINAPI SFileAddWave(HANDLE hMpq, const TCHAR * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality)
+{
+ DWORD dwCompression = 0;
+
+ //
+ // Note to wave compression level:
+ // The following conversion table applied:
+ // High quality: WaveCompressionLevel = -1
+ // Medium quality: WaveCompressionLevel = 4
+ // Low quality: WaveCompressionLevel = 2
+ //
+ // Starcraft files are packed as Mono (0x41) on medium quality.
+ // Because this compression is not used anymore, our compression functions
+ // will default to WaveCompressionLevel = 4 when using ADPCM compression
+ //
+
+ // Convert quality to data compression
+ switch(dwQuality)
+ {
+ case MPQ_WAVE_QUALITY_HIGH:
+// WaveCompressionLevel = -1;
+ dwCompression = MPQ_COMPRESSION_PKWARE;
+ break;
+
+ case MPQ_WAVE_QUALITY_MEDIUM:
+// WaveCompressionLevel = 4;
+ dwCompression = MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN;
+ break;
+
+ case MPQ_WAVE_QUALITY_LOW:
+// WaveCompressionLevel = 2;
+ dwCompression = MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN;
+ break;
+ }
+
+ return SFileAddFileEx(hMpq,
+ szFileName,
+ szArchivedName,
+ dwFlags,
+ MPQ_COMPRESSION_PKWARE, // First sector should be compressed as data
+ dwCompression); // Next sectors should be compressed as WAVE
+}
+
+//-----------------------------------------------------------------------------
+// bool SFileRemoveFile(HANDLE hMpq, char * szFileName)
+//
+// This function removes a file from the archive. The file content
+// remains there, only the entries in the hash table and in the block
+// table are updated.
+
+bool WINAPI SFileRemoveFile(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ TFileEntry * pFileEntry = NULL; // File entry of the file to be deleted
+ DWORD dwFileIndex = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Keep compiler happy
+ dwSearchScope = dwSearchScope;
+
+ // Check the parameters
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!IsValidMpqHandle(ha))
+ nError = ERROR_INVALID_HANDLE;
+ if(szFileName == NULL || *szFileName == 0)
+ nError = ERROR_INVALID_PARAMETER;
+ if(IsInternalMpqFileName(szFileName))
+ nError = ERROR_INTERNAL_FILE;
+ }
+
+ if(nError == ERROR_SUCCESS)
+ {
+ // Do not allow to remove files from MPQ open for read only
+ if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
+ nError = ERROR_ACCESS_DENIED;
+ }
+
+ // Get hash entry belonging to this file
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!IsPseudoFileName(szFileName, &dwFileIndex))
+ {
+ if((pFileEntry = GetFileEntryExact(ha, (char *)szFileName, lcFileLocale)) == NULL)
+ nError = ERROR_FILE_NOT_FOUND;
+ }
+ else
+ {
+ if((pFileEntry = GetFileEntryByIndex(ha, dwFileIndex)) == NULL)
+ nError = ERROR_FILE_NOT_FOUND;
+ }
+ }
+
+ // Test if the file is not already deleted
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!(pFileEntry->dwFlags & MPQ_FILE_EXISTS))
+ nError = ERROR_FILE_NOT_FOUND;
+ }
+
+ if(nError == ERROR_SUCCESS)
+ {
+ // Invalidate the entries for (listfile) and (attributes)
+ // After we are done with MPQ changes, we need to re-create them anyway
+ InvalidateInternalFiles(ha);
+
+ // Mark the file entry as free
+ nError = FreeFileEntry(ha, pFileEntry);
+ }
+
+ // Resolve error and exit
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return (nError == ERROR_SUCCESS);
+}
+
+// Renames the file within the archive.
+bool WINAPI SFileRenameFile(HANDLE hMpq, const char * szFileName, const char * szNewFileName)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ TFileEntry * pFileEntry = NULL;
+ ULONGLONG RawDataOffs;
+ TMPQFile * hf;
+ int nError = ERROR_SUCCESS;
+
+ // Test the valid parameters
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!IsValidMpqHandle(ha))
+ nError = ERROR_INVALID_HANDLE;
+ if(szFileName == NULL || *szFileName == 0 || szNewFileName == NULL || *szNewFileName == 0)
+ nError = ERROR_INVALID_PARAMETER;
+ }
+
+ if(nError == ERROR_SUCCESS)
+ {
+ // Do not allow to rename files in MPQ open for read only
+ if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
+ nError = ERROR_ACCESS_DENIED;
+
+ // Do not allow renaming anything to a pseudo-file name
+ if(IsPseudoFileName(szFileName, NULL) || IsPseudoFileName(szNewFileName, NULL))
+ nError = ERROR_INVALID_PARAMETER;
+
+ // Do not allow to rename any of the internal files
+ // Also do not allow to rename any of files to an internal file
+ if(IsInternalMpqFileName(szFileName) || IsInternalMpqFileName(szNewFileName))
+ nError = ERROR_INTERNAL_FILE;
+ }
+
+ // Find the current file entry.
+ if(nError == ERROR_SUCCESS)
+ {
+ // Get the file entry
+ pFileEntry = GetFileEntryLocale(ha, szFileName, lcFileLocale);
+ if(pFileEntry == NULL)
+ nError = ERROR_FILE_NOT_FOUND;
+ }
+
+ // Also try to find file entry for the new file.
+ // This verifies if we are not overwriting an existing file
+ // (whose name we perhaps don't know)
+ if(nError == ERROR_SUCCESS)
+ {
+ if(GetFileEntryLocale(ha, szNewFileName, pFileEntry->lcLocale) != NULL)
+ nError = ERROR_ALREADY_EXISTS;
+ }
+
+ // Now we rename the existing file entry.
+ if(nError == ERROR_SUCCESS)
+ {
+ // Rename the file entry
+ nError = RenameFileEntry(ha, pFileEntry, szNewFileName);
+ }
+
+ // Now we copy the existing file entry to the new one
+ if(nError == ERROR_SUCCESS)
+ {
+ // If the file is encrypted, we have to re-crypt the file content
+ // with the new decryption key
+ if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
+ {
+ hf = CreateMpqFile(ha);
+ if(hf != NULL)
+ {
+ // Recrypt the file data in the MPQ
+ hf->pFileEntry = pFileEntry;
+ hf->dwDataSize = pFileEntry->dwFileSize;
+ nError = RecryptFileData(ha, hf, szFileName, szNewFileName);
+
+ // Update the MD5
+ if(ha->pHeader->dwRawChunkSize != 0)
+ {
+ RawDataOffs = ha->MpqPos + pFileEntry->ByteOffset;
+ WriteMpqDataMD5(ha->pStream,
+ RawDataOffs,
+ pFileEntry->dwCmpSize,
+ ha->pHeader->dwRawChunkSize);
+ }
+
+ FreeMPQFile(hf);
+ }
+ else
+ {
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+ }
+
+ //
+ // Note: MPQ_FLAG_CHANGED is set by RenameFileEntry
+ //
+
+ // Resolve error and return
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return (nError == ERROR_SUCCESS);
+}
+
+//-----------------------------------------------------------------------------
+// Sets default data compression for SFileAddFile
+
+bool WINAPI SFileSetDataCompression(DWORD DataCompression)
+{
+ unsigned int uValidMask = (MPQ_COMPRESSION_ZLIB | MPQ_COMPRESSION_PKWARE | MPQ_COMPRESSION_BZIP2 | MPQ_COMPRESSION_SPARSE);
+
+ if((DataCompression & uValidMask) != DataCompression)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ DefaultDataCompression = DataCompression;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Changes locale ID of a file
+
+bool WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale)
+{
+ TMPQArchive * ha;
+ TFileEntry * pFileEntry;
+ TMPQFile * hf = (TMPQFile *)hFile;
+
+ // Invalid handle => do nothing
+ if(!IsValidFileHandle(hf))
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return false;
+ }
+
+ // Do not allow unnamed access
+ if(hf->pFileEntry->szFileName == NULL)
+ {
+ SetLastError(ERROR_CAN_NOT_COMPLETE);
+ return false;
+ }
+
+ // Do not allow to change locale of any internal file
+ if(IsInternalMpqFileName(hf->pFileEntry->szFileName))
+ {
+ SetLastError(ERROR_INTERNAL_FILE);
+ return false;
+ }
+
+ // Do not allow changing file locales in MPQs version 3 or higher
+ ha = hf->ha;
+ if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_3)
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return false;
+ }
+
+ // Do not allow to rename files in MPQ open for read only
+ if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
+ {
+ SetLastError(ERROR_ACCESS_DENIED);
+ return false;
+ }
+
+ // If the file already has that locale, return OK
+ if(hf->pFileEntry->lcLocale == lcNewLocale)
+ return true;
+
+ // We have to check if the file+locale is not already there
+ pFileEntry = GetFileEntryExact(ha, hf->pFileEntry->szFileName, lcNewLocale);
+ if(pFileEntry != NULL)
+ {
+ SetLastError(ERROR_ALREADY_EXISTS);
+ return false;
+ }
+
+ // Set the locale and return success
+ pFileEntry = hf->pFileEntry;
+ pFileEntry->lcLocale = (USHORT)lcNewLocale;
+
+ // Save the new locale to the hash table, if any
+ if(ha->pHashTable != NULL)
+ ha->pHashTable[pFileEntry->dwHashIndex].lcLocale = (USHORT)lcNewLocale;
+
+ // Remember that the MPQ tables have been changed
+ ha->dwFlags |= MPQ_FLAG_CHANGED;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Sets add file callback
+
+bool WINAPI SFileSetAddFileCallback(HANDLE /* hMpq */, SFILE_ADDFILE_CALLBACK aAddFileCB, void * pvData)
+{
+ pvUserData = pvData;
+ AddFileCB = aAddFileCB;
+ return true;
+}
diff --git a/dep/StormLib/src/SFileAttributes.cpp b/dep/StormLib/src/SFileAttributes.cpp
new file mode 100644
index 00000000000..0f056088fa3
--- /dev/null
+++ b/dep/StormLib/src/SFileAttributes.cpp
@@ -0,0 +1,477 @@
+/*****************************************************************************/
+/* SAttrFile.cpp Copyright (c) Ladislav Zezula 2007 */
+/*---------------------------------------------------------------------------*/
+/* Description: */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 12.06.04 1.00 Lad The first version of SAttrFile.cpp */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+//-----------------------------------------------------------------------------
+// Local structures
+
+typedef struct _MPQ_ATTRIBUTES_HEADER
+{
+ DWORD dwVersion; // Version of the (attributes) file. Must be 100 (0x64)
+ DWORD dwFlags; // See MPQ_ATTRIBUTE_XXXX
+
+ // Followed by an array of CRC32
+ // Followed by an array of file times
+ // Followed by an array of MD5
+ // Followed by an array of patch bits
+} MPQ_ATTRIBUTES_HEADER, *PMPQ_ATTRIBUTES_HEADER;
+
+//-----------------------------------------------------------------------------
+// Public functions (internal use by StormLib)
+
+int SAttrLoadAttributes(TMPQArchive * ha)
+{
+ MPQ_ATTRIBUTES_HEADER AttrHeader;
+ TMPQFile * hf;
+ HANDLE hFile = NULL;
+ DWORD dwBlockTableSize = ha->pHeader->dwBlockTableSize;
+ DWORD dwArraySize;
+ DWORD dwBytesRead;
+ DWORD i;
+ int nError = ERROR_SUCCESS;
+
+ // File table must be initialized
+ assert(ha->pFileTable != NULL);
+
+ // Attempt to open the "(attributes)" file.
+ // If it's not there, then the archive doesn't support attributes
+ if(SFileOpenFileEx((HANDLE)ha, ATTRIBUTES_NAME, SFILE_OPEN_ANY_LOCALE, &hFile))
+ {
+ // Remember the flags for (attributes)
+ hf = (TMPQFile *)hFile;
+ ha->dwFileFlags2 = hf->pFileEntry->dwFlags;
+
+ // Load the content of the attributes file
+ SFileReadFile(hFile, &AttrHeader, sizeof(MPQ_ATTRIBUTES_HEADER), &dwBytesRead, NULL);
+ if(dwBytesRead != sizeof(MPQ_ATTRIBUTES_HEADER))
+ nError = ERROR_FILE_CORRUPT;
+
+ // Verify the header of the (attributes) file
+ if(nError == ERROR_SUCCESS)
+ {
+ AttrHeader.dwVersion = BSWAP_INT32_UNSIGNED(AttrHeader.dwVersion);
+ AttrHeader.dwFlags = BSWAP_INT32_UNSIGNED(AttrHeader.dwFlags);
+ ha->dwAttrFlags = AttrHeader.dwFlags;
+ if(dwBytesRead != sizeof(MPQ_ATTRIBUTES_HEADER))
+ nError = ERROR_FILE_CORRUPT;
+ }
+
+ // Verify format of the attributes
+ if(nError == ERROR_SUCCESS)
+ {
+ if(AttrHeader.dwVersion > MPQ_ATTRIBUTES_V1)
+ nError = ERROR_BAD_FORMAT;
+ }
+
+ // Load the CRC32 (if any)
+ if(nError == ERROR_SUCCESS && (AttrHeader.dwFlags & MPQ_ATTRIBUTE_CRC32))
+ {
+ LPDWORD pArrayCRC32 = STORM_ALLOC(DWORD, dwBlockTableSize);
+
+ if(pArrayCRC32 != NULL)
+ {
+ dwArraySize = dwBlockTableSize * sizeof(DWORD);
+ SFileReadFile(hFile, pArrayCRC32, dwArraySize, &dwBytesRead, NULL);
+ if(dwBytesRead == dwArraySize)
+ {
+ for(i = 0; i < dwBlockTableSize; i++)
+ ha->pFileTable[i].dwCrc32 = BSWAP_INT32_UNSIGNED(pArrayCRC32[i]);
+ }
+ else
+ nError = ERROR_FILE_CORRUPT;
+
+ STORM_FREE(pArrayCRC32);
+ }
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Read the array of file times
+ if(nError == ERROR_SUCCESS && (AttrHeader.dwFlags & MPQ_ATTRIBUTE_FILETIME))
+ {
+ ULONGLONG * pArrayFileTime = STORM_ALLOC(ULONGLONG, dwBlockTableSize);
+
+ if(pArrayFileTime != NULL)
+ {
+ dwArraySize = dwBlockTableSize * sizeof(ULONGLONG);
+ SFileReadFile(hFile, pArrayFileTime, dwArraySize, &dwBytesRead, NULL);
+ if(dwBytesRead == dwArraySize)
+ {
+ for(i = 0; i < dwBlockTableSize; i++)
+ ha->pFileTable[i].FileTime = BSWAP_INT64_UNSIGNED(pArrayFileTime[i]);
+ }
+ else
+ nError = ERROR_FILE_CORRUPT;
+
+ STORM_FREE(pArrayFileTime);
+ }
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Read the MD5 (if any)
+ // Note: MD5 array can be incomplete, if it's the last array in the (attributes)
+ if(nError == ERROR_SUCCESS && (AttrHeader.dwFlags & MPQ_ATTRIBUTE_MD5))
+ {
+ unsigned char * pArrayMD5 = STORM_ALLOC(unsigned char, (dwBlockTableSize * MD5_DIGEST_SIZE));
+ unsigned char * md5;
+
+ if(pArrayMD5 != NULL)
+ {
+ dwArraySize = dwBlockTableSize * MD5_DIGEST_SIZE;
+ SFileReadFile(hFile, pArrayMD5, dwArraySize, &dwBytesRead, NULL);
+ if(dwBytesRead == dwArraySize)
+ {
+ md5 = pArrayMD5;
+ for(i = 0; i < dwBlockTableSize; i++)
+ {
+ memcpy(ha->pFileTable[i].md5, md5, MD5_DIGEST_SIZE);
+ md5 += MD5_DIGEST_SIZE;
+ }
+ }
+ else
+ nError = ERROR_FILE_CORRUPT;
+
+ STORM_FREE(pArrayMD5);
+ }
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Read the patch bit for each file
+ if(nError == ERROR_SUCCESS && (AttrHeader.dwFlags & MPQ_ATTRIBUTE_PATCH_BIT))
+ {
+ LPBYTE pbBitArray;
+ DWORD dwByteSize = ((dwBlockTableSize - 1) / 8) + 1;
+
+ pbBitArray = STORM_ALLOC(BYTE, dwByteSize);
+ if(pbBitArray != NULL)
+ {
+ SFileReadFile(hFile, pbBitArray, dwByteSize, &dwBytesRead, NULL);
+ if(dwBytesRead == dwByteSize)
+ {
+ for(i = 0; i < dwBlockTableSize; i++)
+ {
+ DWORD dwByteIndex = i / 8;
+ DWORD dwBitMask = 0x80 >> (i & 7);
+
+ // Is the appropriate bit set?
+ if(pbBitArray[dwByteIndex] & dwBitMask)
+ {
+ // At the moment, we assume that the patch bit is present
+ // in both file table and (attributes)
+ assert((ha->pFileTable[i].dwFlags & MPQ_FILE_PATCH_FILE) != 0);
+ ha->pFileTable[i].dwFlags |= MPQ_FILE_PATCH_FILE;
+ }
+ }
+ }
+ else
+ nError = ERROR_FILE_CORRUPT;
+
+ STORM_FREE(pbBitArray);
+ }
+ }
+
+ //
+ // Note: Version 7.00 of StormLib saved the (attributes) incorrectly.
+ // Sometimes, number of entries in the (attributes) was 1 item less
+ // than block table size.
+ // If we encounter such table, we will zero all three arrays
+ //
+
+ if(nError != ERROR_SUCCESS)
+ ha->dwAttrFlags = 0;
+
+ // Cleanup & exit
+ SFileCloseFile(hFile);
+ }
+ return nError;
+}
+
+int SAttrFileSaveToMpq(TMPQArchive * ha)
+{
+ MPQ_ATTRIBUTES_HEADER AttrHeader;
+ TFileEntry * pFileEntry;
+ TMPQFile * hf = NULL;
+ DWORD dwFinalBlockTableSize = ha->dwFileTableSize;
+ DWORD dwFileSize = 0;
+ DWORD dwToWrite;
+ DWORD i;
+ int nError = ERROR_SUCCESS;
+
+ // Now we have to check if we need patch bits in the (attributes)
+ if(nError == ERROR_SUCCESS)
+ {
+ for(i = 0; i < ha->dwFileTableSize; i++)
+ {
+ if(ha->pFileTable[i].dwFlags & MPQ_FILE_PATCH_FILE)
+ {
+ ha->dwAttrFlags |= MPQ_ATTRIBUTE_PATCH_BIT;
+ break;
+ }
+ }
+ }
+
+ // If the (attributes) is not in the file table yet,
+ // we have to increase the final block table size
+ pFileEntry = GetFileEntryExact(ha, ATTRIBUTES_NAME, LANG_NEUTRAL);
+ if(pFileEntry != NULL)
+ {
+ // If "(attributes)" file exists, and it's set to 0, then remove it
+ if(ha->dwAttrFlags == 0)
+ {
+ FreeFileEntry(ha, pFileEntry);
+ return ERROR_SUCCESS;
+ }
+ }
+ else
+ {
+ // If we don't want to create file atributes, do nothing
+ if(ha->dwAttrFlags == 0)
+ return ERROR_SUCCESS;
+
+ // Check where the file entry is going to be allocated.
+ // If at the end of the file table, we have to increment
+ // the expected size of the (attributes) file.
+ pFileEntry = FindFreeFileEntry(ha);
+ if(pFileEntry == ha->pFileTable + ha->dwFileTableSize)
+ dwFinalBlockTableSize++;
+ }
+
+ // Calculate the size of the attributes file
+ if(nError == ERROR_SUCCESS)
+ {
+ dwFileSize = sizeof(MPQ_ATTRIBUTES_HEADER); // Header
+ if(ha->dwAttrFlags & MPQ_ATTRIBUTE_CRC32)
+ dwFileSize += dwFinalBlockTableSize * sizeof(DWORD);
+ if(ha->dwAttrFlags & MPQ_ATTRIBUTE_FILETIME)
+ dwFileSize += dwFinalBlockTableSize * sizeof(ULONGLONG);
+ if(ha->dwAttrFlags & MPQ_ATTRIBUTE_MD5)
+ dwFileSize += dwFinalBlockTableSize * MD5_DIGEST_SIZE;
+ if(ha->dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT)
+ dwFileSize += ((dwFinalBlockTableSize - 1)) / 8 + 1;
+ }
+
+ // Determine the flags for (attributes)
+ if(ha->dwFileFlags2 == 0)
+ ha->dwFileFlags2 = GetDefaultSpecialFileFlags(ha, dwFileSize);
+
+ // Create the attributes file in the MPQ
+ nError = SFileAddFile_Init(ha, ATTRIBUTES_NAME,
+ 0,
+ dwFileSize,
+ LANG_NEUTRAL,
+ ha->dwFileFlags2 | MPQ_FILE_REPLACEEXISTING,
+ &hf);
+
+ // Write all parts of the (attributes) file
+ if(nError == ERROR_SUCCESS)
+ {
+ assert(ha->dwFileTableSize == dwFinalBlockTableSize);
+
+ // Note that we don't know what the new bit (0x08) means.
+ AttrHeader.dwVersion = BSWAP_INT32_UNSIGNED(100);
+ AttrHeader.dwFlags = BSWAP_INT32_UNSIGNED((ha->dwAttrFlags & MPQ_ATTRIBUTE_ALL));
+ dwToWrite = sizeof(MPQ_ATTRIBUTES_HEADER);
+ nError = SFileAddFile_Write(hf, &AttrHeader, dwToWrite, MPQ_COMPRESSION_ZLIB);
+ }
+
+ // Write the array of CRC32
+ if(nError == ERROR_SUCCESS && (ha->dwAttrFlags & MPQ_ATTRIBUTE_CRC32))
+ {
+ LPDWORD pArrayCRC32 = STORM_ALLOC(DWORD, dwFinalBlockTableSize);
+
+ if(pArrayCRC32 != NULL)
+ {
+ // Copy from file table
+ for(i = 0; i < ha->dwFileTableSize; i++)
+ pArrayCRC32[i] = BSWAP_INT32_UNSIGNED(ha->pFileTable[i].dwCrc32);
+
+ dwToWrite = ha->dwFileTableSize * sizeof(DWORD);
+ nError = SFileAddFile_Write(hf, pArrayCRC32, dwToWrite, MPQ_COMPRESSION_ZLIB);
+ STORM_FREE(pArrayCRC32);
+ }
+ }
+
+ // Write the array of file time
+ if(nError == ERROR_SUCCESS && (ha->dwAttrFlags & MPQ_ATTRIBUTE_FILETIME))
+ {
+ ULONGLONG * pArrayFileTime = STORM_ALLOC(ULONGLONG, ha->dwFileTableSize);
+
+ if(pArrayFileTime != NULL)
+ {
+ // Copy from file table
+ for(i = 0; i < ha->dwFileTableSize; i++)
+ pArrayFileTime[i] = BSWAP_INT64_UNSIGNED(ha->pFileTable[i].FileTime);
+
+ dwToWrite = ha->dwFileTableSize * sizeof(ULONGLONG);
+ nError = SFileAddFile_Write(hf, pArrayFileTime, dwToWrite, MPQ_COMPRESSION_ZLIB);
+ STORM_FREE(pArrayFileTime);
+ }
+ }
+
+ // Write the array of MD5s
+ if(nError == ERROR_SUCCESS && (ha->dwAttrFlags & MPQ_ATTRIBUTE_MD5))
+ {
+ char * pArrayMD5 = STORM_ALLOC(char, ha->dwFileTableSize * MD5_DIGEST_SIZE);
+
+ if(pArrayMD5 != NULL)
+ {
+ // Copy from file table
+ for(i = 0; i < ha->dwFileTableSize; i++)
+ memcpy(&pArrayMD5[i * MD5_DIGEST_SIZE], ha->pFileTable[i].md5, MD5_DIGEST_SIZE);
+
+ dwToWrite = ha->dwFileTableSize * MD5_DIGEST_SIZE;
+ nError = SFileAddFile_Write(hf, pArrayMD5, dwToWrite, MPQ_COMPRESSION_ZLIB);
+ STORM_FREE(pArrayMD5);
+ }
+ }
+
+ // Write the array of patch bits
+ if(nError == ERROR_SUCCESS && (ha->dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT))
+ {
+ LPBYTE pbBitArray;
+ DWORD dwByteSize = ((ha->dwFileTableSize - 1) / 8) + 1;
+
+ pbBitArray = STORM_ALLOC(BYTE, dwByteSize);
+ if(pbBitArray != NULL)
+ {
+ memset(pbBitArray, 0, dwByteSize);
+ for(i = 0; i < ha->dwFileTableSize; i++)
+ {
+ DWORD dwByteIndex = i / 8;
+ DWORD dwBitMask = 0x80 >> (i & 7);
+
+ if(ha->pFileTable[i].dwFlags & MPQ_FILE_PATCH_FILE)
+ pbBitArray[dwByteIndex] |= dwBitMask;
+ }
+
+ nError = SFileAddFile_Write(hf, pbBitArray, dwByteSize, MPQ_COMPRESSION_ZLIB);
+ STORM_FREE(pbBitArray);
+ }
+ }
+
+ // Finalize the file in the archive
+ if(hf != NULL)
+ {
+ SFileAddFile_Finish(hf);
+ }
+
+ if(nError == ERROR_SUCCESS)
+ ha->dwFlags &= ~MPQ_FLAG_INV_ATTRIBUTES;
+ return nError;
+}
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+DWORD WINAPI SFileGetAttributes(HANDLE hMpq)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+
+ // Verify the parameters
+ if(!IsValidMpqHandle(ha))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SFILE_INVALID_ATTRIBUTES;
+ }
+
+ return ha->dwAttrFlags;
+}
+
+bool WINAPI SFileSetAttributes(HANDLE hMpq, DWORD dwFlags)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+
+ // Verify the parameters
+ if(!IsValidMpqHandle(ha))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ // Not allowed when the archive is read-only
+ if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
+ {
+ SetLastError(ERROR_ACCESS_DENIED);
+ return false;
+ }
+
+ // Set the attributes
+ InvalidateInternalFiles(ha);
+ ha->dwAttrFlags = (dwFlags & MPQ_ATTRIBUTE_ALL);
+ return true;
+}
+
+bool WINAPI SFileUpdateFileAttributes(HANDLE hMpq, const char * szFileName)
+{
+ hash_state md5_state;
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ TMPQFile * hf;
+ BYTE Buffer[0x1000];
+ HANDLE hFile = NULL;
+ DWORD dwTotalBytes = 0;
+ DWORD dwBytesRead;
+ DWORD dwCrc32;
+
+ // Verify the parameters
+ if(!IsValidMpqHandle(ha))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ // Not allowed when the archive is read-only
+ if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
+ {
+ SetLastError(ERROR_ACCESS_DENIED);
+ return false;
+ }
+
+ // Attempt to open the file
+ if(!SFileOpenFileEx(hMpq, szFileName, SFILE_OPEN_FROM_MPQ, &hFile))
+ return false;
+
+ // Get the file size
+ hf = (TMPQFile *)hFile;
+ SFileGetFileInfo(hFile, SFILE_INFO_FILE_SIZE, &dwTotalBytes, sizeof(DWORD));
+
+ // Initialize the CRC32 and MD5 contexts
+ md5_init(&md5_state);
+ dwCrc32 = crc32(0, Z_NULL, 0);
+
+ // Go through entire file and calculate both CRC32 and MD5
+ while(dwTotalBytes != 0)
+ {
+ // Read data from file
+ SFileReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead, NULL);
+ if(dwBytesRead == 0)
+ break;
+
+ // Update CRC32 and MD5
+ dwCrc32 = crc32(dwCrc32, Buffer, dwBytesRead);
+ md5_process(&md5_state, Buffer, dwBytesRead);
+
+ // Decrement the total size
+ dwTotalBytes -= dwBytesRead;
+ }
+
+ // Update both CRC32 and MD5
+ hf->pFileEntry->dwCrc32 = dwCrc32;
+ md5_done(&md5_state, hf->pFileEntry->md5);
+
+ // Remember that we need to save the MPQ tables
+ InvalidateInternalFiles(ha);
+ SFileCloseFile(hFile);
+ return true;
+}
diff --git a/dep/StormLib/src/SFileCompactArchive.cpp b/dep/StormLib/src/SFileCompactArchive.cpp
new file mode 100644
index 00000000000..319108b08f4
--- /dev/null
+++ b/dep/StormLib/src/SFileCompactArchive.cpp
@@ -0,0 +1,765 @@
+/*****************************************************************************/
+/* SFileCompactArchive.cpp Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Archive compacting function */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 14.04.03 1.00 Lad Splitted from SFileCreateArchiveEx.cpp */
+/* 19.11.03 1.01 Dan Big endian handling */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+/*****************************************************************************/
+/* Local variables */
+/*****************************************************************************/
+
+static SFILE_COMPACT_CALLBACK CompactCB = NULL;
+static ULONGLONG CompactBytesProcessed = 0;
+static ULONGLONG CompactTotalBytes = 0;
+static void * pvUserData = NULL;
+
+/*****************************************************************************/
+/* Local functions */
+/*****************************************************************************/
+
+static int CheckIfAllFilesKnown(TMPQArchive * ha, const char * szListFile, LPDWORD pFileKeys)
+{
+ TFileEntry * pFileTableEnd;
+ TFileEntry * pFileEntry;
+ DWORD dwBlockIndex = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Add the listfile to the MPQ
+ if(nError == ERROR_SUCCESS && szListFile != NULL)
+ {
+ // Notify the user
+ if(CompactCB != NULL)
+ CompactCB(pvUserData, CCB_CHECKING_FILES, CompactBytesProcessed, CompactTotalBytes);
+
+ nError = SFileAddListFile((HANDLE)ha, szListFile);
+ }
+
+ // Verify the file table
+ if(nError == ERROR_SUCCESS)
+ {
+ pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
+ for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++, dwBlockIndex++)
+ {
+ if(pFileEntry->dwFlags & MPQ_FILE_EXISTS)
+ {
+ if(pFileEntry->szFileName != NULL && !IsPseudoFileName(pFileEntry->szFileName, NULL))
+ {
+ DWORD dwFileKey = 0;
+
+ // Resolve the file key. Use plain file name for it
+ if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
+ {
+ dwFileKey = DecryptFileKey(pFileEntry->szFileName,
+ pFileEntry->ByteOffset,
+ pFileEntry->dwFileSize,
+ pFileEntry->dwFlags);
+ }
+
+ // Give the key to the caller
+ if(pFileKeys != NULL)
+ pFileKeys[dwBlockIndex] = dwFileKey;
+ }
+ else
+ {
+ nError = ERROR_CAN_NOT_COMPLETE;
+ break;
+ }
+ }
+ }
+ }
+
+ return nError;
+}
+
+static int CopyNonMpqData(
+ TFileStream * pSrcStream,
+ TFileStream * pTrgStream,
+ ULONGLONG & ByteOffset,
+ ULONGLONG & ByteCount)
+{
+ ULONGLONG DataSize = ByteCount;
+ DWORD dwToRead;
+ char DataBuffer[0x1000];
+ int nError = ERROR_SUCCESS;
+
+ // Copy the data
+ while(DataSize > 0)
+ {
+ // Get the proper size of data
+ dwToRead = sizeof(DataBuffer);
+ if(DataSize < dwToRead)
+ dwToRead = (DWORD)DataSize;
+
+ // Read from the source stream
+ if(!FileStream_Read(pSrcStream, &ByteOffset, DataBuffer, dwToRead))
+ {
+ nError = GetLastError();
+ break;
+ }
+
+ // Write to the target stream
+ if(!FileStream_Write(pTrgStream, NULL, DataBuffer, dwToRead))
+ {
+ nError = GetLastError();
+ break;
+ }
+
+ // Update the progress
+ if(CompactCB != NULL)
+ {
+ CompactBytesProcessed += dwToRead;
+ CompactCB(pvUserData, CCB_COPYING_NON_MPQ_DATA, CompactBytesProcessed, CompactTotalBytes);
+ }
+
+ // Decrement the number of data to be copied
+ ByteOffset += dwToRead;
+ DataSize -= dwToRead;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+// Copies all file sectors into another archive.
+static int CopyMpqFileSectors(
+ TMPQArchive * ha,
+ TMPQFile * hf,
+ TFileStream * pNewStream)
+{
+ TFileEntry * pFileEntry = hf->pFileEntry;
+ ULONGLONG RawFilePos; // Used for calculating sector offset in the old MPQ archive
+ ULONGLONG MpqFilePos; // MPQ file position in the new archive
+ DWORD dwBytesToCopy = pFileEntry->dwCmpSize;
+ DWORD dwPatchSize = 0; // Size of patch header
+ DWORD dwFileKey1 = 0; // File key used for decryption
+ DWORD dwFileKey2 = 0; // File key used for encryption
+ DWORD dwCmpSize = 0; // Compressed file size, including patch header
+ int nError = ERROR_SUCCESS;
+
+ // Remember the position in the destination file
+ FileStream_GetPos(pNewStream, MpqFilePos);
+ MpqFilePos -= ha->MpqPos;
+
+ // Resolve decryption keys. Note that the file key given
+ // in the TMPQFile structure also includes the key adjustment
+ if(nError == ERROR_SUCCESS && (pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED))
+ {
+ dwFileKey2 = dwFileKey1 = hf->dwFileKey;
+ if(pFileEntry->dwFlags & MPQ_FILE_FIX_KEY)
+ {
+ dwFileKey2 = (dwFileKey1 ^ pFileEntry->dwFileSize) - (DWORD)pFileEntry->ByteOffset;
+ dwFileKey2 = (dwFileKey2 + (DWORD)MpqFilePos) ^ pFileEntry->dwFileSize;
+ }
+ }
+
+ // If we have to save patch header, do it
+ if(nError == ERROR_SUCCESS && hf->pPatchInfo != NULL)
+ {
+ BSWAP_ARRAY32_UNSIGNED(hf->pPatchInfo, sizeof(DWORD) * 3);
+ if(!FileStream_Write(pNewStream, NULL, hf->pPatchInfo, hf->pPatchInfo->dwLength))
+ nError = GetLastError();
+
+ // Save the size of the patch info
+ dwPatchSize = hf->pPatchInfo->dwLength;
+ }
+
+ // If we have to save sector offset table, do it.
+ if(nError == ERROR_SUCCESS && hf->SectorOffsets != NULL)
+ {
+ DWORD * SectorOffsetsCopy = (DWORD *)STORM_ALLOC(BYTE, hf->SectorOffsets[0]);
+ DWORD dwSectorOffsLen = hf->SectorOffsets[0];
+
+ assert((pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) == 0);
+ assert(pFileEntry->dwFlags & MPQ_FILE_COMPRESSED);
+
+ if(SectorOffsetsCopy == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+
+ // Encrypt the secondary sector offset table and write it to the target file
+ if(nError == ERROR_SUCCESS)
+ {
+ memcpy(SectorOffsetsCopy, hf->SectorOffsets, dwSectorOffsLen);
+ if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
+ EncryptMpqBlock(SectorOffsetsCopy, dwSectorOffsLen, dwFileKey2 - 1);
+
+ BSWAP_ARRAY32_UNSIGNED(SectorOffsetsCopy, dwSectorOffsLen);
+ if(!FileStream_Write(pNewStream, NULL, SectorOffsetsCopy, dwSectorOffsLen))
+ nError = GetLastError();
+
+ dwBytesToCopy -= dwSectorOffsLen;
+ dwCmpSize += dwSectorOffsLen;
+ }
+
+ // Update compact progress
+ if(CompactCB != NULL)
+ {
+ CompactBytesProcessed += dwSectorOffsLen;
+ CompactCB(pvUserData, CCB_COMPACTING_FILES, CompactBytesProcessed, CompactTotalBytes);
+ }
+
+ STORM_FREE(SectorOffsetsCopy);
+ }
+
+ // Now we have to copy all file sectors. We do it without
+ // recompression, because recompression is not necessary in this case
+ if(nError == ERROR_SUCCESS)
+ {
+ for(DWORD dwSector = 0; dwSector < hf->dwSectorCount; dwSector++)
+ {
+ DWORD dwRawDataInSector = hf->dwSectorSize;
+ DWORD dwRawByteOffset = dwSector * hf->dwSectorSize;
+
+ // Fix the raw data length if the file is compressed
+ if(hf->SectorOffsets != NULL)
+ {
+ dwRawDataInSector = hf->SectorOffsets[dwSector+1] - hf->SectorOffsets[dwSector];
+ dwRawByteOffset = hf->SectorOffsets[dwSector];
+ }
+
+ // Last sector: If there is not enough bytes remaining in the file, cut the raw size
+ if(dwRawDataInSector > dwBytesToCopy)
+ dwRawDataInSector = dwBytesToCopy;
+
+ // Calculate the raw file offset of the file sector
+ CalculateRawSectorOffset(RawFilePos, hf, dwRawByteOffset);
+
+ // Read the file sector
+ if(!FileStream_Read(ha->pStream, &RawFilePos, hf->pbFileSector, dwRawDataInSector))
+ {
+ nError = GetLastError();
+ break;
+ }
+
+ // If necessary, re-encrypt the sector
+ // Note: Recompression is not necessary here. Unlike encryption,
+ // the compression does not depend on the position of the file in MPQ.
+ if((pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) && dwFileKey1 != dwFileKey2)
+ {
+ BSWAP_ARRAY32_UNSIGNED(hf->pbFileSector, dwRawDataInSector);
+ DecryptMpqBlock(hf->pbFileSector, dwRawDataInSector, dwFileKey1 + dwSector);
+ EncryptMpqBlock(hf->pbFileSector, dwRawDataInSector, dwFileKey2 + dwSector);
+ BSWAP_ARRAY32_UNSIGNED(hf->pbFileSector, dwRawDataInSector);
+ }
+
+ // Now write the sector back to the file
+ if(!FileStream_Write(pNewStream, NULL, hf->pbFileSector, dwRawDataInSector))
+ {
+ nError = GetLastError();
+ break;
+ }
+
+ // Update compact progress
+ if(CompactCB != NULL)
+ {
+ CompactBytesProcessed += dwRawDataInSector;
+ CompactCB(pvUserData, CCB_COMPACTING_FILES, CompactBytesProcessed, CompactTotalBytes);
+ }
+
+ // Adjust byte counts
+ dwBytesToCopy -= dwRawDataInSector;
+ dwCmpSize += dwRawDataInSector;
+ }
+ }
+
+ // Copy the sector CRCs, if any
+ // Sector CRCs are always compressed (not imploded) and unencrypted
+ if(nError == ERROR_SUCCESS && hf->SectorOffsets != NULL && hf->SectorChksums != NULL)
+ {
+ DWORD dwCrcLength;
+
+ dwCrcLength = hf->SectorOffsets[hf->dwSectorCount + 1] - hf->SectorOffsets[hf->dwSectorCount];
+ if(dwCrcLength != 0)
+ {
+ if(!FileStream_Read(ha->pStream, NULL, hf->SectorChksums, dwCrcLength))
+ nError = GetLastError();
+
+ if(!FileStream_Write(pNewStream, NULL, hf->SectorChksums, dwCrcLength))
+ nError = GetLastError();
+
+ // Update compact progress
+ if(CompactCB != NULL)
+ {
+ CompactBytesProcessed += dwCrcLength;
+ CompactCB(pvUserData, CCB_COMPACTING_FILES, CompactBytesProcessed, CompactTotalBytes);
+ }
+
+ // Size of the CRC block is also included in the compressed file size
+ dwBytesToCopy -= dwCrcLength;
+ dwCmpSize += dwCrcLength;
+ }
+ }
+
+ // There might be extra data beyond sector checksum table
+ // Sometimes, these data are even part of sector offset table
+ // Examples:
+ // 2012 - WoW\15354\locale-enGB.MPQ:DBFilesClient\SpellLevels.dbc
+ // 2012 - WoW\15354\locale-enGB.MPQ:Interface\AddOns\Blizzard_AuctionUI\Blizzard_AuctionUI.xml
+ if(nError == ERROR_SUCCESS && dwBytesToCopy != 0)
+ {
+ LPBYTE pbExtraData;
+
+ // Allocate space for the extra data
+ pbExtraData = STORM_ALLOC(BYTE, dwBytesToCopy);
+ if(pbExtraData != NULL)
+ {
+ if(!FileStream_Read(ha->pStream, NULL, pbExtraData, dwBytesToCopy))
+ nError = GetLastError();
+
+ if(!FileStream_Write(pNewStream, NULL, pbExtraData, dwBytesToCopy))
+ nError = GetLastError();
+
+ // Include these extra data in the compressed size
+ dwCmpSize += dwBytesToCopy;
+ dwBytesToCopy = 0;
+ STORM_FREE(pbExtraData);
+ }
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Write the MD5's of the raw file data, if needed
+ if(nError == ERROR_SUCCESS && ha->pHeader->dwRawChunkSize != 0)
+ {
+ nError = WriteMpqDataMD5(pNewStream,
+ ha->MpqPos + MpqFilePos,
+ pFileEntry->dwCmpSize,
+ ha->pHeader->dwRawChunkSize);
+ }
+
+ // Update file position in the block table
+ if(nError == ERROR_SUCCESS)
+ {
+ // At this point, number of bytes written should be exactly
+ // the same like the compressed file size. If it isn't,
+ // there's something wrong (an unknown archive version, MPQ protection, ...)
+ //
+ // Note: Diablo savegames have very weird layout, and the file "hero"
+ // seems to have improper compressed size. Instead of real compressed size,
+ // the "dwCmpSize" member of the block table entry contains
+ // uncompressed size of file data + size of the sector table.
+ // If we compact the archive, Diablo will refuse to load the game
+ // Seems like some sort of protection to me.
+ //
+ // Note: Some patch files in WOW patches don't count the patch header
+ // into compressed size
+ //
+
+ if(dwCmpSize <= pFileEntry->dwCmpSize && pFileEntry->dwCmpSize <= dwCmpSize + dwPatchSize)
+ {
+ // Note: DO NOT update the compressed size in the file entry, no matter how bad it is.
+ pFileEntry->ByteOffset = MpqFilePos;
+ }
+ else
+ {
+ nError = ERROR_FILE_CORRUPT;
+ assert(false);
+ }
+ }
+
+ return nError;
+}
+
+static int CopyMpqFiles(TMPQArchive * ha, LPDWORD pFileKeys, TFileStream * pNewStream)
+{
+ TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
+ TFileEntry * pFileEntry;
+ TMPQFile * hf = NULL;
+ int nError = ERROR_SUCCESS;
+
+ // Walk through all files and write them to the destination MPQ archive
+ for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
+ {
+ // Copy all the file sectors
+ // Only do that when the file has nonzero size
+ if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) && pFileEntry->dwFileSize != 0)
+ {
+ // Allocate structure for the MPQ file
+ hf = CreateMpqFile(ha);
+ if(hf == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Store file entry
+ hf->pFileEntry = pFileEntry;
+
+ // Set the raw file position
+ hf->MpqFilePos = pFileEntry->ByteOffset;
+ hf->RawFilePos = ha->MpqPos + hf->MpqFilePos;
+
+ // Set the file decryption key
+ hf->dwFileKey = pFileKeys[pFileEntry - ha->pFileTable];
+ hf->dwDataSize = pFileEntry->dwFileSize;
+
+ // If the file is a patch file, load the patch header
+ if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE)
+ {
+ nError = AllocatePatchInfo(hf, true);
+ if(nError != ERROR_SUCCESS)
+ break;
+ }
+
+ // Allocate buffers for file sector and sector offset table
+ nError = AllocateSectorBuffer(hf);
+ if(nError != ERROR_SUCCESS)
+ break;
+
+ // Also allocate sector offset table and sector checksum table
+ nError = AllocateSectorOffsets(hf, true);
+ if(nError != ERROR_SUCCESS)
+ break;
+
+ // Also load sector checksums, if any
+ if(pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC)
+ {
+ nError = AllocateSectorChecksums(hf, false);
+ if(nError != ERROR_SUCCESS)
+ break;
+ }
+
+ // Copy all file sectors
+ nError = CopyMpqFileSectors(ha, hf, pNewStream);
+ if(nError != ERROR_SUCCESS)
+ break;
+
+ // Free buffers. This also sets "hf" to NULL.
+ FreeMPQFile(hf);
+ }
+ }
+
+ // Cleanup and exit
+ if(hf != NULL)
+ FreeMPQFile(hf);
+ return nError;
+}
+
+
+/*****************************************************************************/
+/* Public functions */
+/*****************************************************************************/
+
+bool WINAPI SFileSetCompactCallback(HANDLE /* hMpq */, SFILE_COMPACT_CALLBACK aCompactCB, void * pvData)
+{
+ CompactCB = aCompactCB;
+ pvUserData = pvData;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Archive compacting
+
+bool WINAPI SFileCompactArchive(HANDLE hMpq, const char * szListFile, bool /* bReserved */)
+{
+ TFileStream * pTempStream = NULL;
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ ULONGLONG ByteOffset;
+ ULONGLONG ByteCount;
+ LPDWORD pFileKeys = NULL;
+ TCHAR szTempFile[MAX_PATH] = _T("");
+ TCHAR * szTemp = NULL;
+ int nError = ERROR_SUCCESS;
+
+ // Test the valid parameters
+ if(!IsValidMpqHandle(ha))
+ nError = ERROR_INVALID_HANDLE;
+ if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
+ nError = ERROR_ACCESS_DENIED;
+
+ // If the MPQ is changed at this moment, we have to flush the archive
+ if(nError == ERROR_SUCCESS && (ha->dwFlags & MPQ_FLAG_CHANGED))
+ {
+ SFileFlushArchive(hMpq);
+ }
+
+ // Create the table with file keys
+ if(nError == ERROR_SUCCESS)
+ {
+ if((pFileKeys = STORM_ALLOC(DWORD, ha->dwFileTableSize)) != NULL)
+ memset(pFileKeys, 0, sizeof(DWORD) * ha->dwFileTableSize);
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // First of all, we have to check of we are able to decrypt all files.
+ // If not, sorry, but the archive cannot be compacted.
+ if(nError == ERROR_SUCCESS)
+ {
+ // Initialize the progress variables for compact callback
+ FileStream_GetSize(ha->pStream, CompactTotalBytes);
+ CompactBytesProcessed = 0;
+ nError = CheckIfAllFilesKnown(ha, szListFile, pFileKeys);
+ }
+
+ // Get the temporary file name and create it
+ if(nError == ERROR_SUCCESS)
+ {
+ _tcscpy(szTempFile, FileStream_GetFileName(ha->pStream));
+ if((szTemp = _tcsrchr(szTempFile, '.')) != NULL)
+ _tcscpy(szTemp + 1, _T("mp_"));
+ else
+ _tcscat(szTempFile, _T("_"));
+
+ pTempStream = FileStream_CreateFile(szTempFile, STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE);
+ if(pTempStream == NULL)
+ nError = GetLastError();
+ }
+
+ // Write the data before MPQ user data (if any)
+ if(nError == ERROR_SUCCESS && ha->UserDataPos != 0)
+ {
+ // Inform the application about the progress
+ if(CompactCB != NULL)
+ CompactCB(pvUserData, CCB_COPYING_NON_MPQ_DATA, CompactBytesProcessed, CompactTotalBytes);
+
+ ByteOffset = 0;
+ ByteCount = ha->UserDataPos;
+ nError = CopyNonMpqData(ha->pStream, pTempStream, ByteOffset, ByteCount);
+ }
+
+ // Write the MPQ user data (if any)
+ if(nError == ERROR_SUCCESS && ha->MpqPos > ha->UserDataPos)
+ {
+ // At this point, we assume that the user data size is equal
+ // to pUserData->dwHeaderOffs.
+ // If this assumption doesn't work, then we have an unknown version of MPQ
+ ByteOffset = ha->UserDataPos;
+ ByteCount = ha->MpqPos - ha->UserDataPos;
+
+ assert(ha->pUserData != NULL);
+ assert(ha->pUserData->dwHeaderOffs == ByteCount);
+ nError = CopyNonMpqData(ha->pStream, pTempStream, ByteOffset, ByteCount);
+ }
+
+ // Write the MPQ header
+ if(nError == ERROR_SUCCESS)
+ {
+ // Remember the header size before swapping
+ DWORD dwBytesToWrite = ha->pHeader->dwHeaderSize;
+
+ BSWAP_TMPQHEADER(ha->pHeader);
+ if(!FileStream_Write(pTempStream, NULL, ha->pHeader, dwBytesToWrite))
+ nError = GetLastError();
+ BSWAP_TMPQHEADER(ha->pHeader);
+
+ // Update the progress
+ CompactBytesProcessed += ha->pHeader->dwHeaderSize;
+ }
+
+ // Now copy all files
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = CopyMpqFiles(ha, pFileKeys, pTempStream);
+ ha->dwFlags |= MPQ_FLAG_CHANGED;
+ }
+
+ // If succeeded, switch the streams
+ if(nError == ERROR_SUCCESS)
+ {
+ if(FileStream_Switch(ha->pStream, pTempStream))
+ pTempStream = NULL;
+ else
+ nError = ERROR_CAN_NOT_COMPLETE;
+ }
+
+ // If all succeeded, save the MPQ tables
+ if(nError == ERROR_SUCCESS)
+ {
+ //
+ // Note: We don't recalculate position of the MPQ tables at this point.
+ // SaveMPQTables does it automatically.
+ //
+
+ nError = SaveMPQTables(ha);
+ if(nError == ERROR_SUCCESS && CompactCB != NULL)
+ {
+ CompactBytesProcessed += (ha->pHeader->dwHashTableSize * sizeof(TMPQHash));
+ CompactBytesProcessed += (ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock));
+ CompactCB(pvUserData, CCB_CLOSING_ARCHIVE, CompactBytesProcessed, CompactTotalBytes);
+ }
+ }
+
+ // Invalidate the compact callback
+ pvUserData = NULL;
+ CompactCB = NULL;
+
+ // Cleanup and return
+ if(pTempStream != NULL)
+ FileStream_Close(pTempStream);
+ if(pFileKeys != NULL)
+ STORM_FREE(pFileKeys);
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return (nError == ERROR_SUCCESS);
+}
+
+//-----------------------------------------------------------------------------
+// Changing hash table size
+
+DWORD WINAPI SFileGetMaxFileCount(HANDLE hMpq)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+
+ return ha->dwMaxFileCount;
+}
+
+bool WINAPI SFileSetMaxFileCount(HANDLE hMpq, DWORD dwMaxFileCount)
+{
+ TMPQHetTable * pOldHetTable = NULL;
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ TFileEntry * pOldFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
+ TFileEntry * pOldFileTable = NULL;
+ TFileEntry * pOldFileEntry;
+ TFileEntry * pFileEntry;
+ TMPQHash * pOldHashTable = NULL;
+ DWORD dwOldHashTableSize = 0;
+ DWORD dwOldFileTableSize = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Test the valid parameters
+ if(!IsValidMpqHandle(ha))
+ nError = ERROR_INVALID_HANDLE;
+ if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
+ nError = ERROR_ACCESS_DENIED;
+
+ // The new limit must not be lower than the index of the last file entry in the table
+ if(nError == ERROR_SUCCESS && ha->dwFileTableSize > dwMaxFileCount)
+ nError = ERROR_DISK_FULL;
+
+ // ALL file names must be known in order to be able
+ // to rebuild hash table size
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = CheckIfAllFilesKnown(ha, NULL, NULL);
+ }
+
+ // If the MPQ has a hash table, then we relocate the hash table
+ if(nError == ERROR_SUCCESS && ha->pHashTable != NULL)
+ {
+ // Save parameters for the current hash table
+ dwOldHashTableSize = ha->pHeader->dwHashTableSize;
+ pOldHashTable = ha->pHashTable;
+
+ // Allocate new hash table
+ ha->pHeader->dwHashTableSize = GetHashTableSizeForFileCount(dwMaxFileCount);
+ ha->pHashTable = STORM_ALLOC(TMPQHash, ha->pHeader->dwHashTableSize);
+ if(ha->pHashTable != NULL)
+ memset(ha->pHashTable, 0xFF, ha->pHeader->dwHashTableSize * sizeof(TMPQHash));
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // If the MPQ has HET table, allocate new one as well
+ if(nError == ERROR_SUCCESS && ha->pHetTable != NULL)
+ {
+ // Save the original HET table
+ pOldHetTable = ha->pHetTable;
+
+ // Create new one
+ ha->pHetTable = CreateHetTable(dwMaxFileCount, 0x40, true);
+ if(ha->pHetTable == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Now reallocate the file table
+ if(nError == ERROR_SUCCESS)
+ {
+ // Save the current file table
+ dwOldFileTableSize = ha->dwFileTableSize;
+ pOldFileTable = ha->pFileTable;
+
+ // Create new one
+ ha->pFileTable = STORM_ALLOC(TFileEntry, dwMaxFileCount);
+ if(ha->pFileTable != NULL)
+ memset(ha->pFileTable, 0, dwMaxFileCount * sizeof(TFileEntry));
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Now we have to build both classic hash table and HET table.
+ if(nError == ERROR_SUCCESS)
+ {
+ DWORD dwFileIndex = 0;
+ DWORD dwHashIndex = 0;
+
+ // Create new hash and HET entry for each file
+ pFileEntry = ha->pFileTable;
+ for(pOldFileEntry = pOldFileTable; pOldFileEntry < pOldFileTableEnd; pOldFileEntry++)
+ {
+ if(pOldFileEntry->dwFlags & MPQ_FILE_EXISTS)
+ {
+ // Copy the old file entry to the new one
+ memcpy(pFileEntry, pOldFileEntry, sizeof(TFileEntry));
+ assert(pFileEntry->szFileName != NULL);
+
+ // Create new entry in the hash table
+ if(ha->pHashTable != NULL)
+ {
+ dwHashIndex = AllocateHashEntry(ha, pFileEntry);
+ if(dwHashIndex == HASH_ENTRY_FREE)
+ {
+ nError = ERROR_CAN_NOT_COMPLETE;
+ break;
+ }
+ }
+
+ // Create new entry in the HET table, if needed
+ if(ha->pHetTable != NULL)
+ {
+ dwHashIndex = AllocateHetEntry(ha, pFileEntry);
+ if(dwHashIndex == HASH_ENTRY_FREE)
+ {
+ nError = ERROR_CAN_NOT_COMPLETE;
+ break;
+ }
+ }
+
+ // Move to the next file entry in the new table
+ pFileEntry++;
+ dwFileIndex++;
+ }
+ }
+ }
+
+ // Mark the archive as changed
+ // Note: We always have to rebuild the (attributes) file due to file table change
+ if(nError == ERROR_SUCCESS)
+ {
+ ha->dwMaxFileCount = dwMaxFileCount;
+ InvalidateInternalFiles(ha);
+ }
+ else
+ {
+ // Revert the hash table
+ if(ha->pHashTable != NULL && pOldHashTable != NULL)
+ {
+ STORM_FREE(ha->pHashTable);
+ ha->pHeader->dwHashTableSize = dwOldHashTableSize;
+ ha->pHashTable = pOldHashTable;
+ }
+
+ // Revert the HET table
+ if(ha->pHetTable != NULL && pOldHetTable != NULL)
+ {
+ FreeHetTable(ha->pHetTable);
+ ha->pHetTable = pOldHetTable;
+ }
+
+ // Revert the file table
+ if(pOldFileTable != NULL)
+ {
+ STORM_FREE(ha->pFileTable);
+ ha->pFileTable = pOldFileTable;
+ }
+
+ SetLastError(nError);
+ }
+
+ // Return the result
+ return (nError == ERROR_SUCCESS);
+}
diff --git a/dep/StormLib/src/SFileCreateArchive.cpp b/dep/StormLib/src/SFileCreateArchive.cpp
new file mode 100644
index 00000000000..59f3d3fa9e8
--- /dev/null
+++ b/dep/StormLib/src/SFileCreateArchive.cpp
@@ -0,0 +1,255 @@
+/*****************************************************************************/
+/* SFileCreateArchive.cpp Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* MPQ Editing functions */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 24.03.03 1.00 Lad Splitted from SFileOpenArchive.cpp */
+/* 08.06.10 1.00 Lad Renamed to SFileCreateArchive.cpp */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+//-----------------------------------------------------------------------------
+// Local variables
+
+static const DWORD MpqHeaderSizes[] =
+{
+ MPQ_HEADER_SIZE_V1,
+ MPQ_HEADER_SIZE_V2,
+ MPQ_HEADER_SIZE_V3,
+ MPQ_HEADER_SIZE_V4
+};
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static USHORT GetSectorSizeShift(DWORD dwSectorSize)
+{
+ USHORT wSectorSizeShift = 0;
+
+ while(dwSectorSize > 0x200)
+ {
+ dwSectorSize >>= 1;
+ wSectorSizeShift++;
+ }
+
+ return wSectorSizeShift;
+}
+
+static int WriteNakedMPQHeader(TMPQArchive * ha)
+{
+ TMPQHeader * pHeader = ha->pHeader;
+ TMPQHeader Header;
+ DWORD dwBytesToWrite = pHeader->dwHeaderSize;
+ int nError = ERROR_SUCCESS;
+
+ // Prepare the naked MPQ header
+ memset(&Header, 0, sizeof(TMPQHeader));
+ Header.dwID = pHeader->dwID;
+ Header.dwHeaderSize = pHeader->dwHeaderSize;
+ Header.dwArchiveSize = pHeader->dwHeaderSize;
+ Header.wFormatVersion = pHeader->wFormatVersion;
+ Header.wSectorSize = pHeader->wSectorSize;
+
+ // Write it to the file
+ BSWAP_TMPQHEADER(&Header);
+ if(!FileStream_Write(ha->pStream, &ha->MpqPos, &Header, dwBytesToWrite))
+ nError = GetLastError();
+
+ return nError;
+}
+
+//-----------------------------------------------------------------------------
+// Creates a new MPQ archive.
+
+bool WINAPI SFileCreateArchive(const TCHAR * szMpqName, DWORD dwFlags, DWORD dwMaxFileCount, HANDLE * phMpq)
+{
+ SFILE_CREATE_MPQ CreateInfo;
+
+ // Fill the create structure
+ memset(&CreateInfo, 0, sizeof(SFILE_CREATE_MPQ));
+ CreateInfo.cbSize = sizeof(SFILE_CREATE_MPQ);
+ CreateInfo.dwMpqVersion = (dwFlags & MPQ_CREATE_ARCHIVE_VMASK) >> FLAGS_TO_FORMAT_SHIFT;
+ CreateInfo.dwStreamFlags = STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE;
+ CreateInfo.dwAttrFlags = (dwFlags & MPQ_CREATE_ATTRIBUTES) ? MPQ_ATTRIBUTE_ALL : 0;
+ CreateInfo.dwSectorSize = (CreateInfo.dwMpqVersion >= MPQ_FORMAT_VERSION_3) ? 0x4000 : 0x1000;
+ CreateInfo.dwRawChunkSize = (CreateInfo.dwMpqVersion >= MPQ_FORMAT_VERSION_4) ? 0x4000 : 0;
+ CreateInfo.dwMaxFileCount = dwMaxFileCount;
+ return SFileCreateArchive2(szMpqName, &CreateInfo, phMpq);
+}
+
+bool WINAPI SFileCreateArchive2(const TCHAR * szMpqName, PSFILE_CREATE_MPQ pCreateInfo, HANDLE * phMpq)
+{
+ TFileStream * pStream = NULL; // File stream
+ TMPQArchive * ha = NULL; // MPQ archive handle
+ ULONGLONG MpqPos = 0; // Position of MPQ header in the file
+ HANDLE hMpq = NULL;
+ DWORD dwBlockTableSize = 0; // Initial block table size
+ DWORD dwHashTableSize = 0;
+ DWORD dwMaxFileCount;
+ int nError = ERROR_SUCCESS;
+
+ // Check the parameters, if they are valid
+ if(szMpqName == NULL || *szMpqName == 0 || pCreateInfo == NULL || phMpq == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ // Verify if all variables in SFILE_CREATE_MPQ are correct
+ if((pCreateInfo->cbSize == 0 || pCreateInfo->cbSize > sizeof(SFILE_CREATE_MPQ)) ||
+ (pCreateInfo->dwMpqVersion > MPQ_FORMAT_VERSION_4) ||
+ (pCreateInfo->pvUserData != NULL || pCreateInfo->cbUserData != 0) ||
+ (pCreateInfo->dwAttrFlags & ~MPQ_ATTRIBUTE_ALL) ||
+ (pCreateInfo->dwSectorSize & (pCreateInfo->dwSectorSize - 1)) ||
+ (pCreateInfo->dwRawChunkSize & (pCreateInfo->dwRawChunkSize - 1)) ||
+ (pCreateInfo->dwMaxFileCount < 4))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ // One time initialization of MPQ cryptography
+ InitializeMpqCryptography();
+
+ // We verify if the file already exists and if it's a MPQ archive.
+ // If yes, we won't allow to overwrite it.
+ if(SFileOpenArchive(szMpqName, 0, STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE | MPQ_OPEN_NO_ATTRIBUTES | MPQ_OPEN_NO_LISTFILE, &hMpq))
+ {
+ SFileCloseArchive(hMpq);
+ SetLastError(ERROR_ALREADY_EXISTS);
+ return false;
+ }
+
+ //
+ // At this point, we have to create the archive.
+ // - If the file exists, convert it to MPQ archive.
+ // - If the file doesn't exist, create new empty file
+ //
+
+ pStream = FileStream_OpenFile(szMpqName, pCreateInfo->dwStreamFlags);
+ if(pStream == NULL)
+ {
+ pStream = FileStream_CreateFile(szMpqName, pCreateInfo->dwStreamFlags);
+ if(pStream == NULL)
+ return false;
+ }
+
+ // Increment the maximum amount of files to have space
+ // for listfile and attributes file
+ dwMaxFileCount = pCreateInfo->dwMaxFileCount;
+ if(pCreateInfo->dwAttrFlags != 0)
+ dwMaxFileCount++;
+ dwMaxFileCount++;
+
+ // If file count is not zero, initialize the hash table size
+ dwHashTableSize = GetHashTableSizeForFileCount(dwMaxFileCount);
+
+ // Retrieve the file size and round it up to 0x200 bytes
+ FileStream_GetSize(pStream, MpqPos);
+ MpqPos = (MpqPos + 0x1FF) & (ULONGLONG)0xFFFFFFFFFFFFFE00ULL;
+ if(!FileStream_SetSize(pStream, MpqPos))
+ nError = GetLastError();
+
+#ifdef _DEBUG
+ // Debug code, used for testing StormLib
+// dwBlockTableSize = dwHashTableSize * 2;
+#endif
+
+ // Create the archive handle
+ if(nError == ERROR_SUCCESS)
+ {
+ if((ha = STORM_ALLOC(TMPQArchive, 1)) == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Fill the MPQ archive handle structure
+ if(nError == ERROR_SUCCESS)
+ {
+ memset(ha, 0, sizeof(TMPQArchive));
+ ha->pStream = pStream;
+ ha->dwSectorSize = pCreateInfo->dwSectorSize;
+ ha->UserDataPos = MpqPos;
+ ha->MpqPos = MpqPos;
+ ha->pHeader = (TMPQHeader *)ha->HeaderData;
+ ha->dwMaxFileCount = dwMaxFileCount;
+ ha->dwFileTableSize = 0;
+ ha->dwFileFlags1 = pCreateInfo->dwFileFlags1;
+ ha->dwFileFlags2 = pCreateInfo->dwFileFlags2;
+ ha->dwFlags = 0;
+
+ // Setup the attributes
+ ha->dwAttrFlags = pCreateInfo->dwAttrFlags;
+ pStream = NULL;
+ }
+
+ // Fill the MPQ header
+ if(nError == ERROR_SUCCESS)
+ {
+ TMPQHeader * pHeader = ha->pHeader;
+
+ // Fill the MPQ header
+ memset(pHeader, 0, sizeof(ha->HeaderData));
+ pHeader->dwID = ID_MPQ;
+ pHeader->dwHeaderSize = MpqHeaderSizes[pCreateInfo->dwMpqVersion];
+ pHeader->dwArchiveSize = pHeader->dwHeaderSize + dwHashTableSize * sizeof(TMPQHash);
+ pHeader->wFormatVersion = (USHORT)pCreateInfo->dwMpqVersion;
+ pHeader->wSectorSize = GetSectorSizeShift(ha->dwSectorSize);
+ pHeader->dwHashTablePos = pHeader->dwHeaderSize;
+ pHeader->dwHashTableSize = dwHashTableSize;
+ pHeader->dwBlockTablePos = pHeader->dwHashTablePos + dwHashTableSize * sizeof(TMPQHash);
+ pHeader->dwBlockTableSize = dwBlockTableSize;
+
+ // For MPQs version 4 and higher, we set the size of raw data block
+ // for calculating MD5
+ if(pCreateInfo->dwMpqVersion >= MPQ_FORMAT_VERSION_4)
+ pHeader->dwRawChunkSize = pCreateInfo->dwRawChunkSize;
+
+ // Write the naked MPQ header
+ nError = WriteNakedMPQHeader(ha);
+
+ // Remember that the (listfile) and (attributes) need to be saved
+ ha->dwFlags |= MPQ_FLAG_CHANGED | MPQ_FLAG_INV_LISTFILE | MPQ_FLAG_INV_ATTRIBUTES;
+ }
+
+ // Create initial HET table, if the caller required an MPQ format 3.0 or newer
+ if(nError == ERROR_SUCCESS && pCreateInfo->dwMpqVersion >= MPQ_FORMAT_VERSION_3)
+ {
+ ha->pHetTable = CreateHetTable(ha->dwMaxFileCount, 0x40, true);
+ if(ha->pHetTable == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Create initial hash table
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = CreateHashTable(ha, dwHashTableSize);
+ }
+
+ // Create initial file table
+ if(nError == ERROR_SUCCESS)
+ {
+ ha->pFileTable = STORM_ALLOC(TFileEntry, ha->dwMaxFileCount);
+ if(ha->pFileTable != NULL)
+ memset(ha->pFileTable, 0x00, sizeof(TFileEntry) * ha->dwMaxFileCount);
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Cleanup : If an error, delete all buffers and return
+ if(nError != ERROR_SUCCESS)
+ {
+ FileStream_Close(pStream);
+ FreeMPQArchive(ha);
+ SetLastError(nError);
+ ha = NULL;
+ }
+
+ // Return the values
+ *phMpq = (HANDLE)ha;
+ return (nError == ERROR_SUCCESS);
+}
diff --git a/dep/StormLib/src/SFileExtractFile.cpp b/dep/StormLib/src/SFileExtractFile.cpp
new file mode 100644
index 00000000000..c8053ed4e62
--- /dev/null
+++ b/dep/StormLib/src/SFileExtractFile.cpp
@@ -0,0 +1,67 @@
+/*****************************************************************************/
+/* SFileExtractFile.cpp Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Simple extracting utility */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 20.06.03 1.00 Lad The first version of SFileExtractFile.cpp */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+bool WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const TCHAR * szExtracted, DWORD dwSearchScope)
+{
+ TFileStream * pLocalFile = NULL;
+ HANDLE hMpqFile = NULL;
+ int nError = ERROR_SUCCESS;
+
+ // Open the MPQ file
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!SFileOpenFileEx(hMpq, szToExtract, dwSearchScope, &hMpqFile))
+ nError = GetLastError();
+ }
+
+ // Create the local file
+ if(nError == ERROR_SUCCESS)
+ {
+ pLocalFile = FileStream_CreateFile(szExtracted, STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE);
+ if(pLocalFile == NULL)
+ nError = GetLastError();
+ }
+
+ // Copy the file's content
+ if(nError == ERROR_SUCCESS)
+ {
+ char szBuffer[0x1000];
+ DWORD dwTransferred;
+
+ for(;;)
+ {
+ // dwTransferred is only set to nonzero if something has been read.
+ // nError can be ERROR_SUCCESS or ERROR_HANDLE_EOF
+ if(!SFileReadFile(hMpqFile, szBuffer, sizeof(szBuffer), &dwTransferred, NULL))
+ nError = GetLastError();
+ if(nError == ERROR_HANDLE_EOF)
+ nError = ERROR_SUCCESS;
+ if(dwTransferred == 0)
+ break;
+
+ // If something has been actually read, write it
+ if(!FileStream_Write(pLocalFile, NULL, szBuffer, dwTransferred))
+ nError = GetLastError();
+ }
+ }
+
+ // Close the files
+ if(hMpqFile != NULL)
+ SFileCloseFile(hMpqFile);
+ if(pLocalFile != NULL)
+ FileStream_Close(pLocalFile);
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return (nError == ERROR_SUCCESS);
+}
diff --git a/dep/StormLib/src/SFileFindFile.cpp b/dep/StormLib/src/SFileFindFile.cpp
new file mode 100644
index 00000000000..337be7d2c54
--- /dev/null
+++ b/dep/StormLib/src/SFileFindFile.cpp
@@ -0,0 +1,446 @@
+/*****************************************************************************/
+/* SFileFindFile.cpp Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* A module for file searching within MPQs */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 25.03.03 1.00 Lad The first version of SFileFindFile.cpp */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+//-----------------------------------------------------------------------------
+// Defines
+
+#define LISTFILE_CACHE_SIZE 0x1000
+
+//-----------------------------------------------------------------------------
+// Private structure used for file search (search handle)
+
+struct TMPQSearch;
+typedef int (*MPQSEARCH)(TMPQSearch *, SFILE_FIND_DATA *);
+
+// Used by searching in MPQ archives
+struct TMPQSearch
+{
+ TMPQArchive * ha; // Handle to MPQ, where the search runs
+ TFileEntry ** pSearchTable; // Table for files that have been already found
+ DWORD dwSearchTableItems; // Number of items in the search table
+ DWORD dwNextIndex; // Next file index to be checked
+ DWORD dwFlagMask; // For checking flag mask
+ char szSearchMask[1]; // Search mask (variable length)
+};
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static bool IsValidSearchHandle(TMPQSearch * hs)
+{
+ if(hs == NULL)
+ return false;
+
+ return IsValidMpqHandle(hs->ha);
+}
+
+bool CheckWildCard(const char * szString, const char * szWildCard)
+{
+ const char * szSubString;
+ int nSubStringLength;
+ int nMatchCount = 0;
+
+ // When the mask is empty, it never matches
+ if(szWildCard == NULL || *szWildCard == 0)
+ return false;
+
+ // If the wildcard contains just "*", then it always matches
+ if(szWildCard[0] == '*' && szWildCard[1] == 0)
+ return true;
+
+ // Do normal test
+ for(;;)
+ {
+ // If there is '?' in the wildcard, we skip one char
+ while(*szWildCard == '?')
+ {
+ szWildCard++;
+ szString++;
+ }
+
+ // If there is '*', means zero or more chars. We have to
+ // find the sequence after '*'
+ if(*szWildCard == '*')
+ {
+ // More stars is equal to one star
+ while(*szWildCard == '*' || *szWildCard == '?')
+ szWildCard++;
+
+ // If we found end of the wildcard, it's a match
+ if(*szWildCard == 0)
+ return true;
+
+ // Determine the length of the substring in szWildCard
+ szSubString = szWildCard;
+ while(*szSubString != 0 && *szSubString != '?' && *szSubString != '*')
+ szSubString++;
+ nSubStringLength = (int)(szSubString - szWildCard);
+ nMatchCount = 0;
+
+ // Now we have to find a substring in szString,
+ // that matches the substring in szWildCard
+ while(*szString != 0)
+ {
+ // Calculate match count
+ while(nMatchCount < nSubStringLength)
+ {
+ if(toupper(szString[nMatchCount]) != toupper(szWildCard[nMatchCount]))
+ break;
+ if(szString[nMatchCount] == 0)
+ break;
+ nMatchCount++;
+ }
+
+ // If the match count has reached substring length, we found a match
+ if(nMatchCount == nSubStringLength)
+ {
+ szWildCard += nMatchCount;
+ szString += nMatchCount;
+ break;
+ }
+
+ // No match, move to the next char in szString
+ nMatchCount = 0;
+ szString++;
+ }
+ }
+ else
+ {
+ // If we came to the end of the string, compare it to the wildcard
+ if(toupper(*szString) != toupper(*szWildCard))
+ return false;
+
+ // If we arrived to the end of the string, it's a match
+ if(*szString == 0)
+ return true;
+
+ // Otherwise, continue in comparing
+ szWildCard++;
+ szString++;
+ }
+ }
+}
+
+static DWORD GetSearchTableItems(TMPQArchive * ha)
+{
+ DWORD dwMergeItems = 0;
+
+ // Loop over all patches
+ while(ha != NULL)
+ {
+ // Append the number of files
+ dwMergeItems += (ha->pHetTable != NULL) ? ha->pHetTable->dwMaxFileCount
+ : ha->pHeader->dwBlockTableSize;
+ // Move to the patched archive
+ ha = ha->haPatch;
+ }
+
+ // Return the double size of number of items
+ return (dwMergeItems | 1);
+}
+
+static bool FileWasFoundBefore(
+ TMPQArchive * ha,
+ TMPQSearch * hs,
+ TFileEntry * pFileEntry)
+{
+ TFileEntry * pEntry;
+ char * szRealFileName = pFileEntry->szFileName;
+ DWORD dwStartIndex;
+ DWORD dwNameHash;
+ DWORD dwIndex;
+
+ if(hs->pSearchTable != NULL && szRealFileName != NULL)
+ {
+ // If we are in patch MPQ, we check if patch prefix matches
+ // and then trim the patch prefix
+ if(ha->cchPatchPrefix != 0)
+ {
+ // If the patch prefix doesn't fit, we pretend that the file
+ // was there before and it will be skipped
+ if(_strnicmp(szRealFileName, ha->szPatchPrefix, ha->cchPatchPrefix))
+ return true;
+
+ szRealFileName += ha->cchPatchPrefix;
+ }
+
+ // Calculate the hash to the table
+ dwNameHash = HashString(szRealFileName, MPQ_HASH_NAME_A);
+ dwStartIndex = dwIndex = (dwNameHash % hs->dwSearchTableItems);
+
+ // The file might have been found before
+ // only if this is not the first MPQ being searched
+ if(ha->haBase != NULL)
+ {
+ // Enumerate all entries in the search table
+ for(;;)
+ {
+ // Get the file entry at that position
+ pEntry = hs->pSearchTable[dwIndex];
+ if(pEntry == NULL)
+ break;
+
+ if(pEntry->szFileName != NULL)
+ {
+ // Does the name match?
+ if(!_stricmp(pEntry->szFileName, szRealFileName))
+ return true;
+ }
+
+ // Move to the next entry
+ dwIndex = (dwIndex + 1) % hs->dwSearchTableItems;
+ if(dwIndex == dwStartIndex)
+ break;
+ }
+ }
+
+ // Put the entry to the table for later use
+ hs->pSearchTable[dwIndex] = pFileEntry;
+ }
+ return false;
+}
+
+static TFileEntry * FindPatchEntry(TMPQArchive * ha, TFileEntry * pFileEntry)
+{
+ TFileEntry * pPatchEntry = NULL;
+ TFileEntry * pTempEntry;
+ char szFileName[MAX_PATH];
+ LCID lcLocale = pFileEntry->lcLocale;
+
+ // Go while there are patches
+ while(ha->haPatch != NULL)
+ {
+ // Move to the patch archive
+ ha = ha->haPatch;
+
+ // Prepare the prefix for the file name
+ strcpy(szFileName, ha->szPatchPrefix);
+ strcat(szFileName, pFileEntry->szFileName);
+
+ // Try to find the file there
+ pTempEntry = GetFileEntryExact(ha, szFileName, lcLocale);
+ if(pTempEntry != NULL)
+ pPatchEntry = pTempEntry;
+ }
+
+ // Return the found patch entry
+ return pPatchEntry;
+}
+
+// Performs one MPQ search
+static int DoMPQSearch(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData)
+{
+ TMPQArchive * ha = hs->ha;
+ TFileEntry * pFileTableEnd;
+ TFileEntry * pPatchEntry;
+ TFileEntry * pFileEntry;
+ const char * szFileName;
+ HANDLE hFile;
+ char szPseudoName[20];
+ DWORD dwBlockIndex;
+ size_t nPrefixLength;
+
+ // Start searching with base MPQ
+ while(ha != NULL)
+ {
+ // Now parse the file entry table in order to get all files.
+ pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
+ pFileEntry = ha->pFileTable + hs->dwNextIndex;
+
+ // Get the length of the patch prefix (0 if none)
+ nPrefixLength = strlen(ha->szPatchPrefix);
+
+ // Parse the file table
+ while(pFileEntry < pFileTableEnd)
+ {
+ // Increment the next index for subsequent search
+ hs->dwNextIndex++;
+
+ // Is it a file and not a patch file?
+ if((pFileEntry->dwFlags & hs->dwFlagMask) == MPQ_FILE_EXISTS)
+ {
+ // Now we have to check if this file was not enumerated before
+ if(!FileWasFoundBefore(ha, hs, pFileEntry))
+ {
+ // Find a patch to this file
+ pPatchEntry = FindPatchEntry(ha, pFileEntry);
+ if(pPatchEntry == NULL)
+ pPatchEntry = pFileEntry;
+
+ // Prepare the block index
+ dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable);
+
+ // Get the file name. If it's not known, we will create pseudo-name
+ szFileName = pFileEntry->szFileName;
+ if(szFileName == NULL)
+ {
+ // Open the file by its pseudo-name.
+ // This also generates the file name with a proper extension
+ sprintf(szPseudoName, "File%08u.xxx", dwBlockIndex);
+ if(SFileOpenFileEx((HANDLE)hs->ha, szPseudoName, SFILE_OPEN_FROM_MPQ, &hFile))
+ {
+ szFileName = (pFileEntry->szFileName != NULL) ? pFileEntry->szFileName : szPseudoName;
+ SFileCloseFile(hFile);
+ }
+ }
+
+ // Check the file name against the wildcard
+ if(CheckWildCard(szFileName + nPrefixLength, hs->szSearchMask))
+ {
+ // Fill the found entry
+ lpFindFileData->dwHashIndex = pPatchEntry->dwHashIndex;
+ lpFindFileData->dwBlockIndex = dwBlockIndex;
+ lpFindFileData->dwFileSize = pPatchEntry->dwFileSize;
+ lpFindFileData->dwFileFlags = pPatchEntry->dwFlags;
+ lpFindFileData->dwCompSize = pPatchEntry->dwCmpSize;
+ lpFindFileData->lcLocale = pPatchEntry->lcLocale;
+
+ // Fill the filetime
+ lpFindFileData->dwFileTimeHi = (DWORD)(pPatchEntry->FileTime >> 32);
+ lpFindFileData->dwFileTimeLo = (DWORD)(pPatchEntry->FileTime);
+
+ // Fill the file name and plain file name
+ strcpy(lpFindFileData->cFileName, szFileName + nPrefixLength);
+ lpFindFileData->szPlainName = (char *)GetPlainFileNameA(lpFindFileData->cFileName);
+ return ERROR_SUCCESS;
+ }
+
+ }
+ }
+
+ pFileEntry++;
+ }
+
+ // Move to the next patch in the patch chain
+ hs->ha = ha = ha->haPatch;
+ hs->dwNextIndex = 0;
+ }
+
+ // No more files found, return error
+ return ERROR_NO_MORE_FILES;
+}
+
+static void FreeMPQSearch(TMPQSearch *& hs)
+{
+ if(hs != NULL)
+ {
+ if(hs->pSearchTable != NULL)
+ STORM_FREE(hs->pSearchTable);
+ STORM_FREE(hs);
+ hs = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+HANDLE WINAPI SFileFindFirstFile(HANDLE hMpq, const char * szMask, SFILE_FIND_DATA * lpFindFileData, const char * szListFile)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ TMPQSearch * hs = NULL;
+ size_t nSize = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Check for the valid parameters
+ if(!IsValidMpqHandle(ha))
+ nError = ERROR_INVALID_HANDLE;
+ if(szMask == NULL || lpFindFileData == NULL)
+ nError = ERROR_INVALID_PARAMETER;
+
+ // Include the listfile into the MPQ's internal listfile
+ // Note that if the listfile name is NULL, do nothing because the
+ // internal listfile is always included.
+ if(nError == ERROR_SUCCESS && szListFile != NULL && *szListFile != 0)
+ nError = SFileAddListFile((HANDLE)ha, szListFile);
+
+ // Allocate the structure for MPQ search
+ if(nError == ERROR_SUCCESS)
+ {
+ nSize = sizeof(TMPQSearch) + strlen(szMask) + 1;
+ if((hs = (TMPQSearch *)STORM_ALLOC(char, nSize)) == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Perform the first search
+ if(nError == ERROR_SUCCESS)
+ {
+ memset(hs, 0, sizeof(TMPQSearch));
+ strcpy(&hs->szSearchMask[0], szMask);
+ hs->dwFlagMask = MPQ_FILE_EXISTS;
+ hs->ha = ha;
+
+ // If the archive is patched archive, we have to create a merge table
+ // to prevent files being repeated
+ if(ha->haPatch != NULL)
+ {
+ hs->dwSearchTableItems = GetSearchTableItems(ha);
+ hs->pSearchTable = STORM_ALLOC(TFileEntry *, hs->dwSearchTableItems);
+ hs->dwFlagMask = MPQ_FILE_EXISTS | MPQ_FILE_PATCH_FILE;
+ if(hs->pSearchTable != NULL)
+ memset(hs->pSearchTable, 0, hs->dwSearchTableItems * sizeof(TFileEntry *));
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+
+ // Perform first item searching
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = DoMPQSearch(hs, lpFindFileData);
+ }
+
+ // Cleanup
+ if(nError != ERROR_SUCCESS)
+ {
+ FreeMPQSearch(hs);
+ SetLastError(nError);
+ }
+
+ // Return the result value
+ return (HANDLE)hs;
+}
+
+bool WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData)
+{
+ TMPQSearch * hs = (TMPQSearch *)hFind;
+ int nError = ERROR_SUCCESS;
+
+ // Check the parameters
+ if(!IsValidSearchHandle(hs))
+ nError = ERROR_INVALID_HANDLE;
+ if(lpFindFileData == NULL)
+ nError = ERROR_INVALID_PARAMETER;
+
+ if(nError == ERROR_SUCCESS)
+ nError = DoMPQSearch(hs, lpFindFileData);
+
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return (nError == ERROR_SUCCESS);
+}
+
+bool WINAPI SFileFindClose(HANDLE hFind)
+{
+ TMPQSearch * hs = (TMPQSearch *)hFind;
+
+ // Check the parameters
+ if(!IsValidSearchHandle(hs))
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return false;
+ }
+
+ FreeMPQSearch(hs);
+ return true;
+}
diff --git a/dep/StormLib/src/SFileListFile.cpp b/dep/StormLib/src/SFileListFile.cpp
new file mode 100644
index 00000000000..4604206ed0a
--- /dev/null
+++ b/dep/StormLib/src/SFileListFile.cpp
@@ -0,0 +1,557 @@
+/*****************************************************************************/
+/* SListFile.cpp Copyright (c) Ladislav Zezula 2004 */
+/*---------------------------------------------------------------------------*/
+/* Description: */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 12.06.04 1.00 Lad The first version of SListFile.cpp */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+#include <assert.h>
+
+//-----------------------------------------------------------------------------
+// Listfile entry structure
+
+#define CACHE_BUFFER_SIZE 0x1000 // Size of the cache buffer
+
+struct TListFileCache
+{
+ HANDLE hFile; // Stormlib file handle
+ char * szMask; // File mask
+ DWORD dwFileSize; // Total size of the cached file
+ DWORD dwFilePos; // Position of the cache in the file
+ BYTE * pBegin; // The begin of the listfile cache
+ BYTE * pPos;
+ BYTE * pEnd; // The last character in the file cache
+
+ BYTE Buffer[CACHE_BUFFER_SIZE]; // Listfile cache itself
+};
+
+//-----------------------------------------------------------------------------
+// Local functions (cache)
+
+static TListFileCache * CreateListFileCache(HANDLE hMpq, const char * szListFile)
+{
+ TListFileCache * pCache = NULL;
+ HANDLE hListFile = NULL;
+ DWORD dwSearchScope = SFILE_OPEN_LOCAL_FILE;
+ DWORD dwBytesRead = 0;
+ int nError = ERROR_SUCCESS;
+
+ // If the szListFile is NULL, it means we have to open internal listfile
+ if(szListFile == NULL)
+ {
+ // Use SFILE_OPEN_ANY_LOCALE for listfile. This will allow us to load
+ // the listfile even if there is only non-neutral version of the listfile in the MPQ
+ dwSearchScope = SFILE_OPEN_ANY_LOCALE;
+ szListFile = LISTFILE_NAME;
+ }
+
+ // Open the local/internal listfile
+ if(SFileOpenFileEx(hMpq, szListFile, dwSearchScope, &hListFile))
+ {
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ TMPQFile * hf = (TMPQFile *)hListFile;
+
+ // Remember flags for (listfile)
+ if(hf->pFileEntry != NULL)
+ ha->dwFileFlags1 = hf->pFileEntry->dwFlags;
+ }
+ else
+ nError = GetLastError();
+
+ // Allocate cache for one file block
+ if(nError == ERROR_SUCCESS)
+ {
+ pCache = (TListFileCache *)STORM_ALLOC(TListFileCache, 1);
+ if(pCache == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ if(nError == ERROR_SUCCESS)
+ {
+ // Initialize the file cache
+ memset(pCache, 0, sizeof(TListFileCache));
+ pCache->dwFileSize = SFileGetFileSize(hListFile, NULL);
+ pCache->hFile = hListFile;
+
+ // Fill the cache
+ SFileReadFile(hListFile, pCache->Buffer, CACHE_BUFFER_SIZE, &dwBytesRead, NULL);
+ if(dwBytesRead == 0)
+ nError = GetLastError();
+ }
+
+ // Initialize the pointers
+ if(nError == ERROR_SUCCESS)
+ {
+ pCache->pBegin =
+ pCache->pPos = &pCache->Buffer[0];
+ pCache->pEnd = pCache->pBegin + dwBytesRead;
+ }
+ else
+ {
+ SListFileFindClose((HANDLE)pCache);
+ SetLastError(nError);
+ pCache = NULL;
+ }
+
+ // Return the cache
+ return pCache;
+}
+
+// Reloads the cache. Returns number of characters
+// that has been loaded into the cache.
+static DWORD ReloadListFileCache(TListFileCache * pCache)
+{
+ DWORD dwBytesToRead;
+ DWORD dwBytesRead = 0;
+
+ // Only do something if the cache is empty
+ if(pCache->pPos >= pCache->pEnd)
+ {
+// __TryReadBlock:
+
+ // Move the file position forward
+ pCache->dwFilePos += CACHE_BUFFER_SIZE;
+ if(pCache->dwFilePos >= pCache->dwFileSize)
+ return 0;
+
+ // Get the number of bytes remaining
+ dwBytesToRead = pCache->dwFileSize - pCache->dwFilePos;
+ if(dwBytesToRead > CACHE_BUFFER_SIZE)
+ dwBytesToRead = CACHE_BUFFER_SIZE;
+
+ // Load the next data chunk to the cache
+ SFileSetFilePointer(pCache->hFile, pCache->dwFilePos, NULL, FILE_BEGIN);
+ SFileReadFile(pCache->hFile, pCache->Buffer, CACHE_BUFFER_SIZE, &dwBytesRead, NULL);
+
+ // If we didn't read anything, it might mean that the block
+ // of the file is not available (in case of partial MPQs).
+ // We stop reading the file at this point, because the rest
+ // of the listfile is unreliable
+ if(dwBytesRead == 0)
+ return 0;
+
+ // Set the buffer pointers
+ pCache->pBegin =
+ pCache->pPos = &pCache->Buffer[0];
+ pCache->pEnd = pCache->pBegin + dwBytesRead;
+ }
+
+ return dwBytesRead;
+}
+
+static size_t ReadListFileLine(TListFileCache * pCache, char * szLine, int nMaxChars)
+{
+ char * szLineBegin = szLine;
+ char * szLineEnd = szLine + nMaxChars - 1;
+ char * szExtraString = NULL;
+
+ // Skip newlines, spaces, tabs and another non-printable stuff
+ for(;;)
+ {
+ // If we need to reload the cache, do it
+ if(pCache->pPos == pCache->pEnd)
+ {
+ if(ReloadListFileCache(pCache) == 0)
+ break;
+ }
+
+ // If we found a non-whitespace character, stop
+ if(*pCache->pPos > 0x20)
+ break;
+
+ // Skip the character
+ pCache->pPos++;
+ }
+
+ // Copy the remaining characters
+ while(szLine < szLineEnd)
+ {
+ // If we need to reload the cache, do it now and resume copying
+ if(pCache->pPos == pCache->pEnd)
+ {
+ if(ReloadListFileCache(pCache) == 0)
+ break;
+ }
+
+ // If we have found a newline, stop loading
+ if(*pCache->pPos == 0x0D || *pCache->pPos == 0x0A)
+ break;
+
+ // Blizzard listfiles can also contain information about patch:
+ // Pass1\Files\MacOS\unconditional\user\Background Downloader.app\Contents\Info.plist~Patch(Data#frFR#base-frFR,1326)
+ if(*pCache->pPos == '~')
+ szExtraString = szLine;
+
+ // Copy the character
+ *szLine++ = *pCache->pPos++;
+ }
+
+ // Terminate line with zero
+ *szLine = 0;
+
+ // If there was extra string after the file name, clear it
+ if(szExtraString != NULL)
+ {
+ if(szExtraString[0] == '~' && szExtraString[1] == 'P')
+ {
+ szLine = szExtraString;
+ *szExtraString = 0;
+ }
+ }
+
+ // Return the length of the line
+ return (szLine - szLineBegin);
+}
+
+static int CompareFileNodes(const void * p1, const void * p2)
+{
+ char * szFileName1 = *(char **)p1;
+ char * szFileName2 = *(char **)p2;
+
+ return _stricmp(szFileName1, szFileName2);
+}
+
+static int WriteListFileLine(
+ TMPQFile * hf,
+ const char * szLine)
+{
+ char szNewLine[2] = {0x0D, 0x0A};
+ size_t nLength = strlen(szLine);
+ int nError;
+
+ nError = SFileAddFile_Write(hf, szLine, (DWORD)nLength, MPQ_COMPRESSION_ZLIB);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ return SFileAddFile_Write(hf, szNewLine, sizeof(szNewLine), MPQ_COMPRESSION_ZLIB);
+}
+
+//-----------------------------------------------------------------------------
+// Local functions (listfile nodes)
+
+// Adds a name into the list of all names. For each locale in the MPQ,
+// one entry will be created
+// If the file name is already there, does nothing.
+int SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFileName)
+{
+ TMPQHeader * pHeader = ha->pHeader;
+ TFileEntry * pFileEntry;
+ TMPQHash * pFirstHash;
+ TMPQHash * pHash;
+ bool bNameEntryCreated = false;
+
+ // If we have HET table, use that one
+ if(ha->pHetTable != NULL)
+ {
+ pFileEntry = GetFileEntryAny(ha, szFileName);
+ if(pFileEntry != NULL)
+ {
+ // Allocate file name for the file entry
+ AllocateFileName(pFileEntry, szFileName);
+ bNameEntryCreated = true;
+ }
+
+ return ERROR_SUCCESS;
+ }
+
+ // If we have hash table, we use it
+ if(bNameEntryCreated == false && ha->pHashTable != NULL)
+ {
+ // Look for the first hash table entry for the file
+ pFirstHash = pHash = GetFirstHashEntry(ha, szFileName);
+
+ // Go while we found something
+ while(pHash != NULL)
+ {
+ // Is it a valid file table index ?
+ if(pHash->dwBlockIndex < pHeader->dwBlockTableSize)
+ {
+ // Allocate file name for the file entry
+ AllocateFileName(ha->pFileTable + pHash->dwBlockIndex, szFileName);
+ bNameEntryCreated = true;
+ }
+
+ // Now find the next language version of the file
+ pHash = GetNextHashEntry(ha, pFirstHash, pHash);
+ }
+ }
+
+ return ERROR_CAN_NOT_COMPLETE;
+}
+
+// Saves the whole listfile into the MPQ.
+int SListFileSaveToMpq(TMPQArchive * ha)
+{
+ TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
+ TFileEntry * pFileEntry;
+ TMPQFile * hf = NULL;
+ char * szPrevItem;
+ char ** SortTable = NULL;
+ DWORD dwFileSize = 0;
+ size_t nFileNodes = 0;
+ size_t i;
+ int nError = ERROR_SUCCESS;
+
+ // Allocate the table for sorting listfile
+ SortTable = STORM_ALLOC(char*, ha->dwFileTableSize);
+ if(SortTable == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Construct the sort table
+ // Note: in MPQs with multiple locale versions of the same file,
+ // this code causes adding multiple listfile entries.
+ // Since those MPQs were last time used in Starcraft,
+ // we leave it as it is.
+ for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
+ {
+ // Only take existing items
+ if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) && pFileEntry->szFileName != NULL)
+ {
+ // Ignore pseudo-names
+ if(!IsPseudoFileName(pFileEntry->szFileName, NULL) && !IsInternalMpqFileName(pFileEntry->szFileName))
+ {
+ SortTable[nFileNodes++] = pFileEntry->szFileName;
+ }
+ }
+ }
+
+ // Sort the table
+ qsort(SortTable, nFileNodes, sizeof(char *), CompareFileNodes);
+
+ // Now parse the table of file names again - remove duplicates
+ // and count file size.
+ if(nFileNodes != 0)
+ {
+ // Count the 0-th item
+ dwFileSize += (DWORD)strlen(SortTable[0]) + 2;
+ szPrevItem = SortTable[0];
+
+ // Count all next items
+ for(i = 1; i < nFileNodes; i++)
+ {
+ // If the item is the same like the last one, skip it
+ if(_stricmp(SortTable[i], szPrevItem))
+ {
+ dwFileSize += (DWORD)strlen(SortTable[i]) + 2;
+ szPrevItem = SortTable[i];
+ }
+ }
+
+ // Determine the flags for (listfile)
+ if(ha->dwFileFlags1 == 0)
+ ha->dwFileFlags1 = GetDefaultSpecialFileFlags(ha, dwFileSize);
+
+ // Create the listfile in the MPQ
+ nError = SFileAddFile_Init(ha, LISTFILE_NAME,
+ 0,
+ dwFileSize,
+ LANG_NEUTRAL,
+ ha->dwFileFlags1 | MPQ_FILE_REPLACEEXISTING,
+ &hf);
+ // Add all file names
+ if(nError == ERROR_SUCCESS)
+ {
+ // Each name is followed by newline ("\x0D\x0A")
+ szPrevItem = SortTable[0];
+ nError = WriteListFileLine(hf, SortTable[0]);
+
+ // Count all next items
+ for(i = 1; i < nFileNodes; i++)
+ {
+ // If the item is the same like the last one, skip it
+ if(_stricmp(SortTable[i], szPrevItem))
+ {
+ WriteListFileLine(hf, SortTable[i]);
+ szPrevItem = SortTable[i];
+ }
+ }
+ }
+ }
+ else
+ {
+ // Create the listfile in the MPQ
+ dwFileSize = (DWORD)strlen(LISTFILE_NAME) + 2;
+ nError = SFileAddFile_Init(ha, LISTFILE_NAME,
+ 0,
+ dwFileSize,
+ LANG_NEUTRAL,
+ MPQ_FILE_ENCRYPTED | MPQ_FILE_COMPRESS | MPQ_FILE_REPLACEEXISTING,
+ &hf);
+
+ // Just add "(listfile)" there
+ if(nError == ERROR_SUCCESS)
+ {
+ WriteListFileLine(hf, LISTFILE_NAME);
+ }
+ }
+
+ // Finalize the file in the MPQ
+ if(hf != NULL)
+ {
+ SFileAddFile_Finish(hf);
+ }
+
+ // Free buffers
+ if(nError == ERROR_SUCCESS)
+ ha->dwFlags &= ~MPQ_FLAG_INV_LISTFILE;
+ if(SortTable != NULL)
+ STORM_FREE(SortTable);
+ return nError;
+}
+
+//-----------------------------------------------------------------------------
+// File functions
+
+// Adds a listfile into the MPQ archive.
+// Note that the function does not remove the
+int WINAPI SFileAddListFile(HANDLE hMpq, const char * szListFile)
+{
+ TListFileCache * pCache = NULL;
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ char szFileName[MAX_PATH];
+ size_t nLength = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Add the listfile for each MPQ in the patch chain
+ while(ha != NULL)
+ {
+ // Load the listfile to cache
+ pCache = CreateListFileCache(hMpq, szListFile);
+ if(pCache == NULL)
+ {
+ nError = GetLastError();
+ break;
+ }
+
+ // Load the node list. Add the node for every locale in the archive
+ while((nLength = ReadListFileLine(pCache, szFileName, sizeof(szFileName))) > 0)
+ SListFileCreateNodeForAllLocales(ha, szFileName);
+
+ // Also, add three special files to the listfile:
+ // (listfile) itself, (attributes) and (signature)
+ SListFileCreateNodeForAllLocales(ha, LISTFILE_NAME);
+ SListFileCreateNodeForAllLocales(ha, SIGNATURE_NAME);
+ SListFileCreateNodeForAllLocales(ha, ATTRIBUTES_NAME);
+
+ // Delete the cache
+ SListFileFindClose((HANDLE)pCache);
+
+ // Move to the next archive in the chain
+ ha = ha->haPatch;
+ }
+
+ return nError;
+}
+
+//-----------------------------------------------------------------------------
+// Passing through the listfile
+
+HANDLE WINAPI SListFileFindFirstFile(HANDLE hMpq, const char * szListFile, const char * szMask, SFILE_FIND_DATA * lpFindFileData)
+{
+ TListFileCache * pCache = NULL;
+ size_t nLength = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Initialize the structure with zeros
+ memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA));
+
+ // Load the listfile to cache
+ pCache = CreateListFileCache(hMpq, szListFile);
+ if(pCache == NULL)
+ nError = GetLastError();
+
+ // Allocate file mask
+ if(nError == ERROR_SUCCESS && szMask != NULL)
+ {
+ pCache->szMask = STORM_ALLOC(char, strlen(szMask) + 1);
+ if(pCache->szMask != NULL)
+ strcpy(pCache->szMask, szMask);
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Perform file search
+ if(nError == ERROR_SUCCESS)
+ {
+ for(;;)
+ {
+ // Read the (next) line
+ nLength = ReadListFileLine(pCache, lpFindFileData->cFileName, sizeof(lpFindFileData->cFileName));
+ if(nLength == 0)
+ {
+ nError = ERROR_NO_MORE_FILES;
+ break;
+ }
+
+ // If some mask entered, check it
+ if(CheckWildCard(lpFindFileData->cFileName, pCache->szMask))
+ break;
+ }
+ }
+
+ // Cleanup & exit
+ if(nError != ERROR_SUCCESS)
+ {
+ memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA));
+ SListFileFindClose((HANDLE)pCache);
+ pCache = NULL;
+
+ SetLastError(nError);
+ }
+ return (HANDLE)pCache;
+}
+
+bool WINAPI SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData)
+{
+ TListFileCache * pCache = (TListFileCache *)hFind;
+ size_t nLength;
+ bool bResult = false;
+ int nError = ERROR_SUCCESS;
+
+ for(;;)
+ {
+ // Read the (next) line
+ nLength = ReadListFileLine(pCache, lpFindFileData->cFileName, sizeof(lpFindFileData->cFileName));
+ if(nLength == 0)
+ {
+ nError = ERROR_NO_MORE_FILES;
+ break;
+ }
+
+ // If some mask entered, check it
+ if(CheckWildCard(lpFindFileData->cFileName, pCache->szMask))
+ {
+ bResult = true;
+ break;
+ }
+ }
+
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return bResult;
+}
+
+bool WINAPI SListFileFindClose(HANDLE hFind)
+{
+ TListFileCache * pCache = (TListFileCache *)hFind;
+
+ if(pCache != NULL)
+ {
+ if(pCache->hFile != NULL)
+ SFileCloseFile(pCache->hFile);
+ if(pCache->szMask != NULL)
+ STORM_FREE(pCache->szMask);
+
+ STORM_FREE(pCache);
+ return true;
+ }
+
+ return false;
+}
+
diff --git a/dep/StormLib/src/SFileOpenArchive.cpp b/dep/StormLib/src/SFileOpenArchive.cpp
new file mode 100644
index 00000000000..b36b7d35ea7
--- /dev/null
+++ b/dep/StormLib/src/SFileOpenArchive.cpp
@@ -0,0 +1,470 @@
+/*****************************************************************************/
+/* SFileOpenArchive.cpp Copyright Ladislav Zezula 1999 */
+/* */
+/* Author : Ladislav Zezula */
+/* E-mail : ladik@zezula.net */
+/* WWW : www.zezula.net */
+/*---------------------------------------------------------------------------*/
+/* Archive functions of Storm.dll */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* xx.xx.xx 1.00 Lad The first version of SFileOpenArchive.cpp */
+/* 19.11.03 1.01 Dan Big endian handling */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+/*****************************************************************************/
+/* Local functions */
+/*****************************************************************************/
+
+static bool IsAviFile(void * pvFileBegin)
+{
+ LPDWORD AviHeader = (DWORD *)pvFileBegin;
+ DWORD DwordValue0 = BSWAP_INT32_UNSIGNED(AviHeader[0]);
+ DWORD DwordValue2 = BSWAP_INT32_UNSIGNED(AviHeader[2]);
+ DWORD DwordValue3 = BSWAP_INT32_UNSIGNED(AviHeader[3]);
+
+ // Test for 'RIFF', 'AVI ' or 'LIST'
+ return (DwordValue0 == 0x46464952 && DwordValue2 == 0x20495641 && DwordValue3 == 0x5453494C);
+}
+
+static TFileBitmap * CreateFileBitmap(TMPQArchive * ha, TMPQBitmap * pMpqBitmap, bool bFileIsComplete)
+{
+ TFileBitmap * pBitmap;
+ size_t nLength;
+
+ // Calculate the length of the bitmap in blocks and in bytes
+ nLength = (size_t)(((ha->pHeader->ArchiveSize64 - 1) / pMpqBitmap->dwBlockSize) + 1);
+ nLength = (size_t)(((nLength - 1) / 8) + 1);
+
+ // Allocate the file bitmap
+ pBitmap = (TFileBitmap *)STORM_ALLOC(BYTE, sizeof(TFileBitmap) + nLength);
+ if(pBitmap != NULL)
+ {
+ // Fill the structure
+ pBitmap->StartOffset = ha->MpqPos;
+ pBitmap->EndOffset = ha->MpqPos + ha->pHeader->ArchiveSize64;
+ pBitmap->IsComplete = bFileIsComplete ? 1 : 0;
+ pBitmap->BitmapSize = (DWORD)nLength;
+ pBitmap->BlockSize = pMpqBitmap->dwBlockSize;
+ pBitmap->Reserved = 0;
+
+ // Copy the file bitmap
+ memcpy((pBitmap + 1), (pMpqBitmap + 1), nLength);
+ }
+
+ return pBitmap;
+}
+
+// This function gets the right positions of the hash table and the block table.
+static int VerifyMpqTablePositions(TMPQArchive * ha, ULONGLONG FileSize)
+{
+ TMPQHeader * pHeader = ha->pHeader;
+ ULONGLONG ByteOffset;
+
+ // Check the begin of HET table
+ if(pHeader->HetTablePos64)
+ {
+ ByteOffset = ha->MpqPos + pHeader->HetTablePos64;
+ if(ByteOffset > FileSize)
+ return ERROR_BAD_FORMAT;
+ }
+
+ // Check the begin of BET table
+ if(pHeader->BetTablePos64)
+ {
+ ByteOffset = ha->MpqPos + pHeader->BetTablePos64;
+ if(ByteOffset > FileSize)
+ return ERROR_BAD_FORMAT;
+ }
+
+ // Check the begin of hash table
+ if(pHeader->wHashTablePosHi || pHeader->dwHashTablePos)
+ {
+ ByteOffset = ha->MpqPos + MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos);
+ if(ByteOffset > FileSize)
+ return ERROR_BAD_FORMAT;
+ }
+
+ // Check the begin of block table
+ if(pHeader->wBlockTablePosHi || pHeader->dwBlockTablePos)
+ {
+ ByteOffset = ha->MpqPos + MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
+ if(ByteOffset > FileSize)
+ return ERROR_BAD_FORMAT;
+ }
+
+ // Check the begin of hi-block table
+ if(pHeader->HiBlockTablePos64 != 0)
+ {
+ ByteOffset = ha->MpqPos + pHeader->HiBlockTablePos64;
+ if(ByteOffset > FileSize)
+ return ERROR_BAD_FORMAT;
+ }
+
+ // All OK.
+ return ERROR_SUCCESS;
+}
+
+
+/*****************************************************************************/
+/* Public functions */
+/*****************************************************************************/
+
+//-----------------------------------------------------------------------------
+// SFileGetLocale and SFileSetLocale
+// Set the locale for all newly opened files
+
+LCID WINAPI SFileGetLocale()
+{
+ return lcFileLocale;
+}
+
+LCID WINAPI SFileSetLocale(LCID lcNewLocale)
+{
+ lcFileLocale = lcNewLocale;
+ return lcFileLocale;
+}
+
+//-----------------------------------------------------------------------------
+// SFileOpenArchive
+//
+// szFileName - MPQ archive file name to open
+// dwPriority - When SFileOpenFileEx called, this contains the search priority for searched archives
+// dwFlags - See MPQ_OPEN_XXX in StormLib.h
+// phMpq - Pointer to store open archive handle
+
+bool WINAPI SFileOpenArchive(
+ const TCHAR * szMpqName,
+ DWORD dwPriority,
+ DWORD dwFlags,
+ HANDLE * phMpq)
+{
+ TFileStream * pStream = NULL; // Open file stream
+ TMPQArchive * ha = NULL; // Archive handle
+ ULONGLONG FileSize = 0; // Size of the file
+ int nError = ERROR_SUCCESS;
+
+ // Verify the parameters
+ if(szMpqName == NULL || *szMpqName == 0 || phMpq == NULL)
+ nError = ERROR_INVALID_PARAMETER;
+
+ // One time initialization of MPQ cryptography
+ InitializeMpqCryptography();
+ dwPriority = dwPriority;
+
+ // Open the MPQ archive file
+ if(nError == ERROR_SUCCESS)
+ {
+ // Initialize the stream
+ pStream = FileStream_OpenFile(szMpqName, (dwFlags & STREAM_OPTIONS_MASK));
+ if(pStream == NULL)
+ nError = GetLastError();
+ }
+
+ // Allocate the MPQhandle
+ if(nError == ERROR_SUCCESS)
+ {
+ FileStream_GetSize(pStream, FileSize);
+ if((ha = STORM_ALLOC(TMPQArchive, 1)) == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Initialize handle structure and allocate structure for MPQ header
+ if(nError == ERROR_SUCCESS)
+ {
+ memset(ha, 0, sizeof(TMPQArchive));
+ ha->pStream = pStream;
+ pStream = NULL;
+
+ // Remember if the archive is open for write
+ if(FileStream_IsReadOnly(ha->pStream))
+ ha->dwFlags |= MPQ_FLAG_READ_ONLY;
+
+ // Also remember if we shall check sector CRCs when reading file
+ if(dwFlags & MPQ_OPEN_CHECK_SECTOR_CRC)
+ ha->dwFlags |= MPQ_FLAG_CHECK_SECTOR_CRC;
+ }
+
+ // Find the offset of MPQ header within the file
+ if(nError == ERROR_SUCCESS)
+ {
+ ULONGLONG SearchPos = 0;
+ DWORD dwHeaderID;
+
+ while(SearchPos < FileSize)
+ {
+ DWORD dwBytesAvailable = MPQ_HEADER_SIZE_V4;
+
+ // Cut the bytes available, if needed
+ if((FileSize - SearchPos) < MPQ_HEADER_SIZE_V4)
+ dwBytesAvailable = (DWORD)(FileSize - SearchPos);
+
+ // Read the eventual MPQ header
+ if(!FileStream_Read(ha->pStream, &SearchPos, ha->HeaderData, dwBytesAvailable))
+ {
+ nError = GetLastError();
+ break;
+ }
+
+ // There are AVI files from Warcraft III with 'MPQ' extension.
+ if(SearchPos == 0 && IsAviFile(ha->HeaderData))
+ {
+ nError = ERROR_AVI_FILE;
+ break;
+ }
+
+ // If there is the MPQ user data signature, process it
+ dwHeaderID = BSWAP_INT32_UNSIGNED(*(LPDWORD)ha->HeaderData);
+ if(dwHeaderID == ID_MPQ_USERDATA && ha->pUserData == NULL)
+ {
+ // Ignore the MPQ user data completely if the caller wants to open the MPQ as V1.0
+ if((dwFlags & MPQ_OPEN_FORCE_MPQ_V1) == 0)
+ {
+ // Fill the user data header
+ ha->pUserData = &ha->UserData;
+ memcpy(ha->pUserData, ha->HeaderData, sizeof(TMPQUserData));
+ BSWAP_TMPQUSERDATA(ha->pUserData);
+
+ // Remember the position of the user data and continue search
+ ha->UserDataPos = SearchPos;
+ SearchPos += ha->pUserData->dwHeaderOffs;
+ continue;
+ }
+ }
+
+ // There must be MPQ header signature
+ if(dwHeaderID == ID_MPQ)
+ {
+ // Save the position where the MPQ header has been found
+ if(ha->pUserData == NULL)
+ ha->UserDataPos = SearchPos;
+ ha->pHeader = (TMPQHeader *)ha->HeaderData;
+ ha->MpqPos = SearchPos;
+
+ // Now convert the header to version 4
+ BSWAP_TMPQHEADER(ha->pHeader);
+ nError = ConvertMpqHeaderToFormat4(ha, FileSize, dwFlags);
+ break;
+ }
+
+ // Move to the next possible offset
+ SearchPos += 0x200;
+ }
+
+ // If we haven't found MPQ header in the file, it's an error
+ if(ha->pHeader == NULL)
+ nError = ERROR_BAD_FORMAT;
+ }
+
+ // Fix table positions according to format
+ if(nError == ERROR_SUCCESS)
+ {
+ // Dump the header
+// DumpMpqHeader(ha->pHeader);
+
+ // W3x Map Protectors use the fact that War3's Storm.dll ignores the MPQ user data,
+ // and probably ignores the MPQ format version as well. The trick is to
+ // fake MPQ format 2, with an improper hi-word position of hash table and block table
+ // We can overcome such protectors by forcing opening the archive as MPQ v 1.0
+ if(dwFlags & MPQ_OPEN_FORCE_MPQ_V1)
+ {
+ ha->pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1;
+ ha->pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1;
+ ha->dwFlags |= MPQ_FLAG_READ_ONLY;
+ ha->pUserData = NULL;
+ }
+
+ // Both MPQ_OPEN_NO_LISTFILE or MPQ_OPEN_NO_ATTRIBUTES trigger read only mode
+ if(dwFlags & (MPQ_OPEN_NO_LISTFILE | MPQ_OPEN_NO_ATTRIBUTES))
+ ha->dwFlags |= MPQ_FLAG_READ_ONLY;
+
+ // Set the size of file sector
+ ha->dwSectorSize = (0x200 << ha->pHeader->wSectorSize);
+
+ // Verify if any of the tables doesn't start beyond the end of the file
+ nError = VerifyMpqTablePositions(ha, FileSize);
+ }
+
+ // Check if the MPQ has data bitmap. If yes, we can verify if the MPQ is complete
+ if(nError == ERROR_SUCCESS && ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_4)
+ {
+ TFileBitmap * pBitmap;
+ bool bFileIsComplete = true;
+
+ LoadMpqDataBitmap(ha, FileSize, &bFileIsComplete);
+ if(ha->pBitmap != NULL && bFileIsComplete == false)
+ {
+ // Convert the MPQ bitmap to the file bitmap
+ pBitmap = CreateFileBitmap(ha, ha->pBitmap, bFileIsComplete);
+
+ // Set the data bitmap into the file stream for additional checks
+ FileStream_SetBitmap(ha->pStream, pBitmap);
+ ha->dwFlags |= MPQ_FLAG_READ_ONLY;
+ }
+ }
+
+ // Read the hash table. Ignore the result, as hash table is no longer required
+ // Read HET table. Ignore the result, as HET table is no longer required
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = LoadAnyHashTable(ha);
+ }
+
+ // Now, build the file table. It will be built by combining
+ // the block table, BET table, hi-block table, (attributes) and (listfile).
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = BuildFileTable(ha, FileSize);
+ }
+
+ // Verify the file table, if no kind of protection was detected
+ if(nError == ERROR_SUCCESS && (ha->dwFlags & MPQ_FLAG_PROTECTED) == 0)
+ {
+ TFileEntry * pFileTableEnd = ha->pFileTable + ha->pHeader->dwBlockTableSize;
+ TFileEntry * pFileEntry = ha->pFileTable;
+// ULONGLONG ArchiveSize = 0;
+ ULONGLONG RawFilePos;
+
+ // Parse all file entries
+ for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
+ {
+ // If that file entry is valid, check the file position
+ if(pFileEntry->dwFlags & MPQ_FILE_EXISTS)
+ {
+ // Get the 64-bit file position,
+ // relative to the begin of the file
+ RawFilePos = ha->MpqPos + pFileEntry->ByteOffset;
+
+ // Begin of the file must be within range
+ if(RawFilePos > FileSize)
+ {
+ nError = ERROR_FILE_CORRUPT;
+ break;
+ }
+
+ // End of the file must be within range
+ RawFilePos += pFileEntry->dwCmpSize;
+ if(RawFilePos > FileSize)
+ {
+ nError = ERROR_FILE_CORRUPT;
+ break;
+ }
+
+ // Also, we remember end of the file
+// if(RawFilePos > ArchiveSize)
+// ArchiveSize = RawFilePos;
+ }
+ }
+ }
+
+ // Load the internal listfile and include it to the file table
+ if(nError == ERROR_SUCCESS && (dwFlags & MPQ_OPEN_NO_LISTFILE) == 0)
+ {
+ // Ignore result of the operation. (listfile) is optional.
+ SFileAddListFile((HANDLE)ha, NULL);
+ }
+
+ // Load the "(attributes)" file and merge it to the file table
+ if(nError == ERROR_SUCCESS && (dwFlags & MPQ_OPEN_NO_ATTRIBUTES) == 0)
+ {
+ // Ignore result of the operation. (attributes) is optional.
+ SAttrLoadAttributes(ha);
+ }
+
+ // Cleanup and exit
+ if(nError != ERROR_SUCCESS)
+ {
+ FileStream_Close(pStream);
+ FreeMPQArchive(ha);
+ SetLastError(nError);
+ ha = NULL;
+ }
+
+ *phMpq = ha;
+ return (nError == ERROR_SUCCESS);
+}
+
+//-----------------------------------------------------------------------------
+// SFileGetArchiveBitmap
+
+bool WINAPI SFileGetArchiveBitmap(HANDLE hMpq, TFileBitmap * pBitmap, DWORD Length, LPDWORD LengthNeeded)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+
+ return FileStream_GetBitmap(ha->pStream, pBitmap, Length, LengthNeeded);
+}
+
+//-----------------------------------------------------------------------------
+// bool SFileFlushArchive(HANDLE hMpq)
+//
+// Saves all dirty data into MPQ archive.
+// Has similar effect like SFileCloseArchive, but the archive is not closed.
+// Use on clients who keep MPQ archive open even for write operations,
+// and terminating without calling SFileCloseArchive might corrupt the archive.
+//
+
+bool WINAPI SFileFlushArchive(HANDLE hMpq)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ int nResultError = ERROR_SUCCESS;
+ int nError;
+
+ // Do nothing if 'hMpq' is bad parameter
+ if(!IsValidMpqHandle(ha))
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return false;
+ }
+
+ // If the (listfile) has been invalidated, save it
+ if(ha->dwFlags & MPQ_FLAG_INV_LISTFILE)
+ {
+ nError = SListFileSaveToMpq(ha);
+ if(nError != ERROR_SUCCESS)
+ nResultError = nError;
+ }
+
+ // If the (attributes) has been invalidated, save it
+ if(ha->dwFlags & MPQ_FLAG_INV_ATTRIBUTES)
+ {
+ nError = SAttrFileSaveToMpq(ha);
+ if(nError != ERROR_SUCCESS)
+ nResultError = nError;
+ }
+
+ // Save HET table, BET table, hash table, block table, hi-block table
+ if(ha->dwFlags & MPQ_FLAG_CHANGED)
+ {
+ nError = SaveMPQTables(ha);
+ if(nError != ERROR_SUCCESS)
+ nResultError = nError;
+ }
+
+ // Return the error
+ if(nResultError != ERROR_SUCCESS)
+ SetLastError(nResultError);
+ return (nResultError == ERROR_SUCCESS);
+}
+
+//-----------------------------------------------------------------------------
+// bool SFileCloseArchive(HANDLE hMpq);
+//
+
+bool WINAPI SFileCloseArchive(HANDLE hMpq)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ bool bResult;
+
+ // Flush all unsaved data to the storage
+ bResult = SFileFlushArchive(hMpq);
+
+ // Free all memory used by MPQ archive
+ FreeMPQArchive(ha);
+ return bResult;
+}
+
diff --git a/dep/StormLib/src/SFileOpenFileEx.cpp b/dep/StormLib/src/SFileOpenFileEx.cpp
new file mode 100644
index 00000000000..e03a8b17998
--- /dev/null
+++ b/dep/StormLib/src/SFileOpenFileEx.cpp
@@ -0,0 +1,469 @@
+/*****************************************************************************/
+/* SFileOpenFileEx.cpp Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Description : */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* xx.xx.99 1.00 Lad The first version of SFileOpenFileEx.cpp */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+/*****************************************************************************/
+/* Local functions */
+/*****************************************************************************/
+
+static bool OpenLocalFile(const char * szFileName, HANDLE * phFile)
+{
+ TFileStream * pStream;
+ TMPQFile * hf = NULL;
+
+ // We have to convert the local file name to UNICODE, if needed
+#ifdef _UNICODE
+ TCHAR szFileNameT[MAX_PATH];
+ int i;
+
+ for(i = 0; szFileName[i] != 0; i++)
+ szFileNameT[i] = szFileName[i];
+ szFileNameT[i] = 0;
+ pStream = FileStream_OpenFile(szFileNameT, STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE);
+
+#else
+ pStream = FileStream_OpenFile(szFileName, STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE);
+#endif
+
+ if(pStream != NULL)
+ {
+ // Allocate and initialize file handle
+ hf = CreateMpqFile(NULL);
+ if(hf != NULL)
+ {
+ hf->pStream = pStream;
+ *phFile = hf;
+ return true;
+ }
+ else
+ {
+ FileStream_Close(pStream);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ }
+ *phFile = NULL;
+ return false;
+}
+
+bool OpenPatchedFile(HANDLE hMpq, const char * szFileName, DWORD dwReserved, HANDLE * phFile)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ TMPQFile * hfPatch; // Pointer to patch file
+ TMPQFile * hfBase = NULL; // Pointer to base open file
+ TMPQFile * hfLast = NULL; // The highest file in the chain that is not patch file
+ TMPQFile * hf = NULL;
+ HANDLE hPatchFile;
+ char szPatchFileName[MAX_PATH];
+
+ // Keep this flag here for future updates
+ dwReserved = dwReserved;
+
+ // First of all, try to open the original version of the file in any of the patch chain
+ while(ha != NULL)
+ {
+ // Construct the name of the patch file
+ strcpy(szPatchFileName, ha->szPatchPrefix);
+ strcpy(&szPatchFileName[ha->cchPatchPrefix], szFileName);
+ if(SFileOpenFileEx((HANDLE)ha, szPatchFileName, SFILE_OPEN_FROM_MPQ, (HANDLE *)&hfBase))
+ {
+ // The file must be a base file, i.e. without MPQ_FILE_PATCH_FILE
+ if((hfBase->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0)
+ {
+ hf = hfLast = hfBase;
+ break;
+ }
+
+ SFileCloseFile((HANDLE)hfBase);
+ }
+
+ // Move to the next file in the patch chain
+ ha = ha->haPatch;
+ }
+
+ // If we couldn't find the file in any of the patches, it doesn't exist
+ if(hf == NULL)
+ {
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ return false;
+ }
+
+ // Now keep going in the patch chain and open every patch file that is there
+ for(ha = ha->haPatch; ha != NULL; ha = ha->haPatch)
+ {
+ // Construct patch file name
+ strcpy(szPatchFileName, ha->szPatchPrefix);
+ strcpy(&szPatchFileName[ha->cchPatchPrefix], szFileName);
+ if(SFileOpenFileEx((HANDLE)ha, szPatchFileName, SFILE_OPEN_FROM_MPQ, &hPatchFile))
+ {
+ // Remember the new version
+ hfPatch = (TMPQFile *)hPatchFile;
+
+ // If we encountered a full replacement of the file,
+ // we have to remember the highest full file
+ if((hfPatch->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0)
+ hfLast = hfPatch;
+
+ // Set current patch to base file and move on
+ hf->hfPatchFile = hfPatch;
+ hf = hfPatch;
+ }
+ }
+
+ // Now we need to free all files that are below the highest unpatched version
+ while(hfBase != hfLast)
+ {
+ TMPQFile * hfNext = hfBase->hfPatchFile;
+
+ // Free the file below
+ hfBase->hfPatchFile = NULL;
+ FreeMPQFile(hfBase);
+
+ // Move the base to the next file
+ hfBase = hfNext;
+ }
+
+ // Give the updated base MPQ
+ if(phFile != NULL)
+ *phFile = (HANDLE)hfBase;
+ return true;
+}
+
+/*****************************************************************************/
+/* Public functions */
+/*****************************************************************************/
+
+//-----------------------------------------------------------------------------
+// SFileEnumLocales enums all locale versions within MPQ.
+// Functions fills all available language identifiers on a file into the buffer
+// pointed by plcLocales. There must be enough entries to copy the localed,
+// otherwise the function returns ERROR_INSUFFICIENT_BUFFER.
+
+int WINAPI SFileEnumLocales(
+ HANDLE hMpq,
+ const char * szFileName,
+ LCID * plcLocales,
+ LPDWORD pdwMaxLocales,
+ DWORD dwSearchScope)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ TFileEntry * pFileEntry;
+ TMPQHash * pFirstHash;
+ TMPQHash * pHash;
+ DWORD dwFileIndex = 0;
+ DWORD dwLocales = 0;
+
+ // Test the parameters
+ if(!IsValidMpqHandle(ha))
+ return ERROR_INVALID_HANDLE;
+ if(szFileName == NULL || *szFileName == 0)
+ return ERROR_INVALID_PARAMETER;
+ if(pdwMaxLocales == NULL)
+ return ERROR_INVALID_PARAMETER;
+
+ // Keep compiler happy
+ dwSearchScope = dwSearchScope;
+
+ // Parse hash table entries for all locales
+ if(!IsPseudoFileName(szFileName, &dwFileIndex))
+ {
+ // Calculate the number of locales
+ pFirstHash = pHash = GetFirstHashEntry(ha, szFileName);
+ while(pHash != NULL)
+ {
+ dwLocales++;
+ pHash = GetNextHashEntry(ha, pFirstHash, pHash);
+ }
+
+ // Test if there is enough space to copy the locales
+ if(*pdwMaxLocales < dwLocales)
+ {
+ *pdwMaxLocales = dwLocales;
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ // Enum the locales
+ pFirstHash = pHash = GetFirstHashEntry(ha, szFileName);
+ while(pHash != NULL)
+ {
+ *plcLocales++ = pHash->lcLocale;
+ pHash = GetNextHashEntry(ha, pFirstHash, pHash);
+ }
+ }
+ else
+ {
+ // There must be space for 1 locale
+ if(*pdwMaxLocales < 1)
+ {
+ *pdwMaxLocales = 1;
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ // For nameless access, always return 1 locale
+ pFileEntry = GetFileEntryByIndex(ha, dwFileIndex);
+ pHash = ha->pHashTable + pFileEntry->dwHashIndex;
+ *plcLocales = pHash->lcLocale;
+ dwLocales = 1;
+ }
+
+ // Give the caller the total number of found locales
+ *pdwMaxLocales = dwLocales;
+ return ERROR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// SFileHasFile
+//
+// hMpq - Handle of opened MPQ archive
+// szFileName - Name of file to look for
+
+bool WINAPI SFileHasFile(HANDLE hMpq, const char * szFileName)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ TFileEntry * pFileEntry;
+ DWORD dwFlagsToCheck = MPQ_FILE_EXISTS;
+ DWORD dwFileIndex = 0;
+ char szPatchFileName[MAX_PATH];
+ bool bIsPseudoName;
+ int nError = ERROR_SUCCESS;
+
+ if(!IsValidMpqHandle(ha))
+ nError = ERROR_INVALID_HANDLE;
+ if(szFileName == NULL || *szFileName == 0)
+ nError = ERROR_INVALID_PARAMETER;
+
+ // Prepare the file opening
+ if(nError == ERROR_SUCCESS)
+ {
+ // Different processing for pseudo-names
+ bIsPseudoName = IsPseudoFileName(szFileName, &dwFileIndex);
+
+ // Walk through the MPQ and all patches
+ while(ha != NULL)
+ {
+ // Verify presence of the file
+ pFileEntry = (bIsPseudoName == false) ? GetFileEntryLocale(ha, szFileName, lcFileLocale)
+ : GetFileEntryByIndex(ha, dwFileIndex);
+ // Verify the file flags
+ if(pFileEntry != NULL && (pFileEntry->dwFlags & dwFlagsToCheck) == MPQ_FILE_EXISTS)
+ return true;
+
+ // If this is patched archive, go to the patch
+ dwFlagsToCheck = MPQ_FILE_EXISTS | MPQ_FILE_PATCH_FILE;
+ ha = ha->haPatch;
+
+ // Prepare the patched file name
+ if(ha != NULL)
+ {
+ strcpy(szPatchFileName, ha->szPatchPrefix);
+ strcat(szPatchFileName, szFileName);
+ szFileName = szPatchFileName;
+ }
+ }
+
+ // Not found, sorry
+ nError = ERROR_FILE_NOT_FOUND;
+ }
+
+ // Cleanup
+ SetLastError(nError);
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// SFileOpenFileEx
+//
+// hMpq - Handle of opened MPQ archive
+// szFileName - Name of file to open
+// dwSearchScope - Where to search
+// phFile - Pointer to store opened file handle
+
+bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ TFileEntry * pFileEntry = NULL;
+ TMPQFile * hf = NULL;
+ DWORD dwFileIndex = 0;
+ bool bOpenByIndex = false;
+ int nError = ERROR_SUCCESS;
+
+ // Don't accept NULL pointer to file handle
+ if(phFile == NULL)
+ nError = ERROR_INVALID_PARAMETER;
+
+ // Prepare the file opening
+ if(nError == ERROR_SUCCESS)
+ {
+ switch(dwSearchScope)
+ {
+ case SFILE_OPEN_PATCHED_FILE:
+
+ // We want to open the updated version of the file
+ return OpenPatchedFile(hMpq, szFileName, 0, phFile);
+
+ case SFILE_OPEN_FROM_MPQ:
+
+ if(!IsValidMpqHandle(ha))
+ {
+ nError = ERROR_INVALID_HANDLE;
+ break;
+ }
+
+ if(szFileName == NULL || *szFileName == 0)
+ {
+ nError = ERROR_INVALID_PARAMETER;
+ break;
+ }
+
+ // First of all, check the name as-is
+ if(!IsPseudoFileName(szFileName, &dwFileIndex))
+ {
+ pFileEntry = GetFileEntryLocale(ha, szFileName, lcFileLocale);
+ if(pFileEntry == NULL)
+ nError = ERROR_FILE_NOT_FOUND;
+ }
+ else
+ {
+ bOpenByIndex = true;
+ pFileEntry = GetFileEntryByIndex(ha, dwFileIndex);
+ if(pFileEntry == NULL)
+ nError = ERROR_FILE_NOT_FOUND;
+ }
+ break;
+
+ case SFILE_OPEN_ANY_LOCALE:
+
+ // This open option is reserved for opening MPQ internal listfile.
+ // No argument validation. Tries to open file with neutral locale first,
+ // then any other available.
+ dwSearchScope = SFILE_OPEN_FROM_MPQ;
+ pFileEntry = GetFileEntryAny(ha, szFileName);
+ if(pFileEntry == NULL)
+ nError = ERROR_FILE_NOT_FOUND;
+ break;
+
+ case SFILE_OPEN_LOCAL_FILE:
+
+ if(szFileName == NULL || *szFileName == 0)
+ {
+ nError = ERROR_INVALID_PARAMETER;
+ break;
+ }
+
+ return OpenLocalFile(szFileName, phFile);
+
+ default:
+
+ // Don't accept any other value
+ nError = ERROR_INVALID_PARAMETER;
+ break;
+ }
+
+ // Quick return if something failed
+ if(nError != ERROR_SUCCESS)
+ {
+ SetLastError(nError);
+ return false;
+ }
+ }
+
+ // Test if the file was not already deleted.
+ if(nError == ERROR_SUCCESS)
+ {
+ if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0)
+ nError = ERROR_FILE_NOT_FOUND;
+ if(pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS)
+ nError = ERROR_NOT_SUPPORTED;
+ }
+
+ // Allocate file handle
+ if(nError == ERROR_SUCCESS)
+ {
+ if((hf = STORM_ALLOC(TMPQFile, 1)) == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Initialize file handle
+ if(nError == ERROR_SUCCESS)
+ {
+ memset(hf, 0, sizeof(TMPQFile));
+ hf->pFileEntry = pFileEntry;
+ hf->dwMagic = ID_MPQ_FILE;
+ hf->ha = ha;
+
+ hf->MpqFilePos = pFileEntry->ByteOffset;
+ hf->RawFilePos = ha->MpqPos + hf->MpqFilePos;
+ hf->dwDataSize = pFileEntry->dwFileSize;
+
+ // If the MPQ has sector CRC enabled, enable if for the file
+ if(ha->dwFlags & MPQ_FLAG_CHECK_SECTOR_CRC)
+ hf->bCheckSectorCRCs = true;
+
+ // If we know the real file name, copy it to the file entry
+ if(bOpenByIndex == false)
+ {
+ // If there is no file name yet, allocate it
+ AllocateFileName(pFileEntry, szFileName);
+
+ // If the file is encrypted, we should detect the file key
+ if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
+ {
+ hf->dwFileKey = DecryptFileKey(szFileName,
+ pFileEntry->ByteOffset,
+ pFileEntry->dwFileSize,
+ pFileEntry->dwFlags);
+ }
+ }
+ else
+ {
+ // Try to auto-detect the file name
+ if(!SFileGetFileName(hf, NULL))
+ nError = GetLastError();
+ }
+ }
+
+ // If the file is actually a patch file, we have to load the patch file header
+ if(nError == ERROR_SUCCESS && pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE)
+ {
+ assert(hf->pPatchInfo == NULL);
+ nError = AllocatePatchInfo(hf, true);
+ }
+
+ // Cleanup
+ if(nError != ERROR_SUCCESS)
+ {
+ SetLastError(nError);
+ FreeMPQFile(hf);
+ }
+
+ *phFile = hf;
+ return (nError == ERROR_SUCCESS);
+}
+
+//-----------------------------------------------------------------------------
+// bool WINAPI SFileCloseFile(HANDLE hFile);
+
+bool WINAPI SFileCloseFile(HANDLE hFile)
+{
+ TMPQFile * hf = (TMPQFile *)hFile;
+
+ if(!IsValidFileHandle(hf))
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return false;
+ }
+
+ // Free the structure
+ FreeMPQFile(hf);
+ return true;
+}
diff --git a/dep/StormLib/src/SFilePatchArchives.cpp b/dep/StormLib/src/SFilePatchArchives.cpp
new file mode 100644
index 00000000000..24ae2c52c37
--- /dev/null
+++ b/dep/StormLib/src/SFilePatchArchives.cpp
@@ -0,0 +1,587 @@
+/*****************************************************************************/
+/* SFilePatchArchives.cpp Copyright (c) Ladislav Zezula 2010 */
+/*---------------------------------------------------------------------------*/
+/* Description: */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 18.08.10 1.00 Lad The first version of SFilePatchArchives.cpp */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+//-----------------------------------------------------------------------------
+// Local structures
+
+typedef struct _BLIZZARD_BSDIFF40_FILE
+{
+ ULONGLONG Signature;
+ ULONGLONG CtrlBlockSize;
+ ULONGLONG DataBlockSize;
+ ULONGLONG NewFileSize;
+} BLIZZARD_BSDIFF40_FILE, *PBLIZZARD_BSDIFF40_FILE;
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static bool GetDefaultPatchPrefix(
+ const TCHAR * szBaseMpqName,
+ char * szBuffer)
+{
+ const TCHAR * szExtension;
+ const TCHAR * szDash;
+
+ // Ensure that both names are plain names
+ szBaseMpqName = GetPlainFileNameT(szBaseMpqName);
+
+ // Patch prefix is for the Cataclysm MPQs, whose names
+ // are like "locale-enGB.MPQ" or "speech-enGB.MPQ"
+ szExtension = _tcsrchr(szBaseMpqName, _T('.'));
+ szDash = _tcsrchr(szBaseMpqName, _T('-'));
+ strcpy(szBuffer, "Base");
+
+ // If the length of the prefix doesn't match, use default one
+ if(szExtension != NULL && szDash != NULL && (szExtension - szDash) == 5)
+ {
+ // Copy the prefix
+ szBuffer[0] = (char)szDash[1];
+ szBuffer[1] = (char)szDash[2];
+ szBuffer[2] = (char)szDash[3];
+ szBuffer[3] = (char)szDash[4];
+ szBuffer[4] = 0;
+ }
+
+ return true;
+}
+
+static void Decompress_RLE(LPBYTE pbDecompressed, DWORD cbDecompressed, LPBYTE pbCompressed, DWORD cbCompressed)
+{
+ LPBYTE pbDecompressedEnd = pbDecompressed + cbDecompressed;
+ LPBYTE pbCompressedEnd = pbCompressed + cbCompressed;
+ BYTE RepeatCount;
+ BYTE OneByte;
+
+ // Cut the initial DWORD from the compressed chunk
+ pbCompressed += sizeof(DWORD);
+ cbCompressed -= sizeof(DWORD);
+
+ // Pre-fill decompressed buffer with zeros
+ memset(pbDecompressed, 0, cbDecompressed);
+
+ // Unpack
+ while(pbCompressed < pbCompressedEnd && pbDecompressed < pbDecompressedEnd)
+ {
+ OneByte = *pbCompressed++;
+
+ // Is it a repetition byte ?
+ if(OneByte & 0x80)
+ {
+ RepeatCount = (OneByte & 0x7F) + 1;
+ for(BYTE i = 0; i < RepeatCount; i++)
+ {
+ if(pbDecompressed == pbDecompressedEnd || pbCompressed == pbCompressedEnd)
+ break;
+
+ *pbDecompressed++ = *pbCompressed++;
+ }
+ }
+ else
+ {
+ pbDecompressed += (OneByte + 1);
+ }
+ }
+}
+
+static int LoadMpqPatch_COPY(TMPQFile * hf, TPatchHeader * pPatchHeader)
+{
+ int nError = ERROR_SUCCESS;
+
+ // Allocate space for patch header and compressed data
+ hf->pPatchHeader = (TPatchHeader *)STORM_ALLOC(BYTE, pPatchHeader->dwSizeOfPatchData);
+ if(hf->pPatchHeader == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+
+ // Load the patch data and decide if they are compressed or not
+ if(nError == ERROR_SUCCESS)
+ {
+ LPBYTE pbPatchFile = (LPBYTE)hf->pPatchHeader;
+
+ // Copy the patch header itself
+ memcpy(pbPatchFile, pPatchHeader, sizeof(TPatchHeader));
+ pbPatchFile += sizeof(TPatchHeader);
+
+ // Load the rest of the patch
+ if(!SFileReadFile((HANDLE)hf, pbPatchFile, pPatchHeader->dwSizeOfPatchData - sizeof(TPatchHeader)))
+ nError = GetLastError();
+ }
+
+ return nError;
+}
+
+static int LoadMpqPatch_BSD0(TMPQFile * hf, TPatchHeader * pPatchHeader)
+{
+ LPBYTE pbDecompressed = NULL;
+ LPBYTE pbCompressed = NULL;
+ DWORD cbDecompressed = 0;
+ DWORD cbCompressed = 0;
+ DWORD dwBytesRead = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Allocate space for compressed data
+ cbCompressed = pPatchHeader->dwXfrmBlockSize - SIZE_OF_XFRM_HEADER;
+ pbCompressed = STORM_ALLOC(BYTE, cbCompressed);
+ if(pbCompressed == NULL)
+ nError = ERROR_SUCCESS;
+
+ // Read the compressed patch data
+ if(nError == ERROR_SUCCESS)
+ {
+ // Load the rest of the header
+ SFileReadFile((HANDLE)hf, pbCompressed, cbCompressed, &dwBytesRead);
+ if(dwBytesRead != cbCompressed)
+ nError = ERROR_FILE_CORRUPT;
+ }
+
+ // Get the uncompressed size of the patch
+ if(nError == ERROR_SUCCESS)
+ {
+ cbDecompressed = pPatchHeader->dwSizeOfPatchData - sizeof(TPatchHeader);
+ hf->pPatchHeader = (TPatchHeader *)STORM_ALLOC(BYTE, pPatchHeader->dwSizeOfPatchData);
+ if(hf->pPatchHeader == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Now decompress the patch data
+ if(nError == ERROR_SUCCESS)
+ {
+ // Copy the patch header
+ memcpy(hf->pPatchHeader, pPatchHeader, sizeof(TPatchHeader));
+ pbDecompressed = (LPBYTE)hf->pPatchHeader + sizeof(TPatchHeader);
+
+ // Uncompress or copy the patch data
+ if(cbCompressed < cbDecompressed)
+ {
+ Decompress_RLE(pbDecompressed, cbDecompressed, pbCompressed, cbCompressed);
+ }
+ else
+ {
+ assert(cbCompressed == cbDecompressed);
+ memcpy(pbDecompressed, pbCompressed, cbCompressed);
+ }
+ }
+
+ // Free buffers and exit
+ if(pbCompressed != NULL)
+ STORM_FREE(pbCompressed);
+ return nError;
+}
+
+static int ApplyMpqPatch_COPY(
+ TMPQFile * hf,
+ TPatchHeader * pPatchHeader)
+{
+ LPBYTE pbNewFileData;
+ DWORD cbNewFileData;
+
+ // Allocate space for new file data
+ cbNewFileData = pPatchHeader->dwXfrmBlockSize - SIZE_OF_XFRM_HEADER;
+ pbNewFileData = STORM_ALLOC(BYTE, cbNewFileData);
+ if(pbNewFileData == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Copy the patch data as-is
+ memcpy(pbNewFileData, (LPBYTE)pPatchHeader + sizeof(TPatchHeader), cbNewFileData);
+
+ // Free the old file data
+ STORM_FREE(hf->pbFileData);
+
+ // Put the new file data there
+ hf->pbFileData = pbNewFileData;
+ hf->cbFileData = cbNewFileData;
+ return ERROR_SUCCESS;
+}
+
+static int ApplyMpqPatch_BSD0(
+ TMPQFile * hf,
+ TPatchHeader * pPatchHeader)
+{
+ PBLIZZARD_BSDIFF40_FILE pBsdiff;
+ LPDWORD pCtrlBlock;
+ LPBYTE pbPatchData = (LPBYTE)pPatchHeader + sizeof(TPatchHeader);
+ LPBYTE pDataBlock;
+ LPBYTE pExtraBlock;
+ LPBYTE pbNewData = NULL;
+ LPBYTE pbOldData = (LPBYTE)hf->pbFileData;
+ DWORD dwNewOffset = 0; // Current position to patch
+ DWORD dwOldOffset = 0; // Current source position
+ DWORD dwNewSize; // Patched file size
+ DWORD dwOldSize = hf->cbFileData; // File size before patch
+
+ // Get pointer to the patch header
+ // Format of BSDIFF header corresponds to original BSDIFF, which is:
+ // 0000 8 bytes signature "BSDIFF40"
+ // 0008 8 bytes size of the control block
+ // 0010 8 bytes size of the data block
+ // 0018 8 bytes new size of the patched file
+ pBsdiff = (PBLIZZARD_BSDIFF40_FILE)pbPatchData;
+ pbPatchData += sizeof(BLIZZARD_BSDIFF40_FILE);
+
+ // Get pointer to the 32-bit BSDIFF control block
+ // The control block follows immediately after the BSDIFF header
+ // and consists of three 32-bit integers
+ // 0000 4 bytes Length to copy from the BSDIFF data block the new file
+ // 0004 4 bytes Length to copy from the BSDIFF extra block
+ // 0008 4 bytes Size to increment source file offset
+ pCtrlBlock = (LPDWORD)pbPatchData;
+ pbPatchData += (size_t)BSWAP_INT64_UNSIGNED(pBsdiff->CtrlBlockSize);
+
+ // Get the pointer to the data block
+ pDataBlock = (LPBYTE)pbPatchData;
+ pbPatchData += (size_t)BSWAP_INT64_UNSIGNED(pBsdiff->DataBlockSize);
+
+ // Get the pointer to the extra block
+ pExtraBlock = (LPBYTE)pbPatchData;
+ dwNewSize = (DWORD)BSWAP_INT64_UNSIGNED(pBsdiff->NewFileSize);
+
+ // Allocate new buffer
+ pbNewData = STORM_ALLOC(BYTE, dwNewSize);
+ if(pbNewData == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Now patch the file
+ while(dwNewOffset < dwNewSize)
+ {
+ DWORD dwAddDataLength = BSWAP_INT32_UNSIGNED(pCtrlBlock[0]);
+ DWORD dwMovDataLength = BSWAP_INT32_UNSIGNED(pCtrlBlock[1]);
+ DWORD dwOldMoveLength = BSWAP_INT32_UNSIGNED(pCtrlBlock[2]);
+ DWORD i;
+
+ // Sanity check
+ if((dwNewOffset + dwAddDataLength) > dwNewSize)
+ {
+ STORM_FREE(pbNewData);
+ return ERROR_FILE_CORRUPT;
+ }
+
+ // Read the diff string to the target buffer
+ memcpy(pbNewData + dwNewOffset, pDataBlock, dwAddDataLength);
+ pDataBlock += dwAddDataLength;
+
+ // Now combine the patch data with the original file
+ for(i = 0; i < dwAddDataLength; i++)
+ {
+ if(dwOldOffset < dwOldSize)
+ pbNewData[dwNewOffset] = pbNewData[dwNewOffset] + pbOldData[dwOldOffset];
+
+ dwNewOffset++;
+ dwOldOffset++;
+ }
+
+ // Sanity check
+ if((dwNewOffset + dwMovDataLength) > dwNewSize)
+ {
+ STORM_FREE(pbNewData);
+ return ERROR_FILE_CORRUPT;
+ }
+
+ // Copy the data from the extra block in BSDIFF patch
+ memcpy(pbNewData + dwNewOffset, pExtraBlock, dwMovDataLength);
+ pExtraBlock += dwMovDataLength;
+ dwNewOffset += dwMovDataLength;
+
+ // Move the old offset
+ if(dwOldMoveLength & 0x80000000)
+ dwOldMoveLength = 0x80000000 - dwOldMoveLength;
+ dwOldOffset += dwOldMoveLength;
+ pCtrlBlock += 3;
+ }
+
+ // Free the old file data
+ STORM_FREE(hf->pbFileData);
+
+ // Put the new data to the fil structure
+ hf->pbFileData = pbNewData;
+ hf->cbFileData = dwNewSize;
+ return ERROR_SUCCESS;
+}
+
+
+static int LoadMpqPatch(TMPQFile * hf)
+{
+ TPatchHeader PatchHeader;
+ DWORD dwBytesRead;
+ int nError = ERROR_SUCCESS;
+
+ // Read the patch header
+ SFileReadFile((HANDLE)hf, &PatchHeader, sizeof(TPatchHeader), &dwBytesRead);
+ if(dwBytesRead != sizeof(TPatchHeader))
+ nError = ERROR_FILE_CORRUPT;
+
+ // Verify the signatures in the patch header
+ if(nError == ERROR_SUCCESS)
+ {
+ // BSWAP the entire header, if needed
+ BSWAP_ARRAY32_UNSIGNED(&PatchHeader, sizeof(DWORD) * 6);
+ PatchHeader.dwXFRM = BSWAP_INT32_UNSIGNED(PatchHeader.dwXFRM);
+ PatchHeader.dwXfrmBlockSize = BSWAP_INT32_UNSIGNED(PatchHeader.dwXfrmBlockSize);
+ PatchHeader.dwPatchType = BSWAP_INT32_UNSIGNED(PatchHeader.dwPatchType);
+
+ if(PatchHeader.dwSignature != 0x48435450 || PatchHeader.dwMD5 != 0x5f35444d || PatchHeader.dwXFRM != 0x4d524658)
+ nError = ERROR_FILE_CORRUPT;
+ }
+
+ // Read the patch, depending on patch type
+ if(nError == ERROR_SUCCESS)
+ {
+ switch(PatchHeader.dwPatchType)
+ {
+ case 0x59504f43: // 'COPY'
+ nError = LoadMpqPatch_COPY(hf, &PatchHeader);
+ break;
+
+ case 0x30445342: // 'BSD0'
+ nError = LoadMpqPatch_BSD0(hf, &PatchHeader);
+ break;
+
+ default:
+ nError = ERROR_FILE_CORRUPT;
+ break;
+ }
+ }
+
+ return nError;
+}
+
+static int ApplyMpqPatch(
+ TMPQFile * hf,
+ TPatchHeader * pPatchHeader)
+{
+ int nError = ERROR_SUCCESS;
+
+ // Verify the original file before patching
+ if(pPatchHeader->dwSizeBeforePatch != 0)
+ {
+ if(!VerifyDataBlockHash(hf->pbFileData, hf->cbFileData, pPatchHeader->md5_before_patch))
+ nError = ERROR_FILE_CORRUPT;
+ }
+
+ // Apply the patch
+ if(nError == ERROR_SUCCESS)
+ {
+ switch(pPatchHeader->dwPatchType)
+ {
+ case 0x59504f43: // 'COPY'
+ nError = ApplyMpqPatch_COPY(hf, pPatchHeader);
+ break;
+
+ case 0x30445342: // 'BSD0'
+ nError = ApplyMpqPatch_BSD0(hf, pPatchHeader);
+ break;
+
+ default:
+ nError = ERROR_FILE_CORRUPT;
+ break;
+ }
+ }
+
+ // Verify MD5 after patch
+ if(nError == ERROR_SUCCESS && pPatchHeader->dwSizeAfterPatch != 0)
+ {
+ // Verify the patched file
+ if(!VerifyDataBlockHash(hf->pbFileData, hf->cbFileData, pPatchHeader->md5_after_patch))
+ nError = ERROR_FILE_CORRUPT;
+ }
+
+ return nError;
+}
+
+//-----------------------------------------------------------------------------
+// Public functions (StormLib internals)
+
+bool IsIncrementalPatchFile(const void * pvData, DWORD cbData, LPDWORD pdwPatchedFileSize)
+{
+ TPatchHeader * pPatchHeader = (TPatchHeader *)pvData;
+ BLIZZARD_BSDIFF40_FILE DiffFile;
+ DWORD dwPatchType;
+
+ if(cbData >= sizeof(TPatchHeader) + sizeof(BLIZZARD_BSDIFF40_FILE))
+ {
+ dwPatchType = BSWAP_INT32_UNSIGNED(pPatchHeader->dwPatchType);
+ if(dwPatchType == 0x30445342)
+ {
+ // Give the caller the patch file size
+ if(pdwPatchedFileSize != NULL)
+ {
+ Decompress_RLE((LPBYTE)&DiffFile, sizeof(BLIZZARD_BSDIFF40_FILE), (LPBYTE)(pPatchHeader + 1), sizeof(BLIZZARD_BSDIFF40_FILE));
+ DiffFile.NewFileSize = BSWAP_INT64_UNSIGNED(DiffFile.NewFileSize);
+ *pdwPatchedFileSize = (DWORD)DiffFile.NewFileSize;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+int PatchFileData(TMPQFile * hf)
+{
+ TMPQFile * hfBase = hf;
+ int nError = ERROR_SUCCESS;
+
+ // Move to the first patch
+ hf = hf->hfPatchFile;
+
+ // Now go through all patches and patch the original data
+ while(hf != NULL)
+ {
+ // This must be true
+ assert(hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE);
+
+ // Make sure that the patch data is loaded
+ nError = LoadMpqPatch(hf);
+ if(nError != ERROR_SUCCESS)
+ break;
+
+ // Apply the patch
+ nError = ApplyMpqPatch(hfBase, hf->pPatchHeader);
+ if(nError != ERROR_SUCCESS)
+ break;
+
+ // Move to the next patch
+ hf = hf->hfPatchFile;
+ }
+
+ return nError;
+}
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+//
+// Patch prefix is the path subdirectory where the patched files are within MPQ.
+//
+// Example 1:
+// Main MPQ: locale-enGB.MPQ
+// Patch MPQ: wow-update-12694.MPQ
+// File in main MPQ: DBFilesClient\Achievement.dbc
+// File in patch MPQ: enGB\DBFilesClient\Achievement.dbc
+// Path prefix: enGB
+//
+// Example 2:
+// Main MPQ: expansion1.MPQ
+// Patch MPQ: wow-update-12694.MPQ
+// File in main MPQ: DBFilesClient\Achievement.dbc
+// File in patch MPQ: Base\DBFilesClient\Achievement.dbc
+// Path prefix: Base
+//
+
+bool WINAPI SFileOpenPatchArchive(
+ HANDLE hMpq,
+ const TCHAR * szPatchMpqName,
+ const char * szPatchPathPrefix,
+ DWORD dwFlags)
+{
+ TMPQArchive * haPatch;
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ HANDLE hPatchMpq = NULL;
+ char szPatchPrefixBuff[MPQ_PATCH_PREFIX_LEN];
+ int nError = ERROR_SUCCESS;
+
+ // Keep compiler happy
+ dwFlags = dwFlags;
+
+ // Verify input parameters
+ if(!IsValidMpqHandle(ha))
+ nError = ERROR_INVALID_HANDLE;
+ if(szPatchMpqName == NULL || *szPatchMpqName == 0)
+ nError = ERROR_INVALID_PARAMETER;
+
+ // If the user didn't give the patch prefix, get default one
+ if(szPatchPathPrefix != NULL)
+ {
+ // Save length of the patch prefix
+ if(strlen(szPatchPathPrefix) > MPQ_PATCH_PREFIX_LEN - 2)
+ nError = ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // We don't allow adding patches to archives that have been open for write
+ //
+ // Error scenario:
+ //
+ // 1) Open archive for writing
+ // 2) Modify or replace a file
+ // 3) Add patch archive to the opened MPQ
+ // 4) Read patched file
+ // 5) Now what ?
+ //
+
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!FileStream_IsReadOnly(ha->pStream))
+ nError = ERROR_ACCESS_DENIED;
+ }
+
+ // Open the archive like it is normal archive
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!SFileOpenArchive(szPatchMpqName, 0, MPQ_OPEN_READ_ONLY, &hPatchMpq))
+ return false;
+ haPatch = (TMPQArchive *)hPatchMpq;
+
+ // Older WoW patches (build 13914) used to have
+ // several language versions in one patch file
+ // Those patches needed to have a path prefix
+ // We can distinguish such patches by not having the (patch_metadata) file
+ if(szPatchPathPrefix == NULL)
+ {
+ if(!SFileHasFile(hPatchMpq, PATCH_METADATA_NAME))
+ {
+ GetDefaultPatchPrefix(FileStream_GetFileName(ha->pStream), szPatchPrefixBuff);
+ szPatchPathPrefix = szPatchPrefixBuff;
+ }
+ }
+
+ // Save the prefix for patch file names.
+ // Make sure that there is backslash after it
+ if(szPatchPathPrefix != NULL && *szPatchPathPrefix != 0)
+ {
+ strcpy(haPatch->szPatchPrefix, szPatchPathPrefix);
+ strcat(haPatch->szPatchPrefix, "\\");
+ haPatch->cchPatchPrefix = strlen(haPatch->szPatchPrefix);
+ }
+
+ // Now add the patch archive to the list of patches to the original MPQ
+ while(ha != NULL)
+ {
+ if(ha->haPatch == NULL)
+ {
+ haPatch->haBase = ha;
+ ha->haPatch = haPatch;
+ return true;
+ }
+
+ // Move to the next archive
+ ha = ha->haPatch;
+ }
+
+ // Should never happen
+ nError = ERROR_CAN_NOT_COMPLETE;
+ }
+
+ SetLastError(nError);
+ return false;
+}
+
+bool WINAPI SFileIsPatchedArchive(HANDLE hMpq)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+
+ // Verify input parameters
+ if(!IsValidMpqHandle(ha))
+ return false;
+
+ return (ha->haPatch != NULL);
+}
diff --git a/dep/StormLib/src/SFileReadFile.cpp b/dep/StormLib/src/SFileReadFile.cpp
new file mode 100644
index 00000000000..5570fd466c5
--- /dev/null
+++ b/dep/StormLib/src/SFileReadFile.cpp
@@ -0,0 +1,1183 @@
+/*****************************************************************************/
+/* SFileReadFile.cpp Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Description : */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* xx.xx.99 1.00 Lad The first version of SFileReadFile.cpp */
+/* 24.03.99 1.00 Lad Added the SFileGetFileInfo function */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+//-----------------------------------------------------------------------------
+// Local structures
+
+struct TFileHeader2Ext
+{
+ DWORD dwOffset00Data; // Required data at offset 00 (32-bits)
+ DWORD dwOffset00Mask; // Mask for data at offset 00 (32 bits). 0 = data are ignored
+ DWORD dwOffset04Data; // Required data at offset 04 (32-bits)
+ DWORD dwOffset04Mask; // Mask for data at offset 04 (32 bits). 0 = data are ignored
+ const char * szExt; // Supplied extension, if the condition is true
+};
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static void CopyFileName(char * szTarget, const TCHAR * szSource)
+{
+ while(*szSource != 0)
+ *szTarget++ = (char)*szSource++;
+ *szTarget = 0;
+}
+
+static DWORD GetMpqFileCount(TMPQArchive * ha)
+{
+ TFileEntry * pFileTableEnd;
+ TFileEntry * pFileEntry;
+ DWORD dwFileCount = 0;
+
+ // Go through all open MPQs, including patches
+ while(ha != NULL)
+ {
+ // Only count files that are not patch files
+ pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
+ for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
+ {
+ // If the file is patch file and this is not primary archive, skip it
+ // BUGBUG: This errorneously counts non-patch files that are in both
+ // base MPQ and in patches, and increases the number of files by cca 50%
+ if((pFileEntry->dwFlags & (MPQ_FILE_EXISTS | MPQ_FILE_PATCH_FILE)) == MPQ_FILE_EXISTS)
+ dwFileCount++;
+ }
+
+ // Move to the next patch archive
+ ha = ha->haPatch;
+ }
+
+ return dwFileCount;
+}
+
+static bool GetFilePatchChain(TMPQFile * hf, void * pvFileInfo, DWORD cbFileInfo, LPDWORD pcbLengthNeeded)
+{
+ TMPQFile * hfTemp;
+ TCHAR * szPatchChain = (TCHAR *)pvFileInfo;
+ TCHAR * szFileName;
+ size_t cchCharsNeeded = 1;
+ size_t nLength;
+ DWORD cbLengthNeeded;
+
+ // Check if the "hf" is a MPQ file
+ if(hf->pStream != NULL)
+ {
+ // Calculate the length needed
+ szFileName = FileStream_GetFileName(hf->pStream);
+ cchCharsNeeded += _tcslen(szFileName) + 1;
+ cbLengthNeeded = (DWORD)(cchCharsNeeded * sizeof(TCHAR));
+
+ // If we have enough space, copy the file name
+ if(cbFileInfo >= cbLengthNeeded)
+ {
+ nLength = _tcslen(szFileName) + 1;
+ memcpy(szPatchChain, szFileName, nLength * sizeof(TCHAR));
+ szPatchChain += nLength;
+
+ // Terminate the multi-string
+ *szPatchChain = 0;
+ }
+ }
+ else
+ {
+ // Calculate number of characters needed
+ for(hfTemp = hf; hfTemp != NULL; hfTemp = hfTemp->hfPatchFile)
+ cchCharsNeeded += _tcslen(FileStream_GetFileName(hfTemp->ha->pStream)) + 1;
+ cbLengthNeeded = (DWORD)(cchCharsNeeded * sizeof(TCHAR));
+
+ // If we have enough space, the copy the patch chain
+ if(cbFileInfo >= cbLengthNeeded)
+ {
+ for(hfTemp = hf; hfTemp != NULL; hfTemp = hfTemp->hfPatchFile)
+ {
+ szFileName = FileStream_GetFileName(hfTemp->ha->pStream);
+ nLength = _tcslen(szFileName) + 1;
+ memcpy(szPatchChain, szFileName, nLength * sizeof(TCHAR));
+ szPatchChain += nLength;
+ }
+
+ // Terminate the multi-string
+ *szPatchChain = 0;
+ }
+ }
+
+ // Give result length, terminate multi-string and return
+ *pcbLengthNeeded = cbLengthNeeded;
+ return true;
+}
+
+// hf - MPQ File handle.
+// pbBuffer - Pointer to target buffer to store sectors.
+// dwByteOffset - Position of sector in the file (relative to file begin)
+// dwBytesToRead - Number of bytes to read. Must be multiplier of sector size.
+// pdwBytesRead - Stored number of bytes loaded
+static int ReadMpqSectors(TMPQFile * hf, LPBYTE pbBuffer, DWORD dwByteOffset, DWORD dwBytesToRead, LPDWORD pdwBytesRead)
+{
+ ULONGLONG RawFilePos;
+ TMPQArchive * ha = hf->ha;
+ TFileEntry * pFileEntry = hf->pFileEntry;
+ LPBYTE pbRawSector = NULL;
+ LPBYTE pbOutSector = pbBuffer;
+ LPBYTE pbInSector = pbBuffer;
+ DWORD dwRawBytesToRead;
+ DWORD dwRawSectorOffset = dwByteOffset;
+ DWORD dwSectorsToRead = dwBytesToRead / ha->dwSectorSize;
+ DWORD dwSectorIndex = dwByteOffset / ha->dwSectorSize;
+ DWORD dwSectorsDone = 0;
+ DWORD dwBytesRead = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Note that dwByteOffset must be aligned to size of one sector
+ // Note that dwBytesToRead must be a multiplier of one sector size
+ // This is local function, so we won't check if that's true.
+ // Note that files stored in single units are processed by a separate function
+
+ // If there is not enough bytes remaining, cut dwBytesToRead
+ if((dwByteOffset + dwBytesToRead) > hf->dwDataSize)
+ dwBytesToRead = hf->dwDataSize - dwByteOffset;
+ dwRawBytesToRead = dwBytesToRead;
+
+ // Perform all necessary work to do with compressed files
+ if(pFileEntry->dwFlags & MPQ_FILE_COMPRESSED)
+ {
+ // If the sector positions are not loaded yet, do it
+ if(hf->SectorOffsets == NULL)
+ {
+ nError = AllocateSectorOffsets(hf, true);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+ }
+
+ // If the sector checksums are not loaded yet, load them now.
+ if(hf->SectorChksums == NULL && (pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC) && hf->bLoadedSectorCRCs == false)
+ {
+ //
+ // Sector CRCs is plain crap feature. It is almost never present,
+ // often it's empty, or the end offset of sector CRCs is zero.
+ // We only try to load sector CRCs once, and regardless if it fails
+ // or not, we won't try that again for the given file.
+ //
+
+ AllocateSectorChecksums(hf, true);
+ hf->bLoadedSectorCRCs = true;
+ }
+
+ // TODO: If the raw data MD5s are not loaded yet, load them now
+ // Only do it if the MPQ is of format 4.0
+// if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_4 && ha->pHeader->dwRawChunkSize != 0)
+// {
+// nError = AllocateRawMD5s(hf, true);
+// if(nError != ERROR_SUCCESS)
+// return nError;
+// }
+
+ // If the file is compressed, also allocate secondary buffer
+ pbInSector = pbRawSector = STORM_ALLOC(BYTE, dwBytesToRead);
+ if(pbRawSector == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Assign the temporary buffer as target for read operation
+ dwRawSectorOffset = hf->SectorOffsets[dwSectorIndex];
+ dwRawBytesToRead = hf->SectorOffsets[dwSectorIndex + dwSectorsToRead] - dwRawSectorOffset;
+ }
+
+ // Calculate raw file offset where the sector(s) are stored.
+ CalculateRawSectorOffset(RawFilePos, hf, dwRawSectorOffset);
+
+ // Set file pointer and read all required sectors
+ if(!FileStream_Read(ha->pStream, &RawFilePos, pbInSector, dwRawBytesToRead))
+ return GetLastError();
+ dwBytesRead = 0;
+
+ // Now we have to decrypt and decompress all file sectors that have been loaded
+ for(DWORD i = 0; i < dwSectorsToRead; i++)
+ {
+ DWORD dwRawBytesInThisSector = ha->dwSectorSize;
+ DWORD dwBytesInThisSector = ha->dwSectorSize;
+ DWORD dwIndex = dwSectorIndex + i;
+
+ // If there is not enough bytes in the last sector,
+ // cut the number of bytes in this sector
+ if(dwRawBytesInThisSector > dwBytesToRead)
+ dwRawBytesInThisSector = dwBytesToRead;
+ if(dwBytesInThisSector > dwBytesToRead)
+ dwBytesInThisSector = dwBytesToRead;
+
+ // If the file is compressed, we have to adjust the raw sector size
+ if(pFileEntry->dwFlags & MPQ_FILE_COMPRESSED)
+ dwRawBytesInThisSector = hf->SectorOffsets[dwIndex + 1] - hf->SectorOffsets[dwIndex];
+
+ // If the file is encrypted, we have to decrypt the sector
+ if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
+ {
+ BSWAP_ARRAY32_UNSIGNED(pbInSector, dwRawBytesInThisSector);
+
+ // If we don't know the key, try to detect it by file content
+ if(hf->dwFileKey == 0)
+ {
+ hf->dwFileKey = DetectFileKeyByContent(pbInSector, dwBytesInThisSector);
+ if(hf->dwFileKey == 0)
+ {
+ nError = ERROR_UNKNOWN_FILE_KEY;
+ break;
+ }
+ }
+
+ DecryptMpqBlock(pbInSector, dwRawBytesInThisSector, hf->dwFileKey + dwIndex);
+ BSWAP_ARRAY32_UNSIGNED(pbInSector, dwRawBytesInThisSector);
+ }
+
+ // If the file has sector CRC check turned on, perform it
+ if(hf->bCheckSectorCRCs && hf->SectorChksums != NULL)
+ {
+ DWORD dwAdlerExpected = hf->SectorChksums[dwIndex];
+ DWORD dwAdlerValue = 0;
+
+ // We can only check sector CRC when it's not zero
+ // Neither can we check it if it's 0xFFFFFFFF.
+ if(dwAdlerExpected != 0 && dwAdlerExpected != 0xFFFFFFFF)
+ {
+ dwAdlerValue = adler32(0, pbInSector, dwRawBytesInThisSector);
+ if(dwAdlerValue != dwAdlerExpected)
+ {
+ nError = ERROR_CHECKSUM_ERROR;
+ break;
+ }
+ }
+ }
+
+ // If the sector is really compressed, decompress it.
+ // WARNING : Some sectors may not be compressed, it can be determined only
+ // by comparing uncompressed and compressed size !!!
+ if(dwRawBytesInThisSector < dwBytesInThisSector)
+ {
+ int cbOutSector = dwBytesInThisSector;
+ int cbInSector = dwRawBytesInThisSector;
+ int nResult = 0;
+
+ // Is the file compressed by Blizzard's multiple compression ?
+ if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS)
+ {
+ if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2)
+ nResult = SCompDecompress2((char *)pbOutSector, &cbOutSector, (char *)pbInSector, cbInSector);
+ else
+ nResult = SCompDecompress((char *)pbOutSector, &cbOutSector, (char *)pbInSector, cbInSector);
+ }
+
+ // Is the file compressed by PKWARE Data Compression Library ?
+ else if(pFileEntry->dwFlags & MPQ_FILE_IMPLODE)
+ {
+ nResult = SCompExplode((char *)pbOutSector, &cbOutSector, (char *)pbInSector, cbInSector);
+ }
+
+ // Did the decompression fail ?
+ if(nResult == 0)
+ {
+ nError = ERROR_FILE_CORRUPT;
+ break;
+ }
+ }
+ else
+ {
+ if(pbOutSector != pbInSector)
+ memcpy(pbOutSector, pbInSector, dwBytesInThisSector);
+ }
+
+ // Move pointers
+ dwBytesToRead -= dwBytesInThisSector;
+ dwByteOffset += dwBytesInThisSector;
+ dwBytesRead += dwBytesInThisSector;
+ pbOutSector += dwBytesInThisSector;
+ pbInSector += dwRawBytesInThisSector;
+ dwSectorsDone++;
+ }
+
+ // Free all used buffers
+ if(pbRawSector != NULL)
+ STORM_FREE(pbRawSector);
+
+ // Give the caller thenumber of bytes read
+ *pdwBytesRead = dwBytesRead;
+ return nError;
+}
+
+static int ReadMpqFileSingleUnit(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwToRead, LPDWORD pdwBytesRead)
+{
+ ULONGLONG RawFilePos = hf->RawFilePos;
+ TMPQArchive * ha = hf->ha;
+ TFileEntry * pFileEntry = hf->pFileEntry;
+ LPBYTE pbCompressed = NULL;
+ LPBYTE pbRawData = NULL;
+ int nError = ERROR_SUCCESS;
+
+ // If the file buffer is not allocated yet, do it.
+ if(hf->pbFileSector == NULL)
+ {
+ nError = AllocateSectorBuffer(hf);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+ pbRawData = hf->pbFileSector;
+ }
+
+ // If the file is a patch file, adjust raw data offset
+ if(hf->pPatchInfo != NULL)
+ RawFilePos += hf->pPatchInfo->dwLength;
+
+ // If the file sector is not loaded yet, do it
+ if(hf->dwSectorOffs != 0)
+ {
+ // Is the file compressed?
+ if(pFileEntry->dwFlags & MPQ_FILE_COMPRESSED)
+ {
+ // Allocate space for compressed data
+ pbCompressed = STORM_ALLOC(BYTE, pFileEntry->dwCmpSize);
+ if(pbCompressed == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ pbRawData = pbCompressed;
+ }
+
+ // Load the raw (compressed, encrypted) data
+ if(!FileStream_Read(ha->pStream, &RawFilePos, pbRawData, pFileEntry->dwCmpSize))
+ {
+ STORM_FREE(pbCompressed);
+ return GetLastError();
+ }
+
+ // If the file is encrypted, we have to decrypt the data first
+ if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
+ {
+ BSWAP_ARRAY32_UNSIGNED(pbRawData, pFileEntry->dwCmpSize);
+ DecryptMpqBlock(pbRawData, pFileEntry->dwCmpSize, hf->dwFileKey);
+ BSWAP_ARRAY32_UNSIGNED(pbRawData, pFileEntry->dwCmpSize);
+ }
+
+ // If the file is compressed, we have to decompress it now
+ if(pFileEntry->dwFlags & MPQ_FILE_COMPRESSED)
+ {
+ int cbOutBuffer = (int)hf->dwDataSize;
+ int cbInBuffer = (int)pFileEntry->dwCmpSize;
+ int nResult = 0;
+
+ //
+ // If the file is an incremental patch, the size of compressed data
+ // is determined as pFileEntry->dwCmpSize - sizeof(TPatchInfo)
+ //
+ // In "wow-update-12694.MPQ" from Wow-Cataclysm BETA:
+ //
+ // File CmprSize DcmpSize DataSize Compressed?
+ // -------------------------------------- ---------- -------- -------- ---------------
+ // esES\DBFilesClient\LightSkyBox.dbc 0xBE->0xA2 0xBC 0xBC Yes
+ // deDE\DBFilesClient\MountCapability.dbc 0x93->0x77 0x77 0x77 No
+ //
+
+ if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE)
+ cbInBuffer = cbInBuffer - sizeof(TPatchInfo);
+
+ // Is the file compressed by Blizzard's multiple compression ?
+ if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS)
+ {
+ if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2)
+ nResult = SCompDecompress2((char *)hf->pbFileSector, &cbOutBuffer, (char *)pbRawData, cbInBuffer);
+ else
+ nResult = SCompDecompress((char *)hf->pbFileSector, &cbOutBuffer, (char *)pbRawData, cbInBuffer);
+ }
+
+ // Is the file compressed by PKWARE Data Compression Library ?
+ // Note: Single unit files compressed with IMPLODE are not supported by Blizzard
+ else if(pFileEntry->dwFlags & MPQ_FILE_IMPLODE)
+ nResult = SCompExplode((char *)hf->pbFileSector, &cbOutBuffer, (char *)pbRawData, cbInBuffer);
+
+ nError = (nResult != 0) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT;
+ }
+ else
+ {
+ if(pbRawData != hf->pbFileSector)
+ memcpy(hf->pbFileSector, pbRawData, hf->dwDataSize);
+ }
+
+ // Free the decompression buffer.
+ if(pbCompressed != NULL)
+ STORM_FREE(pbCompressed);
+
+ // The file sector is now properly loaded
+ hf->dwSectorOffs = 0;
+ }
+
+ // At this moment, we have the file loaded into the file buffer.
+ // Copy as much as the caller wants
+ if(nError == ERROR_SUCCESS && hf->dwSectorOffs == 0)
+ {
+ // File position is greater or equal to file size ?
+ if(dwFilePos >= hf->dwDataSize)
+ {
+ *pdwBytesRead = 0;
+ return ERROR_SUCCESS;
+ }
+
+ // If not enough bytes remaining in the file, cut them
+ if((hf->dwDataSize - dwFilePos) < dwToRead)
+ dwToRead = (hf->dwDataSize - dwFilePos);
+
+ // Copy the bytes
+ memcpy(pvBuffer, hf->pbFileSector + dwFilePos, dwToRead);
+
+ // Give the number of bytes read
+ *pdwBytesRead = dwToRead;
+ return ERROR_SUCCESS;
+ }
+
+ // An error, sorry
+ return ERROR_CAN_NOT_COMPLETE;
+}
+
+static int ReadMpqFile(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwBytesToRead, LPDWORD pdwBytesRead)
+{
+ TMPQArchive * ha = hf->ha;
+ LPBYTE pbBuffer = (BYTE *)pvBuffer;
+ DWORD dwTotalBytesRead = 0; // Total bytes read in all three parts
+ DWORD dwSectorSizeMask = ha->dwSectorSize - 1; // Mask for block size, usually 0x0FFF
+ DWORD dwFileSectorPos; // File offset of the loaded sector
+ DWORD dwBytesRead; // Number of bytes read (temporary variable)
+ int nError;
+
+ // If the file position is at or beyond end of file, do nothing
+ if(dwFilePos >= hf->dwDataSize)
+ {
+ *pdwBytesRead = 0;
+ return ERROR_SUCCESS;
+ }
+
+ // If not enough bytes in the file remaining, cut them
+ if(dwBytesToRead > (hf->dwDataSize - dwFilePos))
+ dwBytesToRead = (hf->dwDataSize - dwFilePos);
+
+ // Compute sector position in the file
+ dwFileSectorPos = dwFilePos & ~dwSectorSizeMask; // Position in the block
+
+ // If the file sector buffer is not allocated yet, do it now
+ if(hf->pbFileSector == NULL)
+ {
+ nError = AllocateSectorBuffer(hf);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+ }
+
+ // Load the first (incomplete) file sector
+ if(dwFilePos & dwSectorSizeMask)
+ {
+ DWORD dwBytesInSector = ha->dwSectorSize;
+ DWORD dwBufferOffs = dwFilePos & dwSectorSizeMask;
+ DWORD dwToCopy;
+
+ // Is the file sector already loaded ?
+ if(hf->dwSectorOffs != dwFileSectorPos)
+ {
+ // Load one MPQ sector into archive buffer
+ nError = ReadMpqSectors(hf, hf->pbFileSector, dwFileSectorPos, ha->dwSectorSize, &dwBytesInSector);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ // Remember that the data loaded to the sector have new file offset
+ hf->dwSectorOffs = dwFileSectorPos;
+ }
+ else
+ {
+ if((dwFileSectorPos + dwBytesInSector) > hf->dwDataSize)
+ dwBytesInSector = hf->dwDataSize - dwFileSectorPos;
+ }
+
+ // Copy the data from the offset in the loaded sector to the end of the sector
+ dwToCopy = dwBytesInSector - dwBufferOffs;
+ if(dwToCopy > dwBytesToRead)
+ dwToCopy = dwBytesToRead;
+
+ // Copy data from sector buffer into target buffer
+ memcpy(pbBuffer, hf->pbFileSector + dwBufferOffs, dwToCopy);
+
+ // Update pointers and byte counts
+ dwTotalBytesRead += dwToCopy;
+ dwFileSectorPos += dwBytesInSector;
+ pbBuffer += dwToCopy;
+ dwBytesToRead -= dwToCopy;
+ }
+
+ // Load the whole ("middle") sectors only if there is at least one full sector to be read
+ if(dwBytesToRead >= ha->dwSectorSize)
+ {
+ DWORD dwBlockBytes = dwBytesToRead & ~dwSectorSizeMask;
+
+ // Load all sectors to the output buffer
+ nError = ReadMpqSectors(hf, pbBuffer, dwFileSectorPos, dwBlockBytes, &dwBytesRead);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ // Update pointers
+ dwTotalBytesRead += dwBytesRead;
+ dwFileSectorPos += dwBytesRead;
+ pbBuffer += dwBytesRead;
+ dwBytesToRead -= dwBytesRead;
+ }
+
+ // Read the terminating sector
+ if(dwBytesToRead > 0)
+ {
+ DWORD dwToCopy = ha->dwSectorSize;
+
+ // Is the file sector already loaded ?
+ if(hf->dwSectorOffs != dwFileSectorPos)
+ {
+ // Load one MPQ sector into archive buffer
+ nError = ReadMpqSectors(hf, hf->pbFileSector, dwFileSectorPos, ha->dwSectorSize, &dwBytesRead);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ // Remember that the data loaded to the sector have new file offset
+ hf->dwSectorOffs = dwFileSectorPos;
+ }
+
+ // Check number of bytes read
+ if(dwToCopy > dwBytesToRead)
+ dwToCopy = dwBytesToRead;
+
+ // Copy the data from the cached last sector to the caller's buffer
+ memcpy(pbBuffer, hf->pbFileSector, dwToCopy);
+
+ // Update pointers
+ dwTotalBytesRead += dwToCopy;
+ }
+
+ // Store total number of bytes read to the caller
+ *pdwBytesRead = dwTotalBytesRead;
+ return ERROR_SUCCESS;
+}
+
+static int ReadMpqFilePatchFile(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwToRead, LPDWORD pdwBytesRead)
+{
+ DWORD dwBytesToRead = dwToRead;
+ DWORD dwBytesRead = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Make sure that the patch file is loaded completely
+ if(hf->pbFileData == NULL)
+ {
+ // Load the original file and store its content to "pbOldData"
+ hf->pbFileData = STORM_ALLOC(BYTE, hf->pFileEntry->dwFileSize);
+ hf->cbFileData = hf->pFileEntry->dwFileSize;
+ if(hf->pbFileData == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Read the file data
+ if(hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT)
+ nError = ReadMpqFileSingleUnit(hf, hf->pbFileData, 0, hf->cbFileData, &dwBytesRead);
+ else
+ nError = ReadMpqFile(hf, hf->pbFileData, 0, hf->cbFileData, &dwBytesRead);
+
+ // Fix error code
+ if(nError == ERROR_SUCCESS && dwBytesRead != hf->cbFileData)
+ nError = ERROR_FILE_CORRUPT;
+
+ // Patch the file data
+ if(nError == ERROR_SUCCESS)
+ nError = PatchFileData(hf);
+
+ // Reset number of bytes read to zero
+ dwBytesRead = 0;
+ }
+
+ // If there is something to read, do it
+ if(nError == ERROR_SUCCESS)
+ {
+ if(dwFilePos < hf->cbFileData)
+ {
+ // Make sure we don't copy more than file size
+ if((dwFilePos + dwToRead) > hf->cbFileData)
+ dwToRead = hf->cbFileData - dwFilePos;
+
+ // Copy the appropriate amount of the file data to the caller's buffer
+ memcpy(pvBuffer, hf->pbFileData + dwFilePos, dwToRead);
+ dwBytesRead = dwToRead;
+ }
+
+ // Set the proper error code
+ nError = (dwBytesRead == dwBytesToRead) ? ERROR_SUCCESS : ERROR_HANDLE_EOF;
+ }
+
+ // Give the result to the caller
+ if(pdwBytesRead != NULL)
+ *pdwBytesRead = dwBytesRead;
+ return nError;
+}
+
+//-----------------------------------------------------------------------------
+// SFileReadFile
+
+bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD pdwRead, LPOVERLAPPED lpOverlapped)
+{
+ TMPQFile * hf = (TMPQFile *)hFile;
+ DWORD dwBytesRead = 0; // Number of bytes read
+ int nError = ERROR_SUCCESS;
+
+ // Keep compilers happy
+ lpOverlapped = lpOverlapped;
+
+ // Check valid parameters
+ if(!IsValidFileHandle(hf))
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return false;
+ }
+
+ if(pvBuffer == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ // If the file is local file, read the data directly from the stream
+ if(hf->pStream != NULL)
+ {
+ ULONGLONG FilePosition1;
+ ULONGLONG FilePosition2;
+
+ // Because stream I/O functions are designed to read
+ // "all or nothing", we compare file position before and after,
+ // and if they differ, we assume that number of bytes read
+ // is the difference between them
+
+ FileStream_GetPos(hf->pStream, FilePosition1);
+ if(!FileStream_Read(hf->pStream, NULL, pvBuffer, dwToRead))
+ {
+ // If not all bytes have been read, then return the number
+ // of bytes read
+ if((nError = GetLastError()) == ERROR_HANDLE_EOF)
+ {
+ FileStream_GetPos(hf->pStream, FilePosition2);
+ dwBytesRead = (DWORD)(FilePosition2 - FilePosition1);
+ }
+ else
+ {
+ nError = GetLastError();
+ }
+ }
+ else
+ {
+ dwBytesRead = dwToRead;
+ }
+ }
+ else
+ {
+ // If the file is a patch file, we have to read it special way
+ if(hf->hfPatchFile != NULL && (hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0)
+ {
+ nError = ReadMpqFilePatchFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead);
+ }
+
+ // If the file is single unit file, redirect it to read file
+ else if(hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT)
+ {
+ nError = ReadMpqFileSingleUnit(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead);
+ }
+
+ // Otherwise read it as sector based MPQ file
+ else
+ {
+ nError = ReadMpqFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead);
+ }
+
+ // Increment the file position
+ hf->dwFilePos += dwBytesRead;
+ }
+
+ // Give the caller the number of bytes read
+ if(pdwRead != NULL)
+ *pdwRead = dwBytesRead;
+
+ // If the read operation succeeded, but not full number of bytes was read,
+ // set the last error to ERROR_HANDLE_EOF
+ if(nError == ERROR_SUCCESS && (dwBytesRead < dwToRead))
+ nError = ERROR_HANDLE_EOF;
+
+ // If something failed, set the last error value
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return (nError == ERROR_SUCCESS);
+}
+
+//-----------------------------------------------------------------------------
+// SFileGetFileSize
+
+DWORD WINAPI SFileGetFileSize(HANDLE hFile, LPDWORD pdwFileSizeHigh)
+{
+ ULONGLONG FileSize;
+ TMPQFile * hf = (TMPQFile *)hFile;
+
+ // Validate the file handle before we go on
+ if(IsValidFileHandle(hf))
+ {
+ // Make sure that the variable is initialized
+ FileSize = 0;
+
+ // If the file is patched file, we have to get the size of the last version
+ if(hf->hfPatchFile != NULL)
+ {
+ // Walk through the entire patch chain, take the last version
+ while(hf != NULL)
+ {
+ // Get the size of the currently pointed version
+ FileSize = hf->pFileEntry->dwFileSize;
+
+ // Move to the next patch file in the hierarchy
+ hf = hf->hfPatchFile;
+ }
+ }
+ else
+ {
+ // Is it a local file ?
+ if(hf->pStream != NULL)
+ {
+ FileStream_GetSize(hf->pStream, FileSize);
+ }
+ else
+ {
+ FileSize = hf->dwDataSize;
+ }
+ }
+
+ // If opened from archive, return file size
+ if(pdwFileSizeHigh != NULL)
+ *pdwFileSizeHigh = (DWORD)(FileSize >> 32);
+ return (DWORD)FileSize;
+ }
+
+ SetLastError(ERROR_INVALID_HANDLE);
+ return SFILE_INVALID_SIZE;
+}
+
+DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHigh, DWORD dwMoveMethod)
+{
+ TMPQFile * hf = (TMPQFile *)hFile;
+ ULONGLONG FilePosition;
+ ULONGLONG MoveOffset;
+ DWORD dwFilePosHi;
+
+ // If the hFile is not a valid file handle, return an error.
+ if(!IsValidFileHandle(hf))
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return SFILE_INVALID_POS;
+ }
+
+ // Get the relative point where to move from
+ switch(dwMoveMethod)
+ {
+ case FILE_BEGIN:
+ FilePosition = 0;
+ break;
+
+ case FILE_CURRENT:
+ if(hf->pStream != NULL)
+ {
+ FileStream_GetPos(hf->pStream, FilePosition);
+ }
+ else
+ {
+ FilePosition = hf->dwFilePos;
+ }
+ break;
+
+ case FILE_END:
+ if(hf->pStream != NULL)
+ {
+ FileStream_GetSize(hf->pStream, FilePosition);
+ }
+ else
+ {
+ FilePosition = SFileGetFileSize(hFile, NULL);
+ }
+ break;
+
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SFILE_INVALID_POS;
+ }
+
+ // Now get the move offset. Note that both values form
+ // a signed 64-bit value (a file pointer can be moved backwards)
+ if(plFilePosHigh != NULL)
+ dwFilePosHi = *plFilePosHigh;
+ else
+ dwFilePosHi = (lFilePos & 0x80000000) ? 0xFFFFFFFF : 0;
+ MoveOffset = MAKE_OFFSET64(dwFilePosHi, lFilePos);
+
+ // Now calculate the new file pointer
+ // Do not allow the file pointer to go before the begin of the file
+ FilePosition += MoveOffset;
+ if(FilePosition < 0)
+ FilePosition = 0;
+
+ // Now apply the file pointer to the file
+ if(hf->pStream != NULL)
+ {
+ // Apply the new file position
+ if(!FileStream_Read(hf->pStream, &FilePosition, NULL, 0))
+ return SFILE_INVALID_POS;
+
+ // Return the new file position
+ if(plFilePosHigh != NULL)
+ *plFilePosHigh = (LONG)(FilePosition >> 32);
+ return (DWORD)FilePosition;
+ }
+ else
+ {
+ // Files in MPQ can't be bigger than 4 GB.
+ // We don't allow to go past 4 GB
+ if(FilePosition >> 32)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SFILE_INVALID_POS;
+ }
+
+ // Change the file position
+ hf->dwFilePos = (DWORD)FilePosition;
+
+ // Return the new file position
+ if(plFilePosHigh != NULL)
+ *plFilePosHigh = 0;
+ return (DWORD)FilePosition;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Tries to retrieve the file name
+
+static TFileHeader2Ext data2ext[] =
+{
+ {0x00005A4D, 0x0000FFFF, 0x00000000, 0x00000000, "exe"}, // EXE files
+ {0x00000006, 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, "dc6"}, // EXE files
+ {0x1A51504D, 0xFFFFFFFF, 0x00000000, 0x00000000, "mpq"}, // MPQ archive header ID ('MPQ\x1A')
+ {0x46464952, 0xFFFFFFFF, 0x00000000, 0x00000000, "wav"}, // WAVE header 'RIFF'
+ {0x324B4D53, 0xFFFFFFFF, 0x00000000, 0x00000000, "smk"}, // Old "Smacker Video" files 'SMK2'
+ {0x694B4942, 0xFFFFFFFF, 0x00000000, 0x00000000, "bik"}, // Bink video files (new)
+ {0x0801050A, 0xFFFFFFFF, 0x00000000, 0x00000000, "pcx"}, // PCX images used in Diablo I
+ {0x544E4F46, 0xFFFFFFFF, 0x00000000, 0x00000000, "fnt"}, // Font files used in Diablo II
+ {0x6D74683C, 0xFFFFFFFF, 0x00000000, 0x00000000, "html"}, // HTML '<htm'
+ {0x4D54483C, 0xFFFFFFFF, 0x00000000, 0x00000000, "html"}, // HTML '<HTM
+ {0x216F6F57, 0xFFFFFFFF, 0x00000000, 0x00000000, "tbl"}, // Table files
+ {0x31504C42, 0xFFFFFFFF, 0x00000000, 0x00000000, "blp"}, // BLP textures
+ {0x32504C42, 0xFFFFFFFF, 0x00000000, 0x00000000, "blp"}, // BLP textures (v2)
+ {0x584C444D, 0xFFFFFFFF, 0x00000000, 0x00000000, "mdx"}, // MDX files
+ {0x45505954, 0xFFFFFFFF, 0x00000000, 0x00000000, "pud"}, // Warcraft II maps
+ {0x38464947, 0xFFFFFFFF, 0x00000000, 0x00000000, "gif"}, // GIF images 'GIF8'
+ {0x3032444D, 0xFFFFFFFF, 0x00000000, 0x00000000, "m2"}, // WoW ??? .m2
+ {0x43424457, 0xFFFFFFFF, 0x00000000, 0x00000000, "dbc"}, // ??? .dbc
+ {0x47585053, 0xFFFFFFFF, 0x00000000, 0x00000000, "bls"}, // WoW pixel shaders
+ {0xE0FFD8FF, 0xFFFFFFFF, 0x00000000, 0x00000000, "jpg"}, // JPEG image
+ {0x00000000, 0x00000000, 0x00000000, 0x00000000, "xxx"}, // Default extension
+ {0, 0, 0, 0, NULL} // Terminator
+};
+
+bool WINAPI SFileGetFileName(HANDLE hFile, char * szFileName)
+{
+ TFileEntry * pFileEntry;
+ TMPQFile * hf = (TMPQFile *)hFile; // MPQ File handle
+ char szPseudoName[20];
+ DWORD FirstBytes[2]; // The first 4 bytes of the file
+ DWORD dwFilePos; // Saved file position
+ int nError = ERROR_SUCCESS;
+ int i;
+
+ // Pre-zero the output buffer
+ if(szFileName != NULL)
+ *szFileName = 0;
+
+ // Check valid parameters
+ if(!IsValidFileHandle(hf))
+ nError = ERROR_INVALID_HANDLE;
+ pFileEntry = hf->pFileEntry;
+
+ // Only do something if the file name is not filled
+ if(nError == ERROR_SUCCESS && pFileEntry != NULL && pFileEntry->szFileName == NULL)
+ {
+ // Read the first 2 DWORDs bytes from the file
+ FirstBytes[0] = FirstBytes[1] = 0;
+ dwFilePos = SFileSetFilePointer(hf, 0, NULL, FILE_CURRENT);
+ SFileReadFile(hFile, FirstBytes, sizeof(FirstBytes), NULL);
+ BSWAP_ARRAY32_UNSIGNED(FirstBytes, sizeof(FirstBytes));
+ SFileSetFilePointer(hf, dwFilePos, NULL, FILE_BEGIN);
+
+ // Try to guess file extension from those 2 DWORDs
+ for(i = 0; data2ext[i].szExt != NULL; i++)
+ {
+ if((FirstBytes[0] & data2ext[i].dwOffset00Mask) == data2ext[i].dwOffset00Data &&
+ (FirstBytes[1] & data2ext[i].dwOffset04Mask) == data2ext[i].dwOffset04Data)
+ {
+ sprintf(szPseudoName, "File%08u.%s", (unsigned int)(pFileEntry - hf->ha->pFileTable), data2ext[i].szExt);
+ break;
+ }
+ }
+
+ // Put the file name to the file table
+ AllocateFileName(pFileEntry, szPseudoName);
+ }
+
+ // Now put the file name to the file structure
+ if(nError == ERROR_SUCCESS && szFileName != NULL)
+ {
+ if(pFileEntry != NULL && pFileEntry->szFileName != NULL)
+ strcpy(szFileName, pFileEntry->szFileName);
+ else if(hf->pStream != NULL)
+ CopyFileName(szFileName, FileStream_GetFileName(hf->pStream));
+ }
+ return (nError == ERROR_SUCCESS);
+}
+
+//-----------------------------------------------------------------------------
+// Retrieves an information about an archive or about a file within the archive
+//
+// hMpqOrFile - Handle to an MPQ archive or to a file
+// dwInfoType - Information to obtain
+
+#define VERIFY_MPQ_HANDLE(h) \
+ if(!IsValidMpqHandle(h)) \
+ { \
+ nError = ERROR_INVALID_HANDLE; \
+ break; \
+ }
+
+#define VERIFY_FILE_HANDLE(h) \
+ if(!IsValidFileHandle(h)) \
+ { \
+ nError = ERROR_INVALID_HANDLE; \
+ break; \
+ }
+
+bool WINAPI SFileGetFileInfo(
+ HANDLE hMpqOrFile,
+ DWORD dwInfoType,
+ void * pvFileInfo,
+ DWORD cbFileInfo,
+ LPDWORD pcbLengthNeeded)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpqOrFile;
+ TMPQBlock * pBlock;
+ TMPQFile * hf = (TMPQFile *)hMpqOrFile;
+ void * pvSrcFileInfo = NULL;
+ DWORD cbLengthNeeded = 0;
+ DWORD dwIsReadOnly;
+ DWORD dwFileCount = 0;
+ DWORD dwFileIndex;
+ DWORD dwFileKey;
+ DWORD i;
+ int nError = ERROR_SUCCESS;
+
+ switch(dwInfoType)
+ {
+ case SFILE_INFO_ARCHIVE_NAME:
+ VERIFY_MPQ_HANDLE(ha);
+
+ // pvFileInfo receives the name of the archive, terminated by 0
+ pvSrcFileInfo = FileStream_GetFileName(ha->pStream);
+ cbLengthNeeded = (DWORD)(_tcslen((TCHAR *)pvSrcFileInfo) + 1) * sizeof(TCHAR);
+ break;
+
+ case SFILE_INFO_ARCHIVE_SIZE: // Size of the archive
+ VERIFY_MPQ_HANDLE(ha);
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &ha->pHeader->dwArchiveSize;
+ break;
+
+ case SFILE_INFO_MAX_FILE_COUNT: // Max. number of files in the MPQ
+ VERIFY_MPQ_HANDLE(ha);
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &ha->dwMaxFileCount;
+ break;
+
+ case SFILE_INFO_HASH_TABLE_SIZE: // Size of the hash table
+ VERIFY_MPQ_HANDLE(ha);
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &ha->pHeader->dwHashTableSize;
+ break;
+
+ case SFILE_INFO_BLOCK_TABLE_SIZE: // Size of the block table
+ VERIFY_MPQ_HANDLE(ha);
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &ha->pHeader->dwBlockTableSize;
+ break;
+
+ case SFILE_INFO_SECTOR_SIZE:
+ VERIFY_MPQ_HANDLE(ha);
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &ha->dwSectorSize;
+ break;
+
+ case SFILE_INFO_HASH_TABLE:
+ VERIFY_MPQ_HANDLE(ha);
+ cbLengthNeeded = ha->pHeader->dwHashTableSize * sizeof(TMPQHash);
+ pvSrcFileInfo = ha->pHashTable;
+ break;
+
+ case SFILE_INFO_BLOCK_TABLE:
+ VERIFY_MPQ_HANDLE(ha);
+ cbLengthNeeded = ha->dwFileTableSize * sizeof(TMPQBlock);
+ if(cbFileInfo < cbLengthNeeded)
+ {
+ nError = ERROR_INSUFFICIENT_BUFFER;
+ break;
+ }
+
+ // Construct block table from file table size
+ pBlock = (TMPQBlock *)pvFileInfo;
+ for(i = 0; i < ha->dwFileTableSize; i++)
+ {
+ pBlock->dwFilePos = (DWORD)ha->pFileTable[i].ByteOffset;
+ pBlock->dwFSize = ha->pFileTable[i].dwFileSize;
+ pBlock->dwCSize = ha->pFileTable[i].dwCmpSize;
+ pBlock->dwFlags = ha->pFileTable[i].dwFlags;
+ pBlock++;
+ }
+ break;
+
+ case SFILE_INFO_NUM_FILES:
+ VERIFY_MPQ_HANDLE(ha);
+ dwFileCount = GetMpqFileCount(ha);
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &dwFileCount;
+ break;
+
+ case SFILE_INFO_STREAM_FLAGS: // Deprecated
+ nError = ERROR_INVALID_PARAMETER;
+ break;
+
+ case SFILE_INFO_IS_READ_ONLY:
+ VERIFY_MPQ_HANDLE(ha);
+ dwIsReadOnly = (FileStream_IsReadOnly(ha->pStream) || (ha->dwFlags & MPQ_FLAG_READ_ONLY));
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &dwIsReadOnly;
+ break;
+
+ case SFILE_INFO_HASH_INDEX:
+ VERIFY_FILE_HANDLE(hf);
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &hf->pFileEntry->dwHashIndex;
+ break;
+
+ case SFILE_INFO_CODENAME1:
+ VERIFY_FILE_HANDLE(hf);
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &hf->pFileEntry->dwHashIndex;
+ if(ha->pHashTable != NULL)
+ pvSrcFileInfo = &ha->pHashTable[hf->pFileEntry->dwHashIndex].dwName1;
+ break;
+
+ case SFILE_INFO_CODENAME2:
+ VERIFY_FILE_HANDLE(hf);
+ cbLengthNeeded = sizeof(DWORD);
+ if(ha->pHashTable != NULL)
+ pvSrcFileInfo = &ha->pHashTable[hf->pFileEntry->dwHashIndex].dwName2;
+ break;
+
+ case SFILE_INFO_LOCALEID:
+ VERIFY_FILE_HANDLE(hf);
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &hf->pFileEntry->lcLocale;
+ break;
+
+ case SFILE_INFO_BLOCKINDEX:
+ VERIFY_FILE_HANDLE(hf);
+ dwFileIndex = (DWORD)(hf->pFileEntry - hf->ha->pFileTable);
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &dwFileIndex;
+ break;
+
+ case SFILE_INFO_FILE_SIZE:
+ VERIFY_FILE_HANDLE(hf);
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &hf->pFileEntry->dwFileSize;
+ break;
+
+ case SFILE_INFO_COMPRESSED_SIZE:
+ VERIFY_FILE_HANDLE(hf);
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &hf->pFileEntry->dwCmpSize;
+ break;
+
+ case SFILE_INFO_FLAGS:
+ VERIFY_FILE_HANDLE(hf);
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &hf->pFileEntry->dwFlags;
+ break;
+
+ case SFILE_INFO_POSITION:
+ VERIFY_FILE_HANDLE(hf);
+ cbLengthNeeded = sizeof(ULONGLONG);
+ pvSrcFileInfo = &hf->pFileEntry->ByteOffset;
+ break;
+
+ case SFILE_INFO_KEY:
+ VERIFY_FILE_HANDLE(hf);
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &hf->dwFileKey;
+ break;
+
+ case SFILE_INFO_KEY_UNFIXED:
+ VERIFY_FILE_HANDLE(hf);
+ dwFileKey = hf->dwFileKey;
+ if(hf->pFileEntry->dwFlags & MPQ_FILE_FIX_KEY)
+ dwFileKey = (dwFileKey ^ hf->pFileEntry->dwFileSize) - (DWORD)hf->MpqFilePos;
+ cbLengthNeeded = sizeof(DWORD);
+ pvSrcFileInfo = &dwFileKey;
+ break;
+
+ case SFILE_INFO_FILETIME:
+ VERIFY_FILE_HANDLE(hf);
+ cbLengthNeeded = sizeof(ULONGLONG);
+ pvSrcFileInfo = &hf->pFileEntry->FileTime;
+ break;
+
+ case SFILE_INFO_PATCH_CHAIN:
+ VERIFY_FILE_HANDLE(hf);
+ GetFilePatchChain(hf, pvFileInfo, cbFileInfo, &cbLengthNeeded);
+ break;
+
+ default:
+ nError = ERROR_INVALID_PARAMETER;
+ break;
+ }
+
+ // If everything is OK so far, copy the information
+ if(nError == ERROR_SUCCESS)
+ {
+ // Is the output buffer large enough?
+ if(cbFileInfo >= cbLengthNeeded)
+ {
+ // Copy the data
+ if(pvSrcFileInfo != NULL)
+ memcpy(pvFileInfo, pvSrcFileInfo, cbLengthNeeded);
+ }
+ else
+ {
+ nError = ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ // Give the size to the caller
+ if(pcbLengthNeeded != NULL)
+ *pcbLengthNeeded = cbLengthNeeded;
+ }
+
+ // Set the last error value, if needed
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return (nError == ERROR_SUCCESS);
+}
diff --git a/dep/StormLib/src/SFileVerify.cpp b/dep/StormLib/src/SFileVerify.cpp
new file mode 100644
index 00000000000..7457171d88f
--- /dev/null
+++ b/dep/StormLib/src/SFileVerify.cpp
@@ -0,0 +1,921 @@
+/*****************************************************************************/
+/* SFileVerify.cpp Copyright (c) Ladislav Zezula 2010 */
+/*---------------------------------------------------------------------------*/
+/* MPQ files and MPQ archives verification. */
+/* */
+/* The MPQ signature verification has been written by Jean-Francois Roy */
+/* <bahamut@macstorm.org> and Justin Olbrantz (Quantam). */
+/* The MPQ public keys have been created by MPQKit, using OpenSSL library. */
+/* */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 04.05.10 1.00 Lad The first version of SFileVerify.cpp */
+/*****************************************************************************/
+
+#define __STORMLIB_SELF__
+#include "StormLib.h"
+#include "StormCommon.h"
+
+//-----------------------------------------------------------------------------
+// Local defines
+
+#define SIGNATURE_TYPE_NONE 0
+#define SIGNATURE_TYPE_WEAK 1
+#define SIGNATURE_TYPE_STRONG 2
+
+#define MPQ_DIGEST_UNIT_SIZE 0x10000
+
+typedef struct _MPQ_SIGNATURE_INFO
+{
+ ULONGLONG BeginMpqData; // File offset where the hashing starts
+ ULONGLONG BeginExclude; // Begin of the excluded area (used for (signature) file)
+ ULONGLONG EndExclude; // End of the excluded area (used for (signature) file)
+ ULONGLONG EndMpqData; // File offset where the hashing ends
+ ULONGLONG EndOfFile; // Size of the entire file
+ BYTE Signature[MPQ_STRONG_SIGNATURE_SIZE + 0x10];
+ DWORD cbSignatureSize; // Length of the signature
+ int nSignatureType; // See SIGNATURE_TYPE_XXX
+
+} MPQ_SIGNATURE_INFO, *PMPQ_SIGNATURE_INFO;
+
+//-----------------------------------------------------------------------------
+// Known Blizzard public keys
+// Created by Jean-Francois Roy using OpenSSL
+
+static const char * szBlizzardWeakPublicKey =
+ "-----BEGIN PUBLIC KEY-----"
+ "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJJidwS/uILMBSO5DLGsBFknIXWWjQJe"
+ "2kfdfEk3G/j66w4KkhZ1V61Rt4zLaMVCYpDun7FLwRjkMDSepO1q2DcCAwEAAQ=="
+ "-----END PUBLIC KEY-----";
+
+static const char * szBlizzardStrongPublicKey =
+ "-----BEGIN PUBLIC KEY-----"
+ "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsQZ+ziT2h8h+J/iMQpgd"
+ "tH1HaJzOBE3agjU4yMPcrixaPOZoA4t8bwfey7qczfWywocYo3pleytFF+IuD4HD"
+ "Fl9OXN1SFyupSgMx1EGZlgbFAomnbq9MQJyMqQtMhRAjFgg4TndS7YNb+JMSAEKp"
+ "kXNqY28n/EVBHD5TsMuVCL579gIenbr61dI92DDEdy790IzIG0VKWLh/KOTcTJfm"
+ "Ds/7HQTkGouVW+WUsfekuqNQo7ND9DBnhLjLjptxeFE2AZqYcA1ao3S9LN3GL1tW"
+ "lVXFIX9c7fWqaVTQlZ2oNsI/ARVApOK3grNgqvwH6YoVYVXjNJEo5sQJsPsdV/hk"
+ "dwIDAQAB"
+ "-----END PUBLIC KEY-----";
+
+static const char * szWarcraft3MapPublicKey =
+ "-----BEGIN PUBLIC KEY-----"
+ "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1BwklUUQ3UvjizOBRoF5"
+ "yyOVc7KD+oGOQH5i6eUk1yfs0luCC70kNucNrfqhmviywVtahRse1JtXCPrx2bd3"
+ "iN8Dx91fbkxjYIOGTsjYoHKTp0BbaFkJih776fcHgnFSb+7mJcDuJVvJOXxEH6w0"
+ "1vo6VtujCqj1arqbyoal+xtAaczF3us5cOEp45sR1zAWTn1+7omN7VWV4QqJPaDS"
+ "gBSESc0l1grO0i1VUSumayk7yBKIkb+LBvcG6WnYZHCi7VdLmaxER5m8oZfER66b"
+ "heHoiSQIZf9PAY6Guw2DT5BTc54j/AaLQAKf2qcRSgQLVo5kQaddF3rCpsXoB/74"
+ "6QIDAQAB"
+ "-----END PUBLIC KEY-----";
+
+static const char * szWowPatchPublicKey =
+ "-----BEGIN PUBLIC KEY-----"
+ "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwOsMV0LagAWPEtEQM6b9"
+ "6FHFkUyGbbyda2/Dfc9dyl21E9QvX+Yw7qKRMAKPzA2TlQQLZKvXpnKXF/YIK5xa"
+ "5uwg9CEHCEAYolLG4xn0FUOE0E/0PuuytI0p0ICe6rk00PifZzTr8na2wI/l/GnQ"
+ "bvnIVF1ck6cslATpQJ5JJVMXzoFlUABS19WESw4MXuJAS3AbMhxNWdEhVv7eO51c"
+ "yGjRLy9QjogZODZTY0fSEksgBqQxNCoYVJYI/sF5K2flDsGqrIp0OdJ6teJlzg1Y"
+ "UjYnb6bKjlidXoHEXI2TgA/mD6O3XFIt08I9s3crOCTgICq7cgX35qrZiIVWZdRv"
+ "TwIDAQAB"
+ "-----END PUBLIC KEY-----";
+
+static const char * szWowSurveyPublicKey =
+ "-----BEGIN PUBLIC KEY-----"
+ "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnIt1DR6nRyyKsy2qahHe"
+ "MKLtacatn/KxieHcwH87wLBxKy+jZ0gycTmJ7SaTdBAEMDs/V5IPIXEtoqYnid2c"
+ "63TmfGDU92oc3Ph1PWUZ2PWxBhT06HYxRdbrgHw9/I29pNPi/607x+lzPORITOgU"
+ "BR6MR8au8HsQP4bn4vkJNgnSgojh48/XQOB/cAln7As1neP61NmVimoLR4Bwi3zt"
+ "zfgrZaUpyeNCUrOYJmH09YIjbBySTtXOUidoPHjFrMsCWpr6xs8xbETbs7MJFL6a"
+ "vcUfTT67qfIZ9RsuKfnXJTIrV0kwDSjjuNXiPTmWAehSsiHIsrUXX5RNcwsSjClr"
+ "nQIDAQAB"
+ "-----END PUBLIC KEY-----";
+
+static const char * szStarcraft2MapPublicKey =
+ "-----BEGIN PUBLIC KEY-----"
+ "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmk4GT8zb+ICC25a17KZB"
+ "q/ygKGJ2VSO6IT5PGHJlm1KfnHBA4B6SH3xMlJ4c6eG2k7QevZv+FOhjsAHubyWq"
+ "2VKqWbrIFKv2ILc2RfMn8J9EDVRxvcxh6slRrVL69D0w1tfVGjMiKq2Fym5yGoRT"
+ "E7CRgDqbAbXP9LBsCNWHiJLwfxMGzHbk8pIl9oia5pvM7ofZamSHchxlpy6xa4GJ"
+ "7xKN01YCNvklTL1D7uol3wkwcHc7vrF8QwuJizuA5bSg4poEGtH62BZOYi+UL/z0"
+ "31YK+k9CbQyM0X0pJoJoYz1TK+Y5J7vBnXCZtfcTYQ/ZzN6UcxTa57dJaiOlCh9z"
+ "nQIDAQAB"
+ "-----END PUBLIC KEY-----";
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static void memrev(unsigned char *buf, size_t count)
+{
+ unsigned char *r;
+
+ for (r = buf + count - 1; buf < r; buf++, r--)
+ {
+ *buf ^= *r;
+ *r ^= *buf;
+ *buf ^= *r;
+ }
+}
+
+static bool is_valid_md5(void * pvMd5)
+{
+ LPDWORD Md5 = (LPDWORD)pvMd5;
+
+ return (Md5[0] | Md5[1] | Md5[2] | Md5[3]) ? true : false;
+}
+
+static bool decode_base64_key(const char * szKeyBase64, rsa_key * key)
+{
+ unsigned char decoded_key[0x200];
+ const char * szBase64Begin;
+ const char * szBase64End;
+ unsigned long decoded_length = sizeof(decoded_key);
+ unsigned long length;
+
+ // Find out the begin of the BASE64 data
+ szBase64Begin = szKeyBase64 + strlen("-----BEGIN PUBLIC KEY-----");
+ szBase64End = szBase64Begin + strlen(szBase64Begin) - strlen("-----END PUBLIC KEY-----");
+ if(szBase64End[0] != '-')
+ return false;
+
+ // decode the base64 string
+ length = (unsigned long)(szBase64End - szBase64Begin);
+ if(base64_decode((unsigned char *)szBase64Begin, length, decoded_key, &decoded_length) != CRYPT_OK)
+ return false;
+
+ // Create RSA key
+ if(rsa_import(decoded_key, decoded_length, key) != CRYPT_OK)
+ return false;
+
+ return true;
+}
+
+static void GetPlainAnsiFileName(
+ const TCHAR * szFileName,
+ char * szPlainName)
+{
+ const TCHAR * szPlainNameT = GetPlainFileNameT(szFileName);
+
+ // Convert the plain name to ANSI
+ while(*szPlainNameT != 0)
+ *szPlainName++ = (char)*szPlainNameT++;
+ *szPlainName = 0;
+}
+
+// Calculate begin and end of the MPQ archive
+static void CalculateArchiveRange(
+ TMPQArchive * ha,
+ PMPQ_SIGNATURE_INFO pSI)
+{
+ ULONGLONG TempPos = 0;
+ char szMapHeader[0x200];
+
+ // Get the MPQ begin
+ pSI->BeginMpqData = ha->MpqPos;
+
+ // Warcraft III maps are signed from the map header to the end
+ if(FileStream_Read(ha->pStream, &TempPos, szMapHeader, sizeof(szMapHeader)))
+ {
+ // Is it a map header ?
+ if(szMapHeader[0] == 'H' && szMapHeader[1] == 'M' && szMapHeader[2] == '3' && szMapHeader[3] == 'W')
+ {
+ // We will have to hash since the map header
+ pSI->BeginMpqData = 0;
+ }
+ }
+
+ // Get the MPQ data end. This is stored in our MPQ header,
+ // and it's been already prepared by SFileOpenArchive,
+ pSI->EndMpqData = ha->MpqPos + ha->pHeader->ArchiveSize64;
+
+ // Get the size of the entire file
+ FileStream_GetSize(ha->pStream, pSI->EndOfFile);
+}
+
+static bool QueryMpqSignatureInfo(
+ TMPQArchive * ha,
+ PMPQ_SIGNATURE_INFO pSI)
+{
+ ULONGLONG ExtraBytes;
+ TMPQFile * hf;
+ HANDLE hFile;
+ DWORD dwFileSize;
+
+ // Calculate the range of the MPQ
+ CalculateArchiveRange(ha, pSI);
+
+ // If there is "(signature)" file in the MPQ, it has a weak signature
+ if(SFileOpenFileEx((HANDLE)ha, SIGNATURE_NAME, SFILE_OPEN_FROM_MPQ, &hFile))
+ {
+ // Get the content of the signature
+ SFileReadFile(hFile, pSI->Signature, sizeof(pSI->Signature), &pSI->cbSignatureSize);
+
+ // Verify the size of the signature
+ hf = (TMPQFile *)hFile;
+
+ // We have to exclude the signature file from the digest
+ pSI->BeginExclude = ha->MpqPos + hf->pFileEntry->ByteOffset;
+ pSI->EndExclude = pSI->BeginExclude + hf->pFileEntry->dwCmpSize;
+ dwFileSize = hf->dwDataSize;
+
+ // Close the file
+ SFileCloseFile(hFile);
+ pSI->nSignatureType = SIGNATURE_TYPE_WEAK;
+ return (dwFileSize == (MPQ_WEAK_SIGNATURE_SIZE + 8)) ? true : false;
+ }
+
+ // If there is extra bytes beyond the end of the archive,
+ // it's the strong signature
+ ExtraBytes = pSI->EndOfFile - pSI->EndMpqData;
+ if(ExtraBytes >= (MPQ_STRONG_SIGNATURE_SIZE + 4))
+ {
+ // Read the strong signature
+ if(!FileStream_Read(ha->pStream, &pSI->EndMpqData, pSI->Signature, (MPQ_STRONG_SIGNATURE_SIZE + 4)))
+ return false;
+
+ // Check the signature header "NGIS"
+ if(pSI->Signature[0] != 'N' || pSI->Signature[1] != 'G' || pSI->Signature[2] != 'I' || pSI->Signature[3] != 'S')
+ return false;
+
+ pSI->nSignatureType = SIGNATURE_TYPE_STRONG;
+ return true;
+ }
+
+ // Succeeded, but no known signature found
+ return true;
+}
+
+static bool CalculateMpqHashMd5(
+ TMPQArchive * ha,
+ PMPQ_SIGNATURE_INFO pSI,
+ LPBYTE pMd5Digest)
+{
+ hash_state md5_state;
+ ULONGLONG BeginBuffer;
+ ULONGLONG EndBuffer;
+ LPBYTE pbDigestBuffer = NULL;
+
+ // Allocate buffer for creating the MPQ digest.
+ pbDigestBuffer = STORM_ALLOC(BYTE, MPQ_DIGEST_UNIT_SIZE);
+ if(pbDigestBuffer == NULL)
+ return false;
+
+ // Initialize the MD5 hash state
+ md5_init(&md5_state);
+
+ // Set the byte offset of begin of the data
+ BeginBuffer = pSI->BeginMpqData;
+
+ // Create the digest
+ for(;;)
+ {
+ ULONGLONG BytesRemaining;
+ LPBYTE pbSigBegin = NULL;
+ LPBYTE pbSigEnd = NULL;
+ DWORD dwToRead = MPQ_DIGEST_UNIT_SIZE;
+
+ // Check the number of bytes remaining
+ BytesRemaining = pSI->EndMpqData - BeginBuffer;
+ if(BytesRemaining < MPQ_DIGEST_UNIT_SIZE)
+ dwToRead = (DWORD)BytesRemaining;
+ if(dwToRead == 0)
+ break;
+
+ // Read the next chunk
+ if(!FileStream_Read(ha->pStream, &BeginBuffer, pbDigestBuffer, dwToRead))
+ {
+ STORM_FREE(pbDigestBuffer);
+ return false;
+ }
+
+ // Move the current byte offset
+ EndBuffer = BeginBuffer + dwToRead;
+
+ // Check if the signature is within the loaded digest
+ if(BeginBuffer <= pSI->BeginExclude && pSI->BeginExclude < EndBuffer)
+ pbSigBegin = pbDigestBuffer + (size_t)(pSI->BeginExclude - BeginBuffer);
+ if(BeginBuffer <= pSI->EndExclude && pSI->EndExclude < EndBuffer)
+ pbSigEnd = pbDigestBuffer + (size_t)(pSI->EndExclude - BeginBuffer);
+
+ // Zero the part that belongs to the signature
+ if(pbSigBegin != NULL || pbSigEnd != NULL)
+ {
+ if(pbSigBegin == NULL)
+ pbSigBegin = pbDigestBuffer;
+ if(pbSigEnd == NULL)
+ pbSigEnd = pbDigestBuffer + dwToRead;
+
+ memset(pbSigBegin, 0, (pbSigEnd - pbSigBegin));
+ }
+
+ // Pass the buffer to the hashing function
+ md5_process(&md5_state, pbDigestBuffer, dwToRead);
+
+ // Move pointers
+ BeginBuffer += dwToRead;
+ }
+
+ // Finalize the MD5 hash
+ md5_done(&md5_state, pMd5Digest);
+ STORM_FREE(pbDigestBuffer);
+ return true;
+}
+
+static void AddTailToSha1(
+ hash_state * psha1_state,
+ const char * szTail)
+{
+ unsigned char szUpperCase[0x200];
+ unsigned long nLength = 0;
+
+ // Convert the tail to uppercase
+ // Note that we don't need to terminate the string with zero
+ while(*szTail != 0)
+ {
+ szUpperCase[nLength++] = (unsigned char)toupper(*szTail++);
+ }
+
+ // Append the tail to the SHA1
+ sha1_process(psha1_state, szUpperCase, nLength);
+}
+
+static bool CalculateMpqHashSha1(
+ TMPQArchive * ha,
+ PMPQ_SIGNATURE_INFO pSI,
+ unsigned char * sha1_tail0,
+ unsigned char * sha1_tail1,
+ unsigned char * sha1_tail2)
+{
+ ULONGLONG BeginBuffer;
+ hash_state sha1_state_temp;
+ hash_state sha1_state;
+ LPBYTE pbDigestBuffer = NULL;
+ char szPlainName[MAX_PATH];
+
+ // Allocate buffer for creating the MPQ digest.
+ pbDigestBuffer = STORM_ALLOC(BYTE, MPQ_DIGEST_UNIT_SIZE);
+ if(pbDigestBuffer == NULL)
+ return false;
+
+ // Initialize SHA1 state structure
+ sha1_init(&sha1_state);
+
+ // Calculate begin of data to be hashed
+ BeginBuffer = pSI->BeginMpqData;
+
+ // Create the digest
+ for(;;)
+ {
+ ULONGLONG BytesRemaining;
+ DWORD dwToRead = MPQ_DIGEST_UNIT_SIZE;
+
+ // Check the number of bytes remaining
+ BytesRemaining = pSI->EndMpqData - BeginBuffer;
+ if(BytesRemaining < MPQ_DIGEST_UNIT_SIZE)
+ dwToRead = (DWORD)BytesRemaining;
+ if(dwToRead == 0)
+ break;
+
+ // Read the next chunk
+ if(!FileStream_Read(ha->pStream, &BeginBuffer, pbDigestBuffer, dwToRead))
+ {
+ STORM_FREE(pbDigestBuffer);
+ return false;
+ }
+
+ // Pass the buffer to the hashing function
+ sha1_process(&sha1_state, pbDigestBuffer, dwToRead);
+
+ // Move pointers
+ BeginBuffer += dwToRead;
+ }
+
+ // Add all three known tails and generate three hashes
+ memcpy(&sha1_state_temp, &sha1_state, sizeof(hash_state));
+ sha1_done(&sha1_state_temp, sha1_tail0);
+
+ memcpy(&sha1_state_temp, &sha1_state, sizeof(hash_state));
+ GetPlainAnsiFileName(FileStream_GetFileName(ha->pStream), szPlainName);
+ AddTailToSha1(&sha1_state_temp, szPlainName);
+ sha1_done(&sha1_state_temp, sha1_tail1);
+
+ memcpy(&sha1_state_temp, &sha1_state, sizeof(hash_state));
+ AddTailToSha1(&sha1_state_temp, "ARCHIVE");
+ sha1_done(&sha1_state_temp, sha1_tail2);
+
+ // Finalize the MD5 hash
+ STORM_FREE(pbDigestBuffer);
+ return true;
+}
+
+static int VerifyRawMpqData(
+ TMPQArchive * ha,
+ ULONGLONG ByteOffset,
+ DWORD dwDataSize)
+{
+ ULONGLONG DataOffset = ha->MpqPos + ByteOffset;
+ LPBYTE pbDataChunk;
+ LPBYTE pbMD5Array1; // Calculated MD5 array
+ LPBYTE pbMD5Array2; // MD5 array loaded from the MPQ
+ DWORD dwBytesInChunk;
+ DWORD dwChunkCount;
+ DWORD dwChunkSize = ha->pHeader->dwRawChunkSize;
+ DWORD dwMD5Size;
+ int nError = ERROR_SUCCESS;
+
+ // Don't verify zero-sized blocks
+ if(dwDataSize == 0)
+ return ERROR_SUCCESS;
+
+ // Get the number of data chunks to calculate MD5
+ assert(dwChunkSize != 0);
+ dwChunkCount = ((dwDataSize - 1) / dwChunkSize) + 1;
+ dwMD5Size = dwChunkCount * MD5_DIGEST_SIZE;
+
+ // Allocate space for data chunk and for the MD5 array
+ pbDataChunk = STORM_ALLOC(BYTE, dwChunkSize);
+ if(pbDataChunk == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Allocate space for MD5 array
+ pbMD5Array1 = STORM_ALLOC(BYTE, dwMD5Size);
+ pbMD5Array2 = STORM_ALLOC(BYTE, dwMD5Size);
+ if(pbMD5Array1 == NULL || pbMD5Array2 == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+
+ // Calculate MD5 of each data chunk
+ if(nError == ERROR_SUCCESS)
+ {
+ LPBYTE pbMD5 = pbMD5Array1;
+
+ for(DWORD i = 0; i < dwChunkCount; i++)
+ {
+ // Get the number of bytes in the chunk
+ dwBytesInChunk = STORMLIB_MIN(dwChunkSize, dwDataSize);
+
+ // Read the data chunk
+ if(!FileStream_Read(ha->pStream, &DataOffset, pbDataChunk, dwBytesInChunk))
+ {
+ nError = ERROR_FILE_CORRUPT;
+ break;
+ }
+
+ // Calculate MD5
+ CalculateDataBlockHash(pbDataChunk, dwBytesInChunk, pbMD5);
+
+ // Move pointers and offsets
+ DataOffset += dwBytesInChunk;
+ dwDataSize -= dwBytesInChunk;
+ pbMD5 += MD5_DIGEST_SIZE;
+ }
+ }
+
+ // Read the MD5 array
+ if(nError == ERROR_SUCCESS)
+ {
+ // Read the array of MD5
+ if(!FileStream_Read(ha->pStream, &DataOffset, pbMD5Array2, dwMD5Size))
+ nError = GetLastError();
+ }
+
+ // Compare the array of MD5
+ if(nError == ERROR_SUCCESS)
+ {
+ // Compare the MD5
+ if(memcmp(pbMD5Array1, pbMD5Array2, dwMD5Size))
+ nError = ERROR_FILE_CORRUPT;
+ }
+
+ // Free memory and return result
+ if(pbMD5Array2 != NULL)
+ STORM_FREE(pbMD5Array2);
+ if(pbMD5Array1 != NULL)
+ STORM_FREE(pbMD5Array1);
+ if(pbDataChunk != NULL)
+ STORM_FREE(pbDataChunk);
+ return nError;
+}
+
+static DWORD VerifyWeakSignature(
+ TMPQArchive * ha,
+ PMPQ_SIGNATURE_INFO pSI)
+{
+ BYTE RevSignature[MPQ_WEAK_SIGNATURE_SIZE];
+ BYTE Md5Digest[MD5_DIGEST_SIZE];
+ rsa_key key;
+ int hash_idx = find_hash("md5");
+ int result = 0;
+
+ // Calculate hash of the entire archive, skipping the (signature) file
+ if(!CalculateMpqHashMd5(ha, pSI, Md5Digest))
+ return ERROR_VERIFY_FAILED;
+
+ // Import the Blizzard key in OpenSSL format
+ if(!decode_base64_key(szBlizzardWeakPublicKey, &key))
+ return ERROR_VERIFY_FAILED;
+
+ // Verify the signature
+ memcpy(RevSignature, &pSI->Signature[8], MPQ_WEAK_SIGNATURE_SIZE);
+ memrev(RevSignature, MPQ_WEAK_SIGNATURE_SIZE);
+ rsa_verify_hash_ex(RevSignature, MPQ_WEAK_SIGNATURE_SIZE, Md5Digest, sizeof(Md5Digest), LTC_LTC_PKCS_1_V1_5, hash_idx, 0, &result, &key);
+ rsa_free(&key);
+
+ // Return the result
+ return result ? ERROR_WEAK_SIGNATURE_OK : ERROR_WEAK_SIGNATURE_ERROR;
+}
+
+static DWORD VerifyStrongSignatureWithKey(
+ unsigned char * reversed_signature,
+ unsigned char * padded_digest,
+ const char * szPublicKey)
+{
+ rsa_key key;
+ int result = 0;
+
+ // Import the Blizzard key in OpenSSL format
+ if(!decode_base64_key(szPublicKey, &key))
+ {
+ assert(false);
+ return ERROR_VERIFY_FAILED;
+ }
+
+ // Verify the signature
+ if(rsa_verify_simple(reversed_signature, MPQ_STRONG_SIGNATURE_SIZE, padded_digest, MPQ_STRONG_SIGNATURE_SIZE, &result, &key) != CRYPT_OK)
+ return ERROR_VERIFY_FAILED;
+
+ // Free the key and return result
+ rsa_free(&key);
+ return result ? ERROR_STRONG_SIGNATURE_OK : ERROR_STRONG_SIGNATURE_ERROR;
+}
+
+static DWORD VerifyStrongSignature(
+ TMPQArchive * ha,
+ PMPQ_SIGNATURE_INFO pSI)
+{
+ unsigned char reversed_signature[MPQ_STRONG_SIGNATURE_SIZE];
+ unsigned char Sha1Digest_tail0[SHA1_DIGEST_SIZE];
+ unsigned char Sha1Digest_tail1[SHA1_DIGEST_SIZE];
+ unsigned char Sha1Digest_tail2[SHA1_DIGEST_SIZE];
+ unsigned char padded_digest[MPQ_STRONG_SIGNATURE_SIZE];
+ DWORD dwResult;
+ size_t digest_offset;
+
+ // Calculate SHA1 hash of the archive
+ if(!CalculateMpqHashSha1(ha, pSI, Sha1Digest_tail0, Sha1Digest_tail1, Sha1Digest_tail2))
+ return ERROR_VERIFY_FAILED;
+
+ // Prepare the signature for decryption
+ memcpy(reversed_signature, &pSI->Signature[4], MPQ_STRONG_SIGNATURE_SIZE);
+ memrev(reversed_signature, MPQ_STRONG_SIGNATURE_SIZE);
+
+ // Prepare the padded digest for comparison
+ digest_offset = sizeof(padded_digest) - SHA1_DIGEST_SIZE;
+ memset(padded_digest, 0xbb, digest_offset);
+ padded_digest[0] = 0x0b;
+
+ // Try Blizzard Strong public key with no SHA1 tail
+ memcpy(padded_digest + digest_offset, Sha1Digest_tail0, SHA1_DIGEST_SIZE);
+ memrev(padded_digest + digest_offset, SHA1_DIGEST_SIZE);
+ dwResult = VerifyStrongSignatureWithKey(reversed_signature, padded_digest, szBlizzardStrongPublicKey);
+ if(dwResult == ERROR_STRONG_SIGNATURE_OK)
+ return dwResult;
+
+ // Try War 3 map public key with plain file name as SHA1 tail
+ memcpy(padded_digest + digest_offset, Sha1Digest_tail1, SHA1_DIGEST_SIZE);
+ memrev(padded_digest + digest_offset, SHA1_DIGEST_SIZE);
+ dwResult = VerifyStrongSignatureWithKey(reversed_signature, padded_digest, szWarcraft3MapPublicKey);
+ if(dwResult == ERROR_STRONG_SIGNATURE_OK)
+ return dwResult;
+
+ // Try WoW-TBC public key with "ARCHIVE" as SHA1 tail
+ memcpy(padded_digest + digest_offset, Sha1Digest_tail2, SHA1_DIGEST_SIZE);
+ memrev(padded_digest + digest_offset, SHA1_DIGEST_SIZE);
+ dwResult = VerifyStrongSignatureWithKey(reversed_signature, padded_digest, szWowPatchPublicKey);
+ if(dwResult == ERROR_STRONG_SIGNATURE_OK)
+ return dwResult;
+
+ // Try Survey public key with no SHA1 tail
+ memcpy(padded_digest + digest_offset, Sha1Digest_tail0, SHA1_DIGEST_SIZE);
+ memrev(padded_digest + digest_offset, SHA1_DIGEST_SIZE);
+ dwResult = VerifyStrongSignatureWithKey(reversed_signature, padded_digest, szWowSurveyPublicKey);
+ if(dwResult == ERROR_STRONG_SIGNATURE_OK)
+ return dwResult;
+
+ // Try Starcraft II public key with no SHA1 tail
+ memcpy(padded_digest + digest_offset, Sha1Digest_tail0, SHA1_DIGEST_SIZE);
+ memrev(padded_digest + digest_offset, SHA1_DIGEST_SIZE);
+ dwResult = VerifyStrongSignatureWithKey(reversed_signature, padded_digest, szStarcraft2MapPublicKey);
+ if(dwResult == ERROR_STRONG_SIGNATURE_OK)
+ return dwResult;
+
+ return ERROR_STRONG_SIGNATURE_ERROR;
+}
+
+static DWORD VerifyFile(
+ HANDLE hMpq,
+ const char * szFileName,
+ LPDWORD pdwCrc32,
+ char * pMD5,
+ DWORD dwFlags)
+{
+ hash_state md5_state;
+ unsigned char * pFileMd5;
+ unsigned char md5[MD5_DIGEST_SIZE];
+ TFileEntry * pFileEntry;
+ TMPQFile * hf;
+ BYTE Buffer[0x1000];
+ HANDLE hFile = NULL;
+ DWORD dwVerifyResult = 0;
+ DWORD dwSearchScope = SFILE_OPEN_FROM_MPQ;
+ DWORD dwTotalBytes = 0;
+ DWORD dwBytesRead;
+ DWORD dwCrc32 = 0;
+
+ // Fix the open type for patched archives
+ if(SFileIsPatchedArchive(hMpq))
+ dwSearchScope = SFILE_OPEN_PATCHED_FILE;
+
+ // If we have to verify raw data MD5, do it before file open
+ if(dwFlags & SFILE_VERIFY_RAW_MD5)
+ {
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+
+ // Parse the base MPQ and all patches
+ while(ha != NULL)
+ {
+ // Does the archive have support for raw MD5?
+ if(ha->pHeader->dwRawChunkSize != 0)
+ {
+ // The file has raw MD5 if the archive supports it
+ dwVerifyResult |= VERIFY_FILE_HAS_RAW_MD5;
+
+ // Find file entry for the file
+ pFileEntry = GetFileEntryLocale(ha, szFileName, lcFileLocale);
+ if(pFileEntry != NULL)
+ {
+ // If the file's raw MD5 doesn't match, don't bother with more checks
+ if(VerifyRawMpqData(ha, pFileEntry->ByteOffset, pFileEntry->dwCmpSize) != ERROR_SUCCESS)
+ return dwVerifyResult | VERIFY_FILE_RAW_MD5_ERROR;
+ }
+ }
+
+ // Move to the next patch
+ ha = ha->haPatch;
+ }
+ }
+
+ // Attempt to open the file
+ if(SFileOpenFileEx(hMpq, szFileName, dwSearchScope, &hFile))
+ {
+ // Get the file size
+ hf = (TMPQFile *)hFile;
+ pFileEntry = hf->pFileEntry;
+ dwTotalBytes = SFileGetFileSize(hFile, NULL);
+
+ // Initialize the CRC32 and MD5 contexts
+ md5_init(&md5_state);
+ dwCrc32 = crc32(0, Z_NULL, 0);
+
+ // Also turn on sector checksum verification
+ if(dwFlags & SFILE_VERIFY_SECTOR_CRC)
+ hf->bCheckSectorCRCs = true;
+
+ // Go through entire file and update both CRC32 and MD5
+ for(;;)
+ {
+ // Read data from file
+ SFileReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead, NULL);
+ if(dwBytesRead == 0)
+ {
+ if(GetLastError() == ERROR_CHECKSUM_ERROR)
+ dwVerifyResult |= VERIFY_FILE_SECTOR_CRC_ERROR;
+ break;
+ }
+
+ // Update CRC32 value
+ if(dwFlags & SFILE_VERIFY_FILE_CRC)
+ dwCrc32 = crc32(dwCrc32, Buffer, dwBytesRead);
+
+ // Update MD5 value
+ if(dwFlags & SFILE_VERIFY_FILE_MD5)
+ md5_process(&md5_state, Buffer, dwBytesRead);
+
+ // Decrement the total size
+ dwTotalBytes -= dwBytesRead;
+ }
+
+ // If the file has sector checksums, indicate it in the flags
+ if(dwFlags & SFILE_VERIFY_SECTOR_CRC)
+ {
+ if((hf->pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC) && hf->SectorChksums != NULL && hf->SectorChksums[0] != 0)
+ dwVerifyResult |= VERIFY_FILE_HAS_SECTOR_CRC;
+ }
+
+ // Check if the entire file has been read
+ // No point in checking CRC32 and MD5 if not
+ // Skip checksum checks if the file has patches
+ if(dwTotalBytes == 0)
+ {
+ // Check CRC32 and MD5 only if there is no patches
+ if(hf->hfPatchFile == NULL)
+ {
+ // Check if the CRC32 matches.
+ if(dwFlags & SFILE_VERIFY_FILE_CRC)
+ {
+ // Only check the CRC32 if it is valid
+ if(pFileEntry->dwCrc32 != 0)
+ {
+ dwVerifyResult |= VERIFY_FILE_HAS_CHECKSUM;
+ if(dwCrc32 != pFileEntry->dwCrc32)
+ dwVerifyResult |= VERIFY_FILE_CHECKSUM_ERROR;
+ }
+ }
+
+ // Check if MD5 matches
+ if(dwFlags & SFILE_VERIFY_FILE_MD5)
+ {
+ // Patch files have their MD5 saved in the patch info
+ pFileMd5 = (hf->pPatchInfo != NULL) ? hf->pPatchInfo->md5 : pFileEntry->md5;
+ md5_done(&md5_state, md5);
+
+ // Only check the MD5 if it is valid
+ if(is_valid_md5(pFileMd5))
+ {
+ dwVerifyResult |= VERIFY_FILE_HAS_MD5;
+ if(memcmp(md5, pFileMd5, MD5_DIGEST_SIZE))
+ dwVerifyResult |= VERIFY_FILE_MD5_ERROR;
+ }
+ }
+ }
+ else
+ {
+ // Patched files are MD5-checked automatically
+ dwVerifyResult |= VERIFY_FILE_HAS_MD5;
+ }
+ }
+ else
+ {
+ dwVerifyResult |= VERIFY_READ_ERROR;
+ }
+
+ SFileCloseFile(hFile);
+ }
+ else
+ {
+ // Remember that the file couldn't be open
+ dwVerifyResult |= VERIFY_OPEN_ERROR;
+ }
+
+ // If the caller required CRC32 and/or MD5, give it to him
+ if(pdwCrc32 != NULL)
+ *pdwCrc32 = dwCrc32;
+ if(pMD5 != NULL)
+ memcpy(pMD5, md5, MD5_DIGEST_SIZE);
+
+ return dwVerifyResult;
+}
+
+//-----------------------------------------------------------------------------
+// Public (exported) functions
+
+bool WINAPI SFileGetFileChecksums(HANDLE hMpq, const char * szFileName, LPDWORD pdwCrc32, char * pMD5)
+{
+ DWORD dwVerifyResult;
+ DWORD dwVerifyFlags = 0;
+
+ if(pdwCrc32 != NULL)
+ dwVerifyFlags |= SFILE_VERIFY_FILE_CRC;
+ if(pMD5 != NULL)
+ dwVerifyFlags |= SFILE_VERIFY_FILE_MD5;
+
+ dwVerifyResult = VerifyFile(hMpq,
+ szFileName,
+ pdwCrc32,
+ pMD5,
+ dwVerifyFlags);
+
+ // If verification failed, return zero
+ if(dwVerifyResult & VERIFY_FILE_ERROR_MASK)
+ {
+ SetLastError(ERROR_FILE_CORRUPT);
+ return false;
+ }
+
+ return true;
+}
+
+
+DWORD WINAPI SFileVerifyFile(HANDLE hMpq, const char * szFileName, DWORD dwFlags)
+{
+ return VerifyFile(hMpq,
+ szFileName,
+ NULL,
+ NULL,
+ dwFlags);
+}
+
+// Verifies raw data of the archive Only works for MPQs version 4 or newer
+int WINAPI SFileVerifyRawData(HANDLE hMpq, DWORD dwWhatToVerify, const char * szFileName)
+{
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+ TFileEntry * pFileEntry;
+ TMPQHeader * pHeader;
+
+ // Verify input parameters
+ if(!IsValidMpqHandle(ha))
+ return ERROR_INVALID_PARAMETER;
+ pHeader = ha->pHeader;
+
+ // If the archive doesn't have raw data MD5, report it as OK
+ if(pHeader->dwRawChunkSize == 0)
+ return ERROR_SUCCESS;
+
+ // If we have to verify MPQ header, do it
+ switch(dwWhatToVerify)
+ {
+ case SFILE_VERIFY_MPQ_HEADER:
+
+ // Only if the header is of version 4 or newer
+ if(pHeader->dwHeaderSize >= (MPQ_HEADER_SIZE_V4 - MD5_DIGEST_SIZE))
+ return VerifyRawMpqData(ha, 0, MPQ_HEADER_SIZE_V4 - MD5_DIGEST_SIZE);
+ return ERROR_SUCCESS;
+
+ case SFILE_VERIFY_HET_TABLE:
+
+ // Only if we have HET table
+ if(pHeader->HetTablePos64 && pHeader->HetTableSize64)
+ return VerifyRawMpqData(ha, pHeader->HetTablePos64, (DWORD)pHeader->HetTableSize64);
+ return ERROR_SUCCESS;
+
+ case SFILE_VERIFY_BET_TABLE:
+
+ // Only if we have BET table
+ if(pHeader->BetTablePos64 && pHeader->BetTableSize64)
+ return VerifyRawMpqData(ha, pHeader->BetTablePos64, (DWORD)pHeader->BetTableSize64);
+ return ERROR_SUCCESS;
+
+ case SFILE_VERIFY_HASH_TABLE:
+
+ // Hash table is not protected by MD5
+ return ERROR_SUCCESS;
+
+ case SFILE_VERIFY_BLOCK_TABLE:
+
+ // Block table is not protected by MD5
+ return ERROR_SUCCESS;
+
+ case SFILE_VERIFY_HIBLOCK_TABLE:
+
+ // It is unknown if the hi-block table is protected my MD5 or not.
+ return ERROR_SUCCESS;
+
+ case SFILE_VERIFY_FILE:
+
+ // Verify parameters
+ if(szFileName == NULL || *szFileName == 0)
+ return ERROR_INVALID_PARAMETER;
+
+ // Get the offset of a file
+ pFileEntry = GetFileEntryLocale(ha, szFileName, lcFileLocale);
+ if(pFileEntry == NULL)
+ return ERROR_FILE_NOT_FOUND;
+
+ return VerifyRawMpqData(ha, pFileEntry->ByteOffset, pFileEntry->dwCmpSize);
+ }
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+// Verifies the archive against the signature
+DWORD WINAPI SFileVerifyArchive(HANDLE hMpq)
+{
+ MPQ_SIGNATURE_INFO si;
+ TMPQArchive * ha = (TMPQArchive *)hMpq;
+
+ // Verify input parameters
+ if(!IsValidMpqHandle(ha))
+ return ERROR_VERIFY_FAILED;
+
+ // Get the MPQ signature and signature type
+ memset(&si, 0, sizeof(MPQ_SIGNATURE_INFO));
+ if(!QueryMpqSignatureInfo(ha, &si))
+ return ERROR_VERIFY_FAILED;
+
+ // Verify the signature
+ switch(si.nSignatureType)
+ {
+ case SIGNATURE_TYPE_NONE:
+ return ERROR_NO_SIGNATURE;
+
+ case SIGNATURE_TYPE_WEAK:
+ return VerifyWeakSignature(ha, &si);
+
+ case SIGNATURE_TYPE_STRONG:
+ return VerifyStrongSignature(ha, &si);
+ }
+
+ return ERROR_VERIFY_FAILED;
+}
diff --git a/dep/StormLib/src/StormCommon.h b/dep/StormLib/src/StormCommon.h
new file mode 100644
index 00000000000..9a85c4bd5ac
--- /dev/null
+++ b/dep/StormLib/src/StormCommon.h
@@ -0,0 +1,274 @@
+/*****************************************************************************/
+/* SCommon.h Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Common functions for encryption/decryption from Storm.dll. Included by */
+/* SFile*** functions, do not include and do not use this file directly */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 24.03.03 1.00 Lad The first version of SFileCommon.h */
+/* 12.06.04 1.00 Lad Renamed to SCommon.h */
+/* 06.09.10 1.00 Lad Renamed to StormCommon.h */
+/*****************************************************************************/
+
+#ifndef __STORMCOMMON_H__
+#define __STORMCOMMON_H__
+
+//-----------------------------------------------------------------------------
+// Compression support
+
+// Include functions from Pkware Data Compression Library
+#include "pklib/pklib.h"
+
+// Include functions from Huffmann compression
+#include "huffman/huff.h"
+
+// Include functions from IMA ADPCM compression
+#include "adpcm/adpcm.h"
+
+// Include functions from SPARSE compression
+#include "sparse/sparse.h"
+
+// Include functions from LZMA compression
+#include "lzma/C/LzmaEnc.h"
+#include "lzma/C/LzmaDec.h"
+
+// Include functions from zlib
+#ifndef __SYS_ZLIB
+ #include "zlib/zlib.h"
+#else
+ #include <zlib.h>
+#endif
+
+// Include functions from bzlib
+#ifndef __SYS_BZLIB
+ #include "bzip2/bzlib.h"
+#else
+ #include <bzlib.h>
+#endif
+
+//-----------------------------------------------------------------------------
+// Cryptography support
+
+// Headers from LibTomCrypt
+#include "libtomcrypt/src/headers/tomcrypt.h"
+
+// For HashStringJenkins
+#include "jenkins/lookup.h"
+
+//-----------------------------------------------------------------------------
+// StormLib private defines
+
+#define ID_MPQ_FILE 0x46494c45 // Used internally for checking TMPQFile ('FILE')
+
+#define MPQ_WEAK_SIGNATURE_SIZE 64
+#define MPQ_STRONG_SIGNATURE_SIZE 256
+
+// Prevent problems with CRT "min" and "max" functions,
+// as they are not defined on all platforms
+#define STORMLIB_MIN(a, b) ((a < b) ? a : b)
+#define STORMLIB_MAX(a, b) ((a > b) ? a : b)
+
+// Macro for building 64-bit file offset from two 32-bit
+#define MAKE_OFFSET64(hi, lo) (((ULONGLONG)hi << 32) | lo)
+
+//-----------------------------------------------------------------------------
+// Memory management
+//
+// We use our own macros for allocating/freeing memory. If you want
+// to redefine them, please keep the following rules
+//
+// - The memory allocation must return NULL if not enough memory
+// (i.e not to throw exception)
+// - It is not necessary to fill the allocated buffer with zeros
+// - Memory freeing function doesn't have to test the pointer to NULL.
+//
+
+#if defined(_MSC_VER) && defined(_DEBUG)
+__inline void * DebugMalloc(char * /* szFile */, int /* nLine */, size_t nSize)
+{
+// return new BYTE[nSize];
+ return HeapAlloc(GetProcessHeap(), 0, nSize);
+}
+
+__inline void DebugFree(void * ptr)
+{
+// delete [] ptr;
+ HeapFree(GetProcessHeap(), 0, ptr);
+}
+
+#define STORM_ALLOC(type, nitems) (type *)DebugMalloc(__FILE__, __LINE__, (nitems) * sizeof(type))
+#define STORM_FREE(ptr) DebugFree(ptr)
+#else
+
+#define STORM_ALLOC(type, nitems) (type *)malloc((nitems) * sizeof(type))
+#define STORM_FREE(ptr) free(ptr)
+
+#endif
+
+//-----------------------------------------------------------------------------
+// StormLib internal global variables
+
+extern LCID lcFileLocale; // Preferred file locale
+
+//-----------------------------------------------------------------------------
+// Encryption and decryption functions
+
+#define MPQ_HASH_TABLE_INDEX 0x000
+#define MPQ_HASH_NAME_A 0x100
+#define MPQ_HASH_NAME_B 0x200
+#define MPQ_HASH_FILE_KEY 0x300
+
+DWORD HashString(const char * szFileName, DWORD dwHashType);
+
+void InitializeMpqCryptography();
+
+DWORD GetHashTableSizeForFileCount(DWORD dwFileCount);
+
+bool IsPseudoFileName(const char * szFileName, LPDWORD pdwFileIndex);
+ULONGLONG HashStringJenkins(const char * szFileName);
+
+int ConvertMpqHeaderToFormat4(TMPQArchive * ha, ULONGLONG FileSize, DWORD dwFlags);
+
+DWORD GetDefaultSpecialFileFlags(TMPQArchive * ha, DWORD dwFileSize);
+
+void EncryptMpqBlock(void * pvFileBlock, DWORD dwLength, DWORD dwKey);
+void DecryptMpqBlock(void * pvFileBlock, DWORD dwLength, DWORD dwKey);
+
+DWORD DetectFileKeyBySectorSize(LPDWORD SectorOffsets, DWORD decrypted);
+DWORD DetectFileKeyByContent(void * pvFileContent, DWORD dwFileSize);
+DWORD DecryptFileKey(const char * szFileName, ULONGLONG MpqPos, DWORD dwFileSize, DWORD dwFlags);
+
+bool IsValidMD5(LPBYTE pbMd5);
+bool VerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5);
+void CalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash);
+
+//-----------------------------------------------------------------------------
+// Handle validation functions
+
+bool IsValidMpqHandle(TMPQArchive * ha);
+bool IsValidFileHandle(TMPQFile * hf);
+
+//-----------------------------------------------------------------------------
+// Hash table and block table manipulation
+
+TMPQHash * GetFirstHashEntry(TMPQArchive * ha, const char * szFileName);
+TMPQHash * GetNextHashEntry(TMPQArchive * ha, TMPQHash * pFirstHash, TMPQHash * pPrevHash);
+DWORD AllocateHashEntry(TMPQArchive * ha, TFileEntry * pFileEntry);
+DWORD AllocateHetEntry(TMPQArchive * ha, TFileEntry * pFileEntry);
+
+void FindFreeMpqSpace(TMPQArchive * ha, ULONGLONG * pFreeSpacePos);
+
+// Functions that loads and verifies MPQ data bitmap
+int LoadMpqDataBitmap(TMPQArchive * ha, ULONGLONG FileSize, bool * pbFileIsComplete);
+
+// Functions that load the HET and BET tables
+int CreateHashTable(TMPQArchive * ha, DWORD dwHashTableSize);
+int LoadAnyHashTable(TMPQArchive * ha);
+int BuildFileTable(TMPQArchive * ha, ULONGLONG FileSize);
+int SaveMPQTables(TMPQArchive * ha);
+
+TMPQHetTable * CreateHetTable(DWORD dwMaxFileCount, DWORD dwHashBitSize, bool bCreateEmpty);
+void FreeHetTable(TMPQHetTable * pHetTable);
+
+TMPQBetTable * CreateBetTable(DWORD dwMaxFileCount);
+void FreeBetTable(TMPQBetTable * pBetTable);
+
+// Functions for finding files in the file table
+TFileEntry * GetFileEntryAny(TMPQArchive * ha, const char * szFileName);
+TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale);
+TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcLocale);
+TFileEntry * GetFileEntryByIndex(TMPQArchive * ha, DWORD dwIndex);
+
+// Allocates file name in the file entry
+void AllocateFileName(TFileEntry * pFileEntry, const char * szFileName);
+
+// Allocates new file entry in the MPQ tables. Reuses existing, if possible
+TFileEntry * FindFreeFileEntry(TMPQArchive * ha);
+TFileEntry * AllocateFileEntry(TMPQArchive * ha, const char * szFileName, LCID lcLocale);
+int RenameFileEntry(TMPQArchive * ha, TFileEntry * pFileEntry, const char * szNewFileName);
+void ClearFileEntry(TMPQArchive * ha, TFileEntry * pFileEntry);
+int FreeFileEntry(TMPQArchive * ha, TFileEntry * pFileEntry);
+
+// Invalidates entries for (listfile) and (attributes)
+void InvalidateInternalFiles(TMPQArchive * ha);
+
+//-----------------------------------------------------------------------------
+// Common functions - MPQ File
+
+TMPQFile * CreateMpqFile(TMPQArchive * ha);
+int LoadMpqTable(TMPQArchive * ha, ULONGLONG ByteOffset, void * pvTable, DWORD dwCompressedSize, DWORD dwRealSize, DWORD dwKey);
+int AllocateSectorBuffer(TMPQFile * hf);
+int AllocatePatchInfo(TMPQFile * hf, bool bLoadFromFile);
+int AllocateSectorOffsets(TMPQFile * hf, bool bLoadFromFile);
+int AllocateSectorChecksums(TMPQFile * hf, bool bLoadFromFile);
+void CalculateRawSectorOffset(ULONGLONG & RawFilePos, TMPQFile * hf, DWORD dwSectorOffset);
+int WritePatchInfo(TMPQFile * hf);
+int WriteSectorOffsets(TMPQFile * hf);
+int WriteSectorChecksums(TMPQFile * hf);
+int WriteMemDataMD5(TFileStream * pStream, ULONGLONG RawDataOffs, void * pvRawData, DWORD dwRawDataSize, DWORD dwChunkSize, LPDWORD pcbTotalSize);
+int WriteMpqDataMD5(TFileStream * pStream, ULONGLONG RawDataOffs, DWORD dwRawDataSize, DWORD dwChunkSize);
+void FreeMPQFile(TMPQFile *& hf);
+
+bool IsIncrementalPatchFile(const void * pvData, DWORD cbData, LPDWORD pdwPatchedFileSize);
+int PatchFileData(TMPQFile * hf);
+
+void FreeMPQArchive(TMPQArchive *& ha);
+
+//-----------------------------------------------------------------------------
+// Utility functions
+
+bool CheckWildCard(const char * szString, const char * szWildCard);
+const char * GetPlainFileNameA(const char * szFileName);
+const TCHAR * GetPlainFileNameT(const TCHAR * szFileName);
+bool IsInternalMpqFileName(const char * szFileName);
+
+//-----------------------------------------------------------------------------
+// Support for adding files to the MPQ
+
+int SFileAddFile_Init(
+ TMPQArchive * ha,
+ const char * szArchivedName,
+ ULONGLONG ft,
+ DWORD dwFileSize,
+ LCID lcLocale,
+ DWORD dwFlags,
+ TMPQFile ** phf
+ );
+
+int SFileAddFile_Write(
+ TMPQFile * hf,
+ const void * pvData,
+ DWORD dwSize,
+ DWORD dwCompression
+ );
+
+int SFileAddFile_Finish(
+ TMPQFile * hf
+ );
+
+//-----------------------------------------------------------------------------
+// Attributes support
+
+int SAttrLoadAttributes(TMPQArchive * ha);
+int SAttrFileSaveToMpq(TMPQArchive * ha);
+
+//-----------------------------------------------------------------------------
+// Listfile functions
+
+int SListFileSaveToMpq(TMPQArchive * ha);
+
+//-----------------------------------------------------------------------------
+// Dump data support
+
+#ifdef __STORMLIB_DUMP_DATA__
+void DumpMpqHeader(TMPQHeader * pHeader);
+void DumpHetAndBetTable(TMPQHetTable * pHetTable, TMPQBetTable * pBetTable);
+
+#else
+#define DumpMpqHeader(h) /* */
+#define DumpHetAndBetTable(h, b) /* */
+#endif
+
+#endif // __STORMCOMMON_H__
+
diff --git a/dep/StormLib/src/StormLib.h b/dep/StormLib/src/StormLib.h
new file mode 100644
index 00000000000..a07ae46ca48
--- /dev/null
+++ b/dep/StormLib/src/StormLib.h
@@ -0,0 +1,984 @@
+/*****************************************************************************/
+/* StormLib.h Copyright (c) Ladislav Zezula 1999-2010 */
+/*---------------------------------------------------------------------------*/
+/* StormLib library v 7.02 */
+/* */
+/* Author : Ladislav Zezula */
+/* E-mail : ladik@zezula.net */
+/* WWW : http://www.zezula.net */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* xx.xx.99 1.00 Lad Created */
+/* 24.03.03 2.50 Lad Version 2.50 */
+/* 02.04.03 3.00 Lad Version 3.00 with compression */
+/* 11.04.03 3.01 Lad Renamed to StormLib.h for compatibility with */
+/* original headers for Storm.dll */
+/* 10.05.03 3.02 Lad Added Pkware DCL compression */
+/* 26.05.03 4.00 Lad Completed all compressions */
+/* 18.06.03 4.01 Lad Added SFileSetFileLocale */
+/* Added SFileExtractFile */
+/* 26.07.03 4.02 Lad Implemented nameless rename and delete */
+/* 26.07.03 4.03 Lad Added support for protected MPQs */
+/* 28.08.03 4.10 Lad Fixed bugs that caused StormLib incorrectly work */
+/* with Diablo I savegames and with files having full */
+/* hash table */
+/* 08.12.03 4.11 DCH Fixed bug in reading file sector larger than 0x1000 */
+/* on certain files. */
+/* Fixed bug in AddFile with MPQ_FILE_REPLACE_EXISTING */
+/* (Thanx Daniel Chiamarello, dchiamarello@madvawes.com)*/
+/* 21.12.03 4.50 Lad Completed port for Mac */
+/* Fixed bug in compacting (if fsize is mul of 0x1000) */
+/* Fixed bug in SCompCompress */
+/* 27.05.04 4.51 Lad Changed memory management from new/delete to our */
+/* own macros */
+/* 22.06.04 4.60 Lad Optimized search. Support for multiple listfiles. */
+/* 30.09.04 4.61 Lad Fixed some bugs (Aaargh !!!) */
+/* Correctly works if HashTableSize > BlockTableSize */
+/* 29.12.04 4.70 Lad Fixed compatibility problem with MPQs from WoW */
+/* 14.07.05 5.00 Lad Added the BZLIB compression support */
+/* Added suport of files stored as single unit */
+/* 17.04.06 5.01 Lad Converted to MS Visual Studio 8.0 */
+/* Fixed issue with protected Warcraft 3 protected maps */
+/* 15.05.06 5.02 Lad Fixed issue with WoW 1.10+ */
+/* 07.09.06 5.10 Lad Fixed processing files longer than 2GB */
+/* 22.11.06 6.00 Lad Support for MPQ archives V2 */
+/* 12.06.07 6.10 Lad Support for (attributes) file */
+/* 10.09.07 6.12 Lad Support for MPQs protected by corrupting hash table */
+/* 03.12.07 6.13 Lad Support for MPQs with hash tbl size > block tbl size */
+/* 07.04.08 6.20 Lad Added SFileFlushArchive */
+/* 09.04.08 Lad Removed FilePointer variable from MPQ handle */
+/* structure, as it caused more problems than benefits */
+/* 12.05.08 6.22 Lad Support for w3xMaster map protector */
+/* 05.10.08 6.23 Lad Support for protectors who set negative values in */
+/* the table of file blocks */
+/* 26.05.09 6.24 Lad Fixed search for multiple lang files with deleted */
+/* entries */
+/* 03.09.09 6.25 Lad Fixed decompression bug in huffmann decompression */
+/* 22.03.10 6.50 Lad New compressions in Starcraft II (LZMA, sparse) */
+/* Fixed compacting MPQs that contain single unit files */
+/* 26.04.10 7.00 Lad Major rewrite */
+/* 08.06.10 7.10 Lad Support for partial MPQs */
+/* 08.07.10 7.11 Lad Support for MPQs v 3.0 */
+/* 20.08.10 7.20 Lad Support for opening multiple MPQs in patch mode */
+/* 20.09.10 8.00 Lad MPQs v 4, HET and BET tables */
+/* 07.01.11 8.01 Lad Write support for MPQs v 3 and 4 */
+/* 15.09.11 8.04 Lad Bug fixes, testing for Diablo III MPQs */
+/* 26.04.12 8.10 Lad Support for data map, added SFileGetArchiveBitmap */
+/*****************************************************************************/
+
+#ifndef __STORMLIB_H__
+#define __STORMLIB_H__
+
+#ifdef _MSC_VER
+#pragma warning(disable:4668) // 'XXX' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
+#pragma warning(disable:4820) // 'XXX' : '2' bytes padding added after data member 'XXX::yyy'
+#endif
+
+#include "StormPort.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//-----------------------------------------------------------------------------
+// Use the apropriate library
+//
+// The library type is encoded in the library name as the following
+// StormLibXYZ.lib
+//
+// X - D for Debug version, R for Release version
+// Y - A for ANSI version, U for Unicode version
+// Z - S for static-linked CRT library, D for multithreaded DLL CRT library
+//
+
+#if 0 && defined(_MSC_VER) && !defined(__STORMLIB_SELF__)
+
+ #ifdef _DEBUG // DEBUG VERSIONS
+ #ifndef _UNICODE
+ #ifdef _DLL
+ #pragma comment(lib, "StormLibDAD.lib") // Debug Ansi CRT-DLL version
+ #else
+ #pragma comment(lib, "StormLibDAS.lib") // Debug Ansi CRT-LIB version
+ #endif
+ #else
+ #ifdef _DLL
+ #pragma comment(lib, "StormLibDUD.lib") // Debug Unicode CRT-DLL version
+ #else
+ #pragma comment(lib, "StormLibDUS.lib") // Debug Unicode CRT-LIB version
+ #endif
+ #endif
+ #else // RELEASE VERSIONS
+ #ifndef _UNICODE
+ #ifdef _DLL
+ #pragma comment(lib, "StormLibRAD.lib") // Release Ansi CRT-DLL version
+ #else
+ #pragma comment(lib, "StormLibRAS.lib") // Release Ansi CRT-LIB version
+ #endif
+ #else
+ #ifdef _DLL
+ #pragma comment(lib, "StormLibRUD.lib") // Release Unicode CRT-DLL version
+ #else
+ #pragma comment(lib, "StormLibRUS.lib") // Release Unicode CRT-LIB version
+ #endif
+ #endif
+ #endif
+
+#endif
+
+//-----------------------------------------------------------------------------
+// Defines
+
+#define ID_MPQ 0x1A51504D // MPQ archive header ID ('MPQ\x1A')
+#define ID_MPQ_USERDATA 0x1B51504D // MPQ userdata entry ('MPQ\x1B')
+
+#define ERROR_AVI_FILE 10000 // No MPQ file, but AVI file.
+#define ERROR_UNKNOWN_FILE_KEY 10001 // Returned by SFileReadFile when can't find file key
+#define ERROR_CHECKSUM_ERROR 10002 // Returned by SFileReadFile when sector CRC doesn't match
+#define ERROR_INTERNAL_FILE 10003 // The given operation is not allowed on internal file
+#define ERROR_BASE_FILE_MISSING 10004 // The file is present as incremental patch file, but base file is missing
+#define ERROR_MARKED_FOR_DELETE 10005 // The file was marked as "deleted" in the MPQ
+
+// Values for SFileCreateArchive
+#define HASH_TABLE_SIZE_MIN 0x00000004 // Minimum acceptable hash table size
+#define HASH_TABLE_SIZE_DEFAULT 0x00001000 // Default hash table size for empty MPQs
+#define HASH_TABLE_SIZE_MAX 0x00080000 // Maximum acceptable hash table size
+
+#define HASH_ENTRY_DELETED 0xFFFFFFFE // Block index for deleted entry in the hash table
+#define HASH_ENTRY_FREE 0xFFFFFFFF // Block index for free entry in the hash table
+
+#define HET_ENTRY_DELETED 0x80 // HET hash value for a deleted entry
+#define HET_ENTRY_FREE 0x00 // HET hash value for free entry
+
+#define HASH_STATE_SIZE 0x60 // Size of LibTomCrypt's hash_state structure
+
+#define MPQ_PATCH_PREFIX_LEN 0x20 // Maximum length of the patch prefix
+
+// Values for SFileOpenArchive
+#define SFILE_OPEN_HARD_DISK_FILE 2 // Open the archive on HDD
+#define SFILE_OPEN_CDROM_FILE 3 // Open the archive only if it is on CDROM
+
+// Values for SFileOpenFile
+#define SFILE_OPEN_FROM_MPQ 0x00000000 // Open the file from the MPQ archive
+#define SFILE_OPEN_PATCHED_FILE 0x00000001 // Open the file from the MPQ archive
+#define SFILE_OPEN_ANY_LOCALE 0xFFFFFFFE // Reserved for StormLib internal use
+#define SFILE_OPEN_LOCAL_FILE 0xFFFFFFFF // Open a local file
+
+// Flags for TMPQArchive::dwFlags
+#define MPQ_FLAG_READ_ONLY 0x00000001 // If set, the MPQ has been open for read-only access
+#define MPQ_FLAG_CHANGED 0x00000002 // If set, the MPQ tables have been changed
+#define MPQ_FLAG_PROTECTED 0x00000004 // Set on protected MPQs (like W3M maps)
+#define MPQ_FLAG_CHECK_SECTOR_CRC 0x00000008 // Checking sector CRC when reading files
+#define MPQ_FLAG_NEED_FIX_SIZE 0x00000010 // Used during opening the archive
+#define MPQ_FLAG_INV_LISTFILE 0x00000020 // If set, it means that the (listfile) has been invalidated
+#define MPQ_FLAG_INV_ATTRIBUTES 0x00000040 // If set, it means that the (attributes) has been invalidated
+
+// Return value for SFileGetFileSize and SFileSetFilePointer
+#define SFILE_INVALID_SIZE 0xFFFFFFFF
+#define SFILE_INVALID_POS 0xFFFFFFFF
+#define SFILE_INVALID_ATTRIBUTES 0xFFFFFFFF
+
+// Flags for SFileAddFile
+#define MPQ_FILE_IMPLODE 0x00000100 // Implode method (By PKWARE Data Compression Library)
+#define MPQ_FILE_COMPRESS 0x00000200 // Compress methods (By multiple methods)
+#define MPQ_FILE_COMPRESSED 0x0000FF00 // File is compressed
+#define MPQ_FILE_ENCRYPTED 0x00010000 // Indicates whether file is encrypted
+#define MPQ_FILE_FIX_KEY 0x00020000 // File decryption key has to be fixed
+#define MPQ_FILE_PATCH_FILE 0x00100000 // The file is a patch file. Raw file data begin with TPatchInfo structure
+#define MPQ_FILE_SINGLE_UNIT 0x01000000 // File is stored as a single unit, rather than split into sectors (Thx, Quantam)
+#define MPQ_FILE_DELETE_MARKER 0x02000000 // File is a deletion marker. Used in MPQ patches, indicating that the file no longer exists.
+#define MPQ_FILE_SECTOR_CRC 0x04000000 // File has checksums for each sector.
+ // Ignored if file is not compressed or imploded.
+#define MPQ_FILE_EXISTS 0x80000000 // Set if file exists, reset when the file was deleted
+#define MPQ_FILE_REPLACEEXISTING 0x80000000 // Replace when the file exist (SFileAddFile)
+
+#define MPQ_FILE_VALID_FLAGS (MPQ_FILE_IMPLODE | \
+ MPQ_FILE_COMPRESS | \
+ MPQ_FILE_ENCRYPTED | \
+ MPQ_FILE_FIX_KEY | \
+ MPQ_FILE_PATCH_FILE | \
+ MPQ_FILE_SINGLE_UNIT | \
+ MPQ_FILE_DELETE_MARKER | \
+ MPQ_FILE_SECTOR_CRC | \
+ MPQ_FILE_EXISTS)
+
+// Compression types for multiple compressions
+#define MPQ_COMPRESSION_HUFFMANN 0x01 // Huffmann compression (used on WAVE files only)
+#define MPQ_COMPRESSION_ZLIB 0x02 // ZLIB compression
+#define MPQ_COMPRESSION_PKWARE 0x08 // PKWARE DCL compression
+#define MPQ_COMPRESSION_BZIP2 0x10 // BZIP2 compression (added in Warcraft III)
+#define MPQ_COMPRESSION_SPARSE 0x20 // Sparse compression (added in Starcraft 2)
+#define MPQ_COMPRESSION_ADPCM_MONO 0x40 // IMA ADPCM compression (mono)
+#define MPQ_COMPRESSION_ADPCM_STEREO 0x80 // IMA ADPCM compression (stereo)
+#define MPQ_COMPRESSION_LZMA 0x12 // LZMA compression. Added in Starcraft 2. This value is NOT a combination of flags.
+#define MPQ_COMPRESSION_NEXT_SAME 0xFFFFFFFF // Same compression
+
+// Constants for SFileAddWave
+#define MPQ_WAVE_QUALITY_HIGH 0 // Best quality, the worst compression
+#define MPQ_WAVE_QUALITY_MEDIUM 1 // Medium quality, medium compression
+#define MPQ_WAVE_QUALITY_LOW 2 // Low quality, the best compression
+
+// Signatures for HET and BET table
+#define HET_TABLE_SIGNATURE 0x1A544548 // 'HET\x1a'
+#define BET_TABLE_SIGNATURE 0x1A544542 // 'BET\x1a'
+
+// Decryption keys for MPQ tables
+#define MPQ_KEY_HASH_TABLE 0xC3AF3770 // Obtained by HashString("(hash table)", MPQ_HASH_FILE_KEY)
+#define MPQ_KEY_BLOCK_TABLE 0xEC83B3A3 // Obtained by HashString("(block table)", MPQ_HASH_FILE_KEY)
+
+// Block map defines
+#define MPQ_DATA_BITMAP_SIGNATURE 0x33767470 // Signature of the MPQ data bitmap ('ptv3')
+
+// Constants for SFileGetFileInfo
+#define SFILE_INFO_ARCHIVE_NAME 1 // MPQ size (value from header)
+#define SFILE_INFO_ARCHIVE_SIZE 2 // MPQ size (value from header)
+#define SFILE_INFO_MAX_FILE_COUNT 3 // Max number of files in the MPQ
+#define SFILE_INFO_HASH_TABLE_SIZE 4 // Size of hash table, in entries
+#define SFILE_INFO_BLOCK_TABLE_SIZE 5 // Number of entries in the block table
+#define SFILE_INFO_SECTOR_SIZE 6 // Size of file sector (in bytes)
+#define SFILE_INFO_HASH_TABLE 7 // Pointer to Hash table (TMPQHash *)
+#define SFILE_INFO_BLOCK_TABLE 8 // Pointer to Block Table (TMPQBlock *)
+#define SFILE_INFO_NUM_FILES 9 // Real number of files within archive
+#define SFILE_INFO_STREAM_FLAGS 10 // Stream flags for the MPQ. See STREAM_FLAG_XXX
+#define SFILE_INFO_IS_READ_ONLY 11 // TRUE of the MPQ was open as read only
+//------
+#define SFILE_INFO_HASH_INDEX 100 // Hash index of file in MPQ
+#define SFILE_INFO_CODENAME1 101 // The first codename of the file
+#define SFILE_INFO_CODENAME2 102 // The second codename of the file
+#define SFILE_INFO_LOCALEID 103 // Locale ID of file in MPQ
+#define SFILE_INFO_BLOCKINDEX 104 // Index to Block Table
+#define SFILE_INFO_FILE_SIZE 105 // Original file size (from the block table)
+#define SFILE_INFO_COMPRESSED_SIZE 106 // Compressed file size (from the block table)
+#define SFILE_INFO_FLAGS 107 // File flags
+#define SFILE_INFO_POSITION 108 // File position within archive
+#define SFILE_INFO_KEY 109 // File decryption key
+#define SFILE_INFO_KEY_UNFIXED 110 // Decryption key not fixed to file pos and size
+#define SFILE_INFO_FILETIME 111 // TMPQFileTime
+#define SFILE_INFO_PATCH_CHAIN 112 // Chain of patches
+
+#define LISTFILE_NAME "(listfile)" // Name of internal listfile
+#define SIGNATURE_NAME "(signature)" // Name of internal signature
+#define ATTRIBUTES_NAME "(attributes)" // Name of internal attributes file
+#define PATCH_METADATA_NAME "(patch_metadata)"
+
+#define STORMLIB_VERSION 0x080A // Current version of StormLib (8.10)
+#define STORMLIB_VERSION_STRING "8.10"
+
+#define MPQ_FORMAT_VERSION_1 0 // Up to The Burning Crusade
+#define MPQ_FORMAT_VERSION_2 1 // The Burning Crusade and newer
+#define MPQ_FORMAT_VERSION_3 2 // WoW Cataclysm Beta
+#define MPQ_FORMAT_VERSION_4 3 // WoW Cataclysm and newer
+
+// Flags for MPQ attributes
+#define MPQ_ATTRIBUTE_CRC32 0x00000001 // The "(attributes)" contains CRC32 for each file
+#define MPQ_ATTRIBUTE_FILETIME 0x00000002 // The "(attributes)" contains file time for each file
+#define MPQ_ATTRIBUTE_MD5 0x00000004 // The "(attributes)" contains MD5 for each file
+#define MPQ_ATTRIBUTE_PATCH_BIT 0x00000008 // The "(attributes)" contains a patch bit for each file
+#define MPQ_ATTRIBUTE_ALL 0x0000000F // Summary mask
+
+#define MPQ_ATTRIBUTES_V1 100 // (attributes) format version 1.00
+
+// Flags for SFileOpenArchive
+#define BASE_PROVIDER_FILE 0x00000000 // Base data source is a file
+#define BASE_PROVIDER_MAP 0x00000001 // Base data source is memory-mapped file
+#define BASE_PROVIDER_HTTP 0x00000002 // Base data source is a file on web server
+#define BASE_PROVIDER_MASK 0x0000000F // Mask for base provider value
+
+#define STREAM_PROVIDER_LINEAR 0x00000000 // Stream is linear with no offset mapping
+#define STREAM_PROVIDER_PARTIAL 0x00000010 // Stream is partial file (.part)
+#define STREAM_PROVIDER_ENCRYPTED 0x00000020 // Stream is an encrypted MPQ
+#define STREAM_PROVIDER_MASK 0x000000F0 // Mask for stream provider value
+
+#define STREAM_FLAG_READ_ONLY 0x00000100 // Stream is read only
+#define STREAM_FLAG_WRITE_SHARE 0x00000200 // Allow write sharing when open for write
+#define STREAM_FLAG_MASK 0x0000FF00 // Mask for stream flags
+#define STREAM_OPTIONS_MASK 0x0000FFFF // Mask for all stream options
+
+#define MPQ_OPEN_NO_LISTFILE 0x00010000 // Don't load the internal listfile
+#define MPQ_OPEN_NO_ATTRIBUTES 0x00020000 // Don't open the attributes
+#define MPQ_OPEN_FORCE_MPQ_V1 0x00040000 // Always open the archive as MPQ v 1.00, ignore the "wFormatVersion" variable in the header
+#define MPQ_OPEN_CHECK_SECTOR_CRC 0x00080000 // On files with MPQ_FILE_SECTOR_CRC, the CRC will be checked when reading file
+
+// Deprecated
+#define MPQ_OPEN_READ_ONLY STREAM_FLAG_READ_ONLY
+#define MPQ_OPEN_ENCRYPTED STREAM_PROVIDER_ENCRYPTED
+
+// Flags for SFileCreateArchive
+#define MPQ_CREATE_ATTRIBUTES 0x00100000 // Also add the (attributes) file
+#define MPQ_CREATE_ARCHIVE_V1 0x00000000 // Creates archive of version 1 (size up to 4GB)
+#define MPQ_CREATE_ARCHIVE_V2 0x01000000 // Creates archive of version 2 (larger than 4 GB)
+#define MPQ_CREATE_ARCHIVE_V3 0x02000000 // Creates archive of version 3
+#define MPQ_CREATE_ARCHIVE_V4 0x03000000 // Creates archive of version 4
+#define MPQ_CREATE_ARCHIVE_VMASK 0x0F000000 // Mask for archive version
+
+#define FLAGS_TO_FORMAT_SHIFT 24 // (MPQ_CREATE_ARCHIVE_V4 >> FLAGS_TO_FORMAT_SHIFT) => MPQ_FORMAT_VERSION_4
+
+// Flags for SFileVerifyFile
+#define SFILE_VERIFY_SECTOR_CRC 0x00000001 // Verify sector checksum for the file, if available
+#define SFILE_VERIFY_FILE_CRC 0x00000002 // Verify file CRC, if available
+#define SFILE_VERIFY_FILE_MD5 0x00000004 // Verify file MD5, if available
+#define SFILE_VERIFY_RAW_MD5 0x00000008 // Verify raw file MD5, if available
+#define SFILE_VERIFY_ALL 0x0000000F // Verify every checksum possible
+
+// Return values for SFileVerifyFile
+#define VERIFY_OPEN_ERROR 0x0001 // Failed to open the file
+#define VERIFY_READ_ERROR 0x0002 // Failed to read all data from the file
+#define VERIFY_FILE_HAS_SECTOR_CRC 0x0004 // File has sector CRC
+#define VERIFY_FILE_SECTOR_CRC_ERROR 0x0008 // Sector CRC check failed
+#define VERIFY_FILE_HAS_CHECKSUM 0x0010 // File has CRC32
+#define VERIFY_FILE_CHECKSUM_ERROR 0x0020 // CRC32 check failed
+#define VERIFY_FILE_HAS_MD5 0x0040 // File has data MD5
+#define VERIFY_FILE_MD5_ERROR 0x0080 // MD5 check failed
+#define VERIFY_FILE_HAS_RAW_MD5 0x0100 // File has raw data MD5
+#define VERIFY_FILE_RAW_MD5_ERROR 0x0200 // Raw MD5 check failed
+#define VERIFY_FILE_ERROR_MASK (VERIFY_OPEN_ERROR | VERIFY_READ_ERROR | VERIFY_FILE_SECTOR_CRC_ERROR | VERIFY_FILE_CHECKSUM_ERROR | VERIFY_FILE_MD5_ERROR | VERIFY_FILE_RAW_MD5_ERROR)
+
+// Flags for SFileVerifyRawData (for MPQs version 4.0 or higher)
+#define SFILE_VERIFY_MPQ_HEADER 0x0001 // Verify raw MPQ header
+#define SFILE_VERIFY_HET_TABLE 0x0002 // Verify raw data of the HET table
+#define SFILE_VERIFY_BET_TABLE 0x0003 // Verify raw data of the BET table
+#define SFILE_VERIFY_HASH_TABLE 0x0004 // Verify raw data of the hash table
+#define SFILE_VERIFY_BLOCK_TABLE 0x0005 // Verify raw data of the block table
+#define SFILE_VERIFY_HIBLOCK_TABLE 0x0006 // Verify raw data of the hi-block table
+#define SFILE_VERIFY_FILE 0x0007 // Verify raw data of a file
+
+// Return values for SFileVerifyArchive
+#define ERROR_NO_SIGNATURE 0 // There is no signature in the MPQ
+#define ERROR_VERIFY_FAILED 1 // There was an error during verifying signature (like no memory)
+#define ERROR_WEAK_SIGNATURE_OK 2 // There is a weak signature and sign check passed
+#define ERROR_WEAK_SIGNATURE_ERROR 3 // There is a weak signature but sign check failed
+#define ERROR_STRONG_SIGNATURE_OK 4 // There is a strong signature and sign check passed
+#define ERROR_STRONG_SIGNATURE_ERROR 5 // There is a strong signature but sign check failed
+
+#ifndef MD5_DIGEST_SIZE
+#define MD5_DIGEST_SIZE 0x10
+#endif
+
+#ifndef SHA1_DIGEST_SIZE
+#define SHA1_DIGEST_SIZE 0x14 // 160 bits
+#endif
+
+#ifndef LANG_NEUTRAL
+#define LANG_NEUTRAL 0x00 // Neutral locale
+#endif
+
+//-----------------------------------------------------------------------------
+// Callback functions
+
+// Values for compact callback
+#define CCB_CHECKING_FILES 1 // Checking archive (dwParam1 = current, dwParam2 = total)
+#define CCB_CHECKING_HASH_TABLE 2 // Checking hash table (dwParam1 = current, dwParam2 = total)
+#define CCB_COPYING_NON_MPQ_DATA 3 // Copying non-MPQ data: No params used
+#define CCB_COMPACTING_FILES 4 // Compacting archive (dwParam1 = current, dwParam2 = total)
+#define CCB_CLOSING_ARCHIVE 5 // Closing archive: No params used
+
+typedef void (WINAPI * SFILE_ADDFILE_CALLBACK)(void * pvUserData, DWORD dwBytesWritten, DWORD dwTotalBytes, bool bFinalCall);
+typedef void (WINAPI * SFILE_COMPACT_CALLBACK)(void * pvUserData, DWORD dwWorkType, ULONGLONG BytesProcessed, ULONGLONG TotalBytes);
+
+struct TFileStream;
+
+//-----------------------------------------------------------------------------
+// Structure for bit arrays used for HET and BET tables
+
+struct TBitArray
+{
+ void GetBits(unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, int nResultSize);
+ void SetBits(unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, int nResultSize);
+
+ DWORD NumberOfBits; // Total number of bits that are available
+ BYTE Elements[1]; // Array of elements (variable length)
+};
+
+// Structure for file bitmap. Used by SFileGetArchiveBitmap
+struct TFileBitmap
+{
+ ULONGLONG StartOffset; // Starting offset of the file, covered by bitmap
+ ULONGLONG EndOffset; // Ending offset of the file, covered by bitmap
+ DWORD IsComplete; // If nonzero, no blocks are missing
+ DWORD BitmapSize; // Size of the file bitmap (in bytes)
+ DWORD BlockSize; // Size of one block, in bytes
+ DWORD Reserved; // Alignment
+
+ // Followed by file bitmap (variable length), array of BYTEs)
+};
+
+//-----------------------------------------------------------------------------
+// Structures related to MPQ format
+//
+// Note: All structures in this header file are supposed to remain private
+// to StormLib. The structures may (and will) change over time, as the MPQ
+// file format evolves. Programmers directly using these structures need to
+// be aware of this. And the last, but not least, NEVER do any modifications
+// to those structures directly, always use SFile* functions.
+//
+
+#define MPQ_HEADER_SIZE_V1 0x20
+#define MPQ_HEADER_SIZE_V2 0x2C
+#define MPQ_HEADER_SIZE_V3 0x44
+#define MPQ_HEADER_SIZE_V4 0xD0
+
+struct TMPQUserData
+{
+ // The ID_MPQ_USERDATA ('MPQ\x1B') signature
+ DWORD dwID;
+
+ // Maximum size of the user data
+ DWORD cbUserDataSize;
+
+ // Offset of the MPQ header, relative to the begin of this header
+ DWORD dwHeaderOffs;
+
+ // Appears to be size of user data header (Starcraft II maps)
+ DWORD cbUserDataHeader;
+};
+
+// MPQ file header
+//
+// We have to make sure that the header is packed OK.
+// Reason: A 64-bit integer at the beginning of 3.0 part,
+// which is offset 0x2C
+#pragma pack(push, 1)
+struct TMPQHeader
+{
+ // The ID_MPQ ('MPQ\x1A') signature
+ DWORD dwID;
+
+ // Size of the archive header
+ DWORD dwHeaderSize;
+
+ // 32-bit size of MPQ archive
+ // This field is deprecated in the Burning Crusade MoPaQ format, and the size of the archive
+ // is calculated as the size from the beginning of the archive to the end of the hash table,
+ // block table, or hi-block table (whichever is largest).
+ DWORD dwArchiveSize;
+
+ // 0 = Format 1 (up to The Burning Crusade)
+ // 1 = Format 2 (The Burning Crusade and newer)
+ // 2 = Format 3 (WoW - Cataclysm beta or newer)
+ // 3 = Format 4 (WoW - Cataclysm beta or newer)
+ USHORT wFormatVersion;
+
+ // Power of two exponent specifying the number of 512-byte disk sectors in each file sector
+ // in the archive. The size of each file sector in the archive is 512 * 2 ^ wSectorSize.
+ USHORT wSectorSize;
+
+ // Offset to the beginning of the hash table, relative to the beginning of the archive.
+ DWORD dwHashTablePos;
+
+ // Offset to the beginning of the block table, relative to the beginning of the archive.
+ DWORD dwBlockTablePos;
+
+ // Number of entries in the hash table. Must be a power of two, and must be less than 2^16 for
+ // the original MoPaQ format, or less than 2^20 for the Burning Crusade format.
+ DWORD dwHashTableSize;
+
+ // Number of entries in the block table
+ DWORD dwBlockTableSize;
+
+ //-- MPQ HEADER v 2 -------------------------------------------
+
+ // Offset to the beginning of array of 16-bit high parts of file offsets.
+ ULONGLONG HiBlockTablePos64;
+
+ // High 16 bits of the hash table offset for large archives.
+ USHORT wHashTablePosHi;
+
+ // High 16 bits of the block table offset for large archives.
+ USHORT wBlockTablePosHi;
+
+ //-- MPQ HEADER v 3 -------------------------------------------
+
+ // 64-bit version of the archive size
+ ULONGLONG ArchiveSize64;
+
+ // 64-bit position of the BET table
+ ULONGLONG BetTablePos64;
+
+ // 64-bit position of the HET table
+ ULONGLONG HetTablePos64;
+
+ //-- MPQ HEADER v 4 -------------------------------------------
+
+ // Compressed size of the hash table
+ ULONGLONG HashTableSize64;
+
+ // Compressed size of the block table
+ ULONGLONG BlockTableSize64;
+
+ // Compressed size of the hi-block table
+ ULONGLONG HiBlockTableSize64;
+
+ // Compressed size of the HET block
+ ULONGLONG HetTableSize64;
+
+ // Compressed size of the BET block
+ ULONGLONG BetTableSize64;
+
+ // Size of raw data chunk to calculate MD5.
+ // MD5 of each data chunk follows the raw file data.
+ DWORD dwRawChunkSize;
+
+ // MD5 of MPQ tables
+ unsigned char MD5_BlockTable[MD5_DIGEST_SIZE]; // MD5 of the block table before decryption
+ unsigned char MD5_HashTable[MD5_DIGEST_SIZE]; // MD5 of the hash table before decryption
+ unsigned char MD5_HiBlockTable[MD5_DIGEST_SIZE]; // MD5 of the hi-block table
+ unsigned char MD5_BetTable[MD5_DIGEST_SIZE]; // MD5 of the BET table before decryption
+ unsigned char MD5_HetTable[MD5_DIGEST_SIZE]; // MD5 of the HET table before decryption
+ unsigned char MD5_MpqHeader[MD5_DIGEST_SIZE]; // MD5 of the MPQ header from signature to (including) MD5_HetTable
+};
+#pragma pack(pop)
+
+
+// Hash entry. All files in the archive are searched by their hashes.
+struct TMPQHash
+{
+ // The hash of the file path, using method A.
+ DWORD dwName1;
+
+ // The hash of the file path, using method B.
+ DWORD dwName2;
+
+#ifdef PLATFORM_LITTLE_ENDIAN
+
+ // The language of the file. This is a Windows LANGID data type, and uses the same values.
+ // 0 indicates the default language (American English), or that the file is language-neutral.
+ USHORT lcLocale;
+
+ // The platform the file is used for. 0 indicates the default platform.
+ // No other values have been observed.
+ // Note: wPlatform is actually just BYTE, but since it has never been used, we don't care.
+ USHORT wPlatform;
+
+#else
+
+ USHORT wPlatform;
+ USHORT lcLocale;
+
+#endif
+
+ // If the hash table entry is valid, this is the index into the block table of the file.
+ // Otherwise, one of the following two values:
+ // - FFFFFFFFh: Hash table entry is empty, and has always been empty.
+ // Terminates searches for a given file.
+ // - FFFFFFFEh: Hash table entry is empty, but was valid at some point (a deleted file).
+ // Does not terminate searches for a given file.
+ DWORD dwBlockIndex;
+};
+
+
+// File description block contains informations about the file
+struct TMPQBlock
+{
+ // Offset of the beginning of the file, relative to the beginning of the archive.
+ DWORD dwFilePos;
+
+ // Compressed file size
+ DWORD dwCSize;
+
+ // Only valid if the block is a file; otherwise meaningless, and should be 0.
+ // If the file is compressed, this is the size of the uncompressed file data.
+ DWORD dwFSize;
+
+ // Flags for the file. See MPQ_FILE_XXXX constants
+ DWORD dwFlags;
+};
+
+// Patch file information, preceding the sector offset table
+struct TPatchInfo
+{
+ DWORD dwLength; // Length of patch info header, in bytes
+ DWORD dwFlags; // Flags. 0x80000000 = MD5 (?)
+ DWORD dwDataSize; // Uncompressed size of the patch file
+ BYTE md5[0x10]; // MD5 of the entire patch file after decompression
+
+ // Followed by the sector table (variable length)
+};
+
+// Header for PTCH files
+struct TPatchHeader
+{
+ //-- PATCH header -----------------------------------
+ DWORD dwSignature; // 'PTCH'
+ DWORD dwSizeOfPatchData; // Size of the entire patch (decompressed)
+ DWORD dwSizeBeforePatch; // Size of the file before patch
+ DWORD dwSizeAfterPatch; // Size of file after patch
+
+ //-- MD5 block --------------------------------------
+ DWORD dwMD5; // 'MD5_'
+ DWORD dwMd5BlockSize; // Size of the MD5 block, including the signature and size itself
+ BYTE md5_before_patch[0x10]; // MD5 of the original (unpached) file
+ BYTE md5_after_patch[0x10]; // MD5 of the patched file
+
+ //-- XFRM block -------------------------------------
+ DWORD dwXFRM; // 'XFRM'
+ DWORD dwXfrmBlockSize; // Size of the XFRM block, includes XFRM header and patch data
+ DWORD dwPatchType; // Type of patch ('BSD0' or 'COPY')
+
+ // Followed by the patch data
+};
+
+#define SIZE_OF_XFRM_HEADER 0x0C
+
+// This is the combined file entry for maintaining file list in the MPQ.
+// This structure is combined from block table, hi-block table,
+// (attributes) file and from (listfile).
+struct TFileEntry
+{
+ ULONGLONG ByteOffset; // Position of the file content in the MPQ, relative to the MPQ header
+ ULONGLONG FileTime; // FileTime from the (attributes) file. 0 if not present.
+ ULONGLONG BetHash; // Lower part of the file name hash. Only used when the MPQ has BET table.
+ DWORD dwHashIndex; // Index to the hash table. Only used when the MPQ has classic hash table
+ DWORD dwHetIndex; // Index to the HET table. Only used when the MPQ has HET table
+ DWORD dwFileSize; // Decompressed size of the file
+ DWORD dwCmpSize; // Compressed size of the file (i.e., size of the file data in the MPQ)
+ DWORD dwFlags; // File flags (from block table)
+ USHORT lcLocale; // Locale ID for the file
+ USHORT wPlatform; // Platform ID for the file
+ DWORD dwCrc32; // CRC32 from (attributes) file. 0 if not present.
+ unsigned char md5[MD5_DIGEST_SIZE]; // File MD5 from the (attributes) file. 0 if not present.
+ char * szFileName; // File name. NULL if not known.
+};
+
+// Common header for HET and BET tables
+struct TMPQExtTable
+{
+ DWORD dwSignature; // 'HET\x1A' or 'BET\x1A'
+ DWORD dwVersion; // Version. Seems to be always 1
+ DWORD dwDataSize; // Size of the contained table
+
+ // Followed by the table header
+ // Followed by the table data
+
+};
+
+//
+// MPQ data bitmap, can be found at (FileSize - sizeof(TMPQBlockMap))
+//
+// There is bit map of the entire MPQ before TMPQBitmap. Each 0x4000-byte
+// block is represented by one bit (including the last, eventually incomplete block).
+//
+struct TMPQBitmap
+{
+ DWORD dwSignature; // 'ptv3' (MPQ_BLOCK_MAP_SIGNATURE)
+ DWORD dwAlways3; // Unknown, seems to always have value of 3
+ DWORD dwBuildNumber; // Game build number for that MPQ
+ DWORD dwMapOffsetLo; // Low 32-bits of the offset of the bit map
+ DWORD dwMapOffsetHi; // High 32-bits of the offset of the bit map
+ DWORD dwBlockSize; // Size of one block (usually 0x4000 bytes)
+};
+
+// Structure for parsed HET table
+struct TMPQHetTable
+{
+ TBitArray * pBetIndexes; // Bit array of indexes to BET tables
+ LPBYTE pHetHashes; // Array of HET hashes. Each entry has size of 1 byte
+ ULONGLONG AndMask64; // AND mask used for calculating file name hash
+ ULONGLONG OrMask64; // OR mask used for setting the highest bit of the file name hash
+
+ DWORD dwIndexSizeTotal; // Total size of one entry in pBetIndexes (in bits)
+ DWORD dwIndexSizeExtra; // Extra bits in the entry in pBetIndexes
+ DWORD dwIndexSize; // Effective size of one entry in pBetIndexes (in bits)
+ DWORD dwMaxFileCount; // Maximum number of files in the MPQ
+ DWORD dwHashTableSize; // Number of entries in pBetHashes
+ DWORD dwHashBitSize; // Effective number of bits in the hash
+};
+
+// Structure for parsed BET table
+struct TMPQBetTable
+{
+ TBitArray * pBetHashes; // Array of BET hashes
+ TBitArray * pFileTable; // Bit-based file table
+ LPDWORD pFileFlags; // Array of file flags
+
+ DWORD dwTableEntrySize; // Size of one table entry, in bits
+ DWORD dwBitIndex_FilePos; // Bit index of the file position in the table entry
+ DWORD dwBitIndex_FileSize; // Bit index of the file size in the table entry
+ DWORD dwBitIndex_CmpSize; // Bit index of the compressed size in the table entry
+ DWORD dwBitIndex_FlagIndex; // Bit index of the flag index in the table entry
+ DWORD dwBitIndex_Unknown; // Bit index of ??? in the table entry
+ DWORD dwBitCount_FilePos; // Size of file offset (in bits) within table entry
+ DWORD dwBitCount_FileSize; // Size of file size (in bits) within table entry
+ DWORD dwBitCount_CmpSize; // Size of compressed file size (in bits) within table entry
+ DWORD dwBitCount_FlagIndex; // Size of flag index (in bits) within table entry
+ DWORD dwBitCount_Unknown; // Size of ??? (in bits) within table entry
+ DWORD dwBetHashSizeTotal; // Total size of bet hash
+ DWORD dwBetHashSizeExtra; // Extra bits in the bet hash
+ DWORD dwBetHashSize; // Effective size of the bet hash
+ DWORD dwFileCount; // Number of files (usually equal to maximum number of files)
+ DWORD dwFlagCount; // Number of entries in pFileFlags
+};
+
+// Archive handle structure
+struct TMPQArchive
+{
+ TFileStream * pStream; // Open stream for the MPQ
+
+ ULONGLONG UserDataPos; // Position of user data (relative to the begin of the file)
+ ULONGLONG MpqPos; // MPQ header offset (relative to the begin of the file)
+
+ TMPQArchive * haPatch; // Pointer to patch archive, if any
+ TMPQArchive * haBase; // Pointer to base ("previous version") archive, if any
+ char szPatchPrefix[MPQ_PATCH_PREFIX_LEN]; // Prefix for file names in patch MPQs
+ size_t cchPatchPrefix; // Length of the patch prefix, in characters
+
+ TMPQUserData * pUserData; // MPQ user data (NULL if not present in the file)
+ TMPQHeader * pHeader; // MPQ file header
+ TMPQBitmap * pBitmap; // MPQ bitmap
+ TMPQHash * pHashTable; // Hash table
+ TMPQHetTable * pHetTable; // Het table
+ TFileEntry * pFileTable; // File table
+
+ TMPQUserData UserData; // MPQ user data. Valid only when ID_MPQ_USERDATA has been found
+ BYTE HeaderData[MPQ_HEADER_SIZE_V4]; // Storage for MPQ header
+
+ DWORD dwHETBlockSize;
+ DWORD dwBETBlockSize;
+ DWORD dwFileTableSize; // Current size of the file table, e.g. index of the entry past the last occupied one
+ DWORD dwMaxFileCount; // Maximum number of files in the MPQ
+ DWORD dwSectorSize; // Default size of one file sector
+ DWORD dwFileFlags1; // Flags for (listfile)
+ DWORD dwFileFlags2; // Flags for (attributes)
+ DWORD dwAttrFlags; // Flags for the (attributes) file, see MPQ_ATTRIBUTE_XXX
+ DWORD dwFlags; // See MPQ_FLAG_XXXXX
+};
+
+// File handle structure
+struct TMPQFile
+{
+ TFileStream * pStream; // File stream. Only used on local files
+ TMPQArchive * ha; // Archive handle
+ TFileEntry * pFileEntry; // File entry for the file
+ DWORD dwFileKey; // Decryption key
+ DWORD dwFilePos; // Current file position
+ ULONGLONG RawFilePos; // Offset in MPQ archive (relative to file begin)
+ ULONGLONG MpqFilePos; // Offset in MPQ archive (relative to MPQ header)
+ DWORD dwMagic; // 'FILE'
+
+ TMPQFile * hfPatchFile; // Pointer to opened patch file
+ TPatchHeader * pPatchHeader; // Patch header. Only used if the file is a patch file
+ LPBYTE pbFileData; // Loaded and patched file data. Only used if the file is a patch file
+ DWORD cbFileData; // Size of loaded patched data
+
+ TPatchInfo * pPatchInfo; // Patch info block, preceding the sector table
+ DWORD * SectorOffsets; // Position of each file sector, relative to the begin of the file. Only for compressed files.
+ DWORD * SectorChksums; // Array of sector checksums (either ADLER32 or MD5) values for each file sector
+ DWORD dwSectorCount; // Number of sectors in the file
+ DWORD dwPatchedFileSize; // Size of patched file. Used when saving patch file to the MPQ
+ DWORD dwDataSize; // Size of data in the file (on patch files, this differs from file size in block table entry)
+
+ LPBYTE pbFileSector; // Last loaded file sector. For single unit files, entire file content
+ DWORD dwSectorOffs; // File position of currently loaded file sector
+ DWORD dwSectorSize; // Size of the file sector. For single unit files, this is equal to the file size
+
+ unsigned char hctx[HASH_STATE_SIZE];// Hash state for MD5. Used when saving file to MPQ
+ DWORD dwCrc32; // CRC32 value, used when saving file to MPQ
+
+ bool bLoadedSectorCRCs; // If true, we already tried to load sector CRCs
+ bool bCheckSectorCRCs; // If true, then SFileReadFile will check sector CRCs when reading the file
+ bool bIsWriteHandle; // If true, this handle has been created by SFileCreateFile
+ bool bErrorOccured; // If true, then at least one error occured during saving the file to the archive
+};
+
+// Structure for SFileFindFirstFile and SFileFindNextFile
+typedef struct _SFILE_FIND_DATA
+{
+ char cFileName[MAX_PATH]; // Full name of the found file
+ char * szPlainName; // Plain name of the found file
+ DWORD dwHashIndex; // Hash table index for the file
+ DWORD dwBlockIndex; // Block table index for the file
+ DWORD dwFileSize; // File size in bytes
+ DWORD dwFileFlags; // MPQ file flags
+ DWORD dwCompSize; // Compressed file size
+ DWORD dwFileTimeLo; // Low 32-bits of the file time (0 if not present)
+ DWORD dwFileTimeHi; // High 32-bits of the file time (0 if not present)
+ LCID lcLocale; // Locale version
+
+} SFILE_FIND_DATA, *PSFILE_FIND_DATA;
+
+typedef struct _SFILE_CREATE_MPQ
+{
+ DWORD cbSize; // Size of this structure, in bytes
+ DWORD dwMpqVersion; // Version of the MPQ to be created
+ void *pvUserData; // Reserved, must be NULL
+ DWORD cbUserData; // Reserved, must be 0
+ DWORD dwStreamFlags; // Stream flags for creating the MPQ
+ DWORD dwFileFlags1; // File flags for (listfile). 0 = default
+ DWORD dwFileFlags2; // File flags for (attributes). 0 = default
+ DWORD dwAttrFlags; // Flags for the (attributes) file. If 0, no attributes will be created
+ DWORD dwSectorSize; // Sector size for compressed files
+ DWORD dwRawChunkSize; // Size of raw data chunk
+ DWORD dwMaxFileCount; // File limit for the MPQ
+
+} SFILE_CREATE_MPQ, *PSFILE_CREATE_MPQ;
+
+//-----------------------------------------------------------------------------
+// Stream support - functions
+
+TFileStream * FileStream_CreateFile(const TCHAR * szFileName, DWORD dwStreamFlags);
+TFileStream * FileStream_OpenFile(const TCHAR * szFileName, DWORD dwStreamFlags);
+TCHAR * FileStream_GetFileName(TFileStream * pStream);
+bool FileStream_IsReadOnly(TFileStream * pStream);
+bool FileStream_Read(TFileStream * pStream, ULONGLONG * pByteOffset, void * pvBuffer, DWORD dwBytesToRead);
+bool FileStream_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite);
+bool FileStream_GetPos(TFileStream * pStream, ULONGLONG & ByteOffset);
+bool FileStream_SetPos(TFileStream * pStream, ULONGLONG ByteOffset);
+bool FileStream_GetSize(TFileStream * pStream, ULONGLONG & FileSize);
+bool FileStream_SetSize(TFileStream * pStream, ULONGLONG NewFileSize);
+bool FileStream_GetTime(TFileStream * pStream, ULONGLONG * pFT);
+bool FileStream_Switch(TFileStream * pStream, TFileStream * pTempStream);
+bool FileStream_SetBitmap(TFileStream * pStream, TFileBitmap * pBitmap);
+bool FileStream_GetBitmap(TFileStream * pStream, TFileBitmap * pBitmap, DWORD Length, LPDWORD LengthNeeded);
+void FileStream_Close(TFileStream * pStream);
+
+//-----------------------------------------------------------------------------
+// Functions prototypes for Storm.dll
+
+// Typedefs for functions exported by Storm.dll
+typedef LCID (WINAPI * SFILESETLOCALE)(LCID);
+typedef bool (WINAPI * SFILEOPENARCHIVE)(const char *, DWORD, DWORD, HANDLE *);
+typedef bool (WINAPI * SFILECLOSEARCHIVE)(HANDLE);
+typedef bool (WINAPI * SFILEOPENFILEEX)(HANDLE, const char *, DWORD, HANDLE *);
+typedef bool (WINAPI * SFILECLOSEFILE)(HANDLE);
+typedef DWORD (WINAPI * SFILEGETFILESIZE)(HANDLE, LPDWORD);
+typedef DWORD (WINAPI * SFILESETFILEPOINTER)(HANDLE, LONG, LONG *, DWORD);
+typedef bool (WINAPI * SFILEREADFILE)(HANDLE, void *, DWORD, LPDWORD, LPOVERLAPPED);
+
+//-----------------------------------------------------------------------------
+// Functions for manipulation with StormLib global flags
+
+LCID WINAPI SFileGetLocale();
+LCID WINAPI SFileSetLocale(LCID lcNewLocale);
+
+//-----------------------------------------------------------------------------
+// Functions for archive manipulation
+
+bool WINAPI SFileOpenArchive(const TCHAR * szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE * phMpq);
+bool WINAPI SFileCreateArchive(const TCHAR * szMpqName, DWORD dwFlags, DWORD dwMaxFileCount, HANDLE * phMpq);
+bool WINAPI SFileCreateArchive2(const TCHAR * szMpqName, PSFILE_CREATE_MPQ pCreateInfo, HANDLE * phMpq);
+
+bool WINAPI SFileGetArchiveBitmap(HANDLE hMpq, TFileBitmap * pBitmap, DWORD Length, LPDWORD LengthNeeded);
+bool WINAPI SFileFlushArchive(HANDLE hMpq);
+bool WINAPI SFileCloseArchive(HANDLE hMpq);
+
+// Adds another listfile into MPQ. The currently added listfile(s) remain,
+// so you can use this API to combining more listfiles.
+// Note that this function is internally called by SFileFindFirstFile
+int WINAPI SFileAddListFile(HANDLE hMpq, const char * szListFile);
+
+// Archive compacting
+bool WINAPI SFileSetCompactCallback(HANDLE hMpq, SFILE_COMPACT_CALLBACK CompactCB, void * pvData);
+bool WINAPI SFileCompactArchive(HANDLE hMpq, const char * szListFile = NULL, bool bReserved = 0);
+
+// Changing the maximum file count
+DWORD WINAPI SFileGetMaxFileCount(HANDLE hMpq);
+bool WINAPI SFileSetMaxFileCount(HANDLE hMpq, DWORD dwMaxFileCount);
+
+// Changing (attributes) file
+DWORD WINAPI SFileGetAttributes(HANDLE hMpq);
+bool WINAPI SFileSetAttributes(HANDLE hMpq, DWORD dwFlags);
+bool WINAPI SFileUpdateFileAttributes(HANDLE hMpq, const char * szFileName);
+
+//-----------------------------------------------------------------------------
+// Functions for manipulation with patch archives
+
+bool WINAPI SFileOpenPatchArchive(HANDLE hMpq, const TCHAR * szPatchMpqName, const char * szPatchPathPrefix, DWORD dwFlags);
+bool WINAPI SFileIsPatchedArchive(HANDLE hMpq);
+
+//-----------------------------------------------------------------------------
+// Functions for file manipulation
+
+// Reading from MPQ file
+bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile);
+DWORD WINAPI SFileGetFileSize(HANDLE hFile, LPDWORD pdwFileSizeHigh = NULL);
+DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHigh, DWORD dwMoveMethod);
+bool WINAPI SFileReadFile(HANDLE hFile, void * lpBuffer, DWORD dwToRead, LPDWORD pdwRead = NULL, LPOVERLAPPED lpOverlapped = NULL);
+bool WINAPI SFileCloseFile(HANDLE hFile);
+
+// Retrieving info about the file
+bool WINAPI SFileHasFile(HANDLE hMpq, const char * szFileName);
+bool WINAPI SFileGetFileName(HANDLE hFile, char * szFileName);
+bool WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, DWORD dwInfoType, void * pvFileInfo, DWORD cbFileInfo, LPDWORD pcbLengthNeeded = NULL);
+
+// High-level extract function
+bool WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const TCHAR * szExtracted, DWORD dwSearchScope = SFILE_OPEN_FROM_MPQ);
+
+//-----------------------------------------------------------------------------
+// Functions for file and archive verification
+
+// Generates file CRC32
+bool WINAPI SFileGetFileChecksums(HANDLE hMpq, const char * szFileName, LPDWORD pdwCrc32, char * pMD5);
+
+// Verifies file against its checksums stored in (attributes) attributes (depending on dwFlags).
+// For dwFlags, use one or more of MPQ_ATTRIBUTE_MD5
+DWORD WINAPI SFileVerifyFile(HANDLE hMpq, const char * szFileName, DWORD dwFlags);
+
+// Verifies raw data of the archive. Only works for MPQs version 4 or newer
+int WINAPI SFileVerifyRawData(HANDLE hMpq, DWORD dwWhatToVerify, const char * szFileName);
+
+// Verifies the signature, if present
+DWORD WINAPI SFileVerifyArchive(HANDLE hMpq);
+
+//-----------------------------------------------------------------------------
+// Functions for file searching
+
+HANDLE WINAPI SFileFindFirstFile(HANDLE hMpq, const char * szMask, SFILE_FIND_DATA * lpFindFileData, const char * szListFile);
+bool WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData);
+bool WINAPI SFileFindClose(HANDLE hFind);
+
+HANDLE WINAPI SListFileFindFirstFile(HANDLE hMpq, const char * szListFile, const char * szMask, SFILE_FIND_DATA * lpFindFileData);
+bool WINAPI SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData);
+bool WINAPI SListFileFindClose(HANDLE hFind);
+
+// Locale support
+int WINAPI SFileEnumLocales(HANDLE hMpq, const char * szFileName, LCID * plcLocales, LPDWORD pdwMaxLocales, DWORD dwSearchScope);
+
+//-----------------------------------------------------------------------------
+// Support for adding files to the MPQ
+
+bool WINAPI SFileCreateFile(HANDLE hMpq, const char * szArchivedName, ULONGLONG FileTime, DWORD dwFileSize, LCID lcLocale, DWORD dwFlags, HANDLE * phFile);
+bool WINAPI SFileWriteFile(HANDLE hFile, const void * pvData, DWORD dwSize, DWORD dwCompression);
+bool WINAPI SFileFinishFile(HANDLE hFile);
+
+bool WINAPI SFileAddFileEx(HANDLE hMpq, const TCHAR * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwCompression, DWORD dwCompressionNext = MPQ_COMPRESSION_NEXT_SAME);
+bool WINAPI SFileAddFile(HANDLE hMpq, const TCHAR * szFileName, const char * szArchivedName, DWORD dwFlags);
+bool WINAPI SFileAddWave(HANDLE hMpq, const TCHAR * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality);
+bool WINAPI SFileRemoveFile(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope = SFILE_OPEN_FROM_MPQ);
+bool WINAPI SFileRenameFile(HANDLE hMpq, const char * szOldFileName, const char * szNewFileName);
+bool WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale);
+bool WINAPI SFileSetDataCompression(DWORD DataCompression);
+
+bool WINAPI SFileSetAddFileCallback(HANDLE hMpq, SFILE_ADDFILE_CALLBACK AddFileCB, void * pvData);
+
+//-----------------------------------------------------------------------------
+// Compression and decompression
+
+int WINAPI SCompImplode (char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer);
+int WINAPI SCompExplode (char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer);
+int WINAPI SCompCompress (char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer, unsigned uCompressionMask, int nCmpType, int nCmpLevel);
+int WINAPI SCompDecompress (char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer);
+int WINAPI SCompDecompress2(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer);
+
+//-----------------------------------------------------------------------------
+// Non-Windows support for SetLastError/GetLastError
+
+#ifndef PLATFORM_WINDOWS
+
+void SetLastError(int err);
+int GetLastError();
+
+#endif
+
+//-----------------------------------------------------------------------------
+// Functions from Storm.dll. They use slightly different names for keeping
+// possibility to use them together with StormLib (StormXXX instead of SFileXXX)
+
+#ifdef __LINK_STORM_DLL__
+ #define STORM_ALTERNATE_NAMES // Force storm_dll.h to use alternate fnc names
+ #include "..\storm_dll\storm_dll.h"
+#endif // __LINK_STORM_DLL__
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // __STORMLIB_H__
diff --git a/dep/StormLib/src/StormPort.h b/dep/StormLib/src/StormPort.h
new file mode 100644
index 00000000000..0914654b9af
--- /dev/null
+++ b/dep/StormLib/src/StormPort.h
@@ -0,0 +1,235 @@
+/*****************************************************************************/
+/* StormPort.h Copyright (c) Marko Friedemann 2001 */
+/*---------------------------------------------------------------------------*/
+/* Portability module for the StormLib library. Contains a wrapper symbols */
+/* to make the compilation under Linux work */
+/* */
+/* Author: Marko Friedemann <marko.friedemann@bmx-chemnitz.de> */
+/* Created at: Mon Jan 29 18:26:01 CEST 2001 */
+/* Computer: whiplash.flachland-chemnitz.de */
+/* System: Linux 2.4.0 on i686 */
+/* */
+/* Author: Sam Wilkins <swilkins1337@gmail.com> */
+/* System: Mac OS X and port to big endian processor */
+/* */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 29.01.01 1.00 Mar Created */
+/* 24.03.03 1.01 Lad Some cosmetic changes */
+/* 12.11.03 1.02 Dan Macintosh compatibility */
+/* 24.07.04 1.03 Sam Mac OS X compatibility */
+/* 22.11.06 1.04 Sam Mac OS X compatibility (for StormLib 6.0) */
+/* 31.12.06 1.05 XPinguin Full GNU/Linux compatibility */
+/*****************************************************************************/
+
+#ifndef __STORMPORT_H__
+#define __STORMPORT_H__
+
+#ifndef __cplusplus
+ #define bool char
+ #define true 1
+ #define false 0
+#endif
+
+// Defines for Windows
+#if !defined(PLATFORM_DEFINED) && (defined(WIN32) || defined(WIN64))
+
+ // In MSVC 8.0, there are some functions declared as deprecated.
+ #if _MSC_VER >= 1400
+ #define _CRT_SECURE_NO_DEPRECATE
+ #define _CRT_NON_CONFORMING_SWPRINTFS
+ #endif
+
+ #include <tchar.h>
+ #include <assert.h>
+ #include <ctype.h>
+ #include <stdio.h>
+ #include <windows.h>
+ #include <wininet.h>
+ #define PLATFORM_LITTLE_ENDIAN
+
+ #ifdef WIN64
+ #define PLATFORM_64BIT
+ #else
+ #define PLATFORM_32BIT
+ #endif
+
+ #define PLATFORM_WINDOWS
+ #define PLATFORM_DEFINED // The platform is known now
+
+#endif
+
+// Defines for Mac
+#if !defined(PLATFORM_DEFINED) && defined(__APPLE__) // Mac BSD API
+
+ // Macintosh
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <sys/mman.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <stdlib.h>
+ #include <errno.h>
+
+ #define PKEXPORT
+ #define __SYS_ZLIB
+ #define __SYS_BZLIB
+
+ #ifndef __BIG_ENDIAN__
+ #define PLATFORM_LITTLE_ENDIAN
+ #endif
+
+ #define PLATFORM_MAC
+ #define PLATFORM_DEFINED // The platform is known now
+
+#endif
+
+// Assumption: we are not on Windows nor Macintosh, so this must be linux *grin*
+#if !defined(PLATFORM_DEFINED)
+
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <sys/mman.h>
+ #include <fcntl.h>
+ #include <unistd.h>
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <stdarg.h>
+ #include <string.h>
+ #include <ctype.h>
+ #include <assert.h>
+ #include <errno.h>
+
+ #define PLATFORM_LITTLE_ENDIAN
+ #define PLATFORM_LINUX
+ #define PLATFORM_DEFINED
+
+#endif
+
+// Definition of Windows-specific structures for non-Windows platforms
+#ifndef PLATFORM_WINDOWS
+ #if __LP64__
+ #define PLATFORM_64BIT
+ #else
+ #define PLATFORM_32BIT
+ #endif
+
+ // Typedefs for ANSI C
+ typedef unsigned char BYTE;
+ typedef unsigned short USHORT;
+ typedef int LONG;
+ typedef unsigned int DWORD;
+ typedef unsigned long DWORD_PTR;
+ typedef long LONG_PTR;
+ typedef long INT_PTR;
+ typedef long long LONGLONG;
+ typedef unsigned long long ULONGLONG;
+ typedef void * HANDLE;
+ typedef void * LPOVERLAPPED; // Unsupported on Linux and Mac
+ typedef char TCHAR;
+ typedef unsigned int LCID;
+ typedef LONG * PLONG;
+ typedef DWORD * LPDWORD;
+ typedef BYTE * LPBYTE;
+
+ #ifdef PLATFORM_32BIT
+ #define _LZMA_UINT32_IS_ULONG
+ #endif
+
+ // Some Windows-specific defines
+ #ifndef MAX_PATH
+ #define MAX_PATH 1024
+ #endif
+
+ #define WINAPI
+
+ #define FILE_BEGIN SEEK_SET
+ #define FILE_CURRENT SEEK_CUR
+ #define FILE_END SEEK_END
+
+ #define _T(x) x
+ #define _tcslen strlen
+ #define _tcscpy strcpy
+ #define _tcscat strcat
+ #define _tcsrchr strrchr
+ #define _tprintf printf
+ #define _stprintf sprintf
+ #define _tremove remove
+
+ #define _stricmp strcasecmp
+ #define _strnicmp strncasecmp
+ #define _tcsnicmp strncasecmp
+
+#endif // !WIN32
+
+// 64-bit calls are supplied by "normal" calls on Mac
+#if defined(PLATFORM_MAC)
+ #define stat64 stat
+ #define fstat64 fstat
+ #define lseek64 lseek
+ #define off64_t off_t
+ #define O_LARGEFILE 0
+#endif
+
+// Platform-specific error codes for UNIX-based platforms
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ #define ERROR_SUCCESS 0
+ #define ERROR_FILE_NOT_FOUND ENOENT
+ #define ERROR_ACCESS_DENIED EPERM
+ #define ERROR_INVALID_HANDLE EBADF
+ #define ERROR_NOT_ENOUGH_MEMORY ENOMEM
+ #define ERROR_BAD_FORMAT 105 // No such error code under Linux
+ #define ERROR_NO_MORE_FILES 106
+ #define ERROR_HANDLE_EOF 107 // No such error code under Linux
+ #define ERROR_NOT_SUPPORTED ENOTSUP
+ #define ERROR_INVALID_PARAMETER EINVAL
+ #define ERROR_DISK_FULL ENOSPC
+ #define ERROR_ALREADY_EXISTS EEXIST
+ #define ERROR_CAN_NOT_COMPLETE 108 // No such error code under Linux
+ #define ERROR_FILE_CORRUPT 109 // No such error code under Linux
+ #define ERROR_INSUFFICIENT_BUFFER ENOBUFS
+#endif
+
+#ifdef PLATFORM_LITTLE_ENDIAN
+ #define BSWAP_INT16_UNSIGNED(a) (a)
+ #define BSWAP_INT16_SIGNED(a) (a)
+ #define BSWAP_INT32_UNSIGNED(a) (a)
+ #define BSWAP_INT32_SIGNED(a) (a)
+ #define BSWAP_INT64_SIGNED(a) (a)
+ #define BSWAP_INT64_UNSIGNED(a) (a)
+ #define BSWAP_ARRAY16_UNSIGNED(a,b) {}
+ #define BSWAP_ARRAY32_UNSIGNED(a,b) {}
+ #define BSWAP_ARRAY64_UNSIGNED(a,b) {}
+ #define BSWAP_PART_HEADER(a) {}
+ #define BSWAP_TMPQUSERDATA(a) {}
+ #define BSWAP_TMPQHEADER(a) {}
+#else
+ int16_t SwapInt16(uint16_t);
+ uint16_t SwapUInt16(uint16_t);
+ int32_t SwapInt32(uint32_t);
+ uint32_t SwapUInt32(uint32_t);
+ int64_t SwapInt64(uint64_t);
+ uint64_t SwapUInt64(uint64_t);
+ void ConvertUInt16Buffer(void * ptr, size_t length);
+ void ConvertUInt32Buffer(void * ptr, size_t length);
+ void ConvertUInt64Buffer(void * ptr, size_t length);
+ void ConvertPartHeader(void * partHeader);
+ void ConvertTMPQUserData(void *userData);
+ void ConvertTMPQHeader(void *header);
+ #define BSWAP_INT16_SIGNED(a) SwapInt16((a))
+ #define BSWAP_INT16_UNSIGNED(a) SwapUInt16((a))
+ #define BSWAP_INT32_SIGNED(a) SwapInt32((a))
+ #define BSWAP_INT32_UNSIGNED(a) SwapUInt32((a))
+ #define BSWAP_INT64_SIGNED(a) SwapInt64((a))
+ #define BSWAP_INT64_UNSIGNED(a) SwapUInt64((a))
+ #define BSWAP_ARRAY16_UNSIGNED(a,b) ConvertUInt16Buffer((a),(b))
+ #define BSWAP_ARRAY32_UNSIGNED(a,b) ConvertUInt32Buffer((a),(b))
+ #define BSWAP_ARRAY64_UNSIGNED(a,b) ConvertUInt64Buffer((a),(b))
+ #define BSWAP_PART_HEADER(a) ConvertPartHeader(a)
+ #define BSWAP_TMPQUSERDATA(a) ConvertTMPQUserData((a))
+ #define BSWAP_TMPQHEADER(a) ConvertTMPQHeader((a))
+#endif
+
+#endif // __STORMPORT_H__
diff --git a/dep/StormLib/src/adpcm/adpcm.cpp b/dep/StormLib/src/adpcm/adpcm.cpp
new file mode 100644
index 00000000000..916fa3811a8
--- /dev/null
+++ b/dep/StormLib/src/adpcm/adpcm.cpp
@@ -0,0 +1,358 @@
+/*****************************************************************************/
+/* adpcm.cpp Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* This module contains implementation of adpcm decompression method used by */
+/* Storm.dll to decompress WAVE files. Thanks to Tom Amigo for releasing */
+/* his sources. */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 11.03.03 1.00 Lad Splitted from Pkware.cpp */
+/* 20.05.03 2.00 Lad Added compression */
+/* 19.11.03 2.01 Dan Big endian handling */
+/*****************************************************************************/
+
+#include "adpcm.h"
+
+//------------------------------------------------------------------------------
+// Structures
+
+typedef union _BYTE_AND_WORD_PTR
+{
+ short * pw;
+ unsigned char * pb;
+} BYTE_AND_WORD_PTR;
+
+typedef union _WORD_AND_BYTE_ARRAY
+{
+ short w;
+ unsigned char b[2];
+} WORD_AND_BYTE_ARRAY;
+
+//-----------------------------------------------------------------------------
+// Tables necessary dor decompression
+
+static long Table1503F120[] =
+{
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000006,
+ 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
+ 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
+ 0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000006, 0xFFFFFFFF, 0x00000008
+};
+
+static long step_table[] =
+{
+ 0x00000007, 0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E,
+ 0x00000010, 0x00000011, 0x00000013, 0x00000015, 0x00000017, 0x00000019, 0x0000001C, 0x0000001F,
+ 0x00000022, 0x00000025, 0x00000029, 0x0000002D, 0x00000032, 0x00000037, 0x0000003C, 0x00000042,
+ 0x00000049, 0x00000050, 0x00000058, 0x00000061, 0x0000006B, 0x00000076, 0x00000082, 0x0000008F,
+ 0x0000009D, 0x000000AD, 0x000000BE, 0x000000D1, 0x000000E6, 0x000000FD, 0x00000117, 0x00000133,
+ 0x00000151, 0x00000173, 0x00000198, 0x000001C1, 0x000001EE, 0x00000220, 0x00000256, 0x00000292,
+ 0x000002D4, 0x0000031C, 0x0000036C, 0x000003C3, 0x00000424, 0x0000048E, 0x00000502, 0x00000583,
+ 0x00000610, 0x000006AB, 0x00000756, 0x00000812, 0x000008E0, 0x000009C3, 0x00000ABD, 0x00000BD0,
+ 0x00000CFF, 0x00000E4C, 0x00000FBA, 0x0000114C, 0x00001307, 0x000014EE, 0x00001706, 0x00001954,
+ 0x00001BDC, 0x00001EA5, 0x000021B6, 0x00002515, 0x000028CA, 0x00002CDF, 0x0000315B, 0x0000364B,
+ 0x00003BB9, 0x000041B2, 0x00004844, 0x00004F7E, 0x00005771, 0x0000602F, 0x000069CE, 0x00007462,
+ 0x00007FFF
+};
+
+//----------------------------------------------------------------------------
+// CompressWave
+
+// 1500EF70
+int CompressADPCM(unsigned char * pbOutBuffer, int dwOutLength, short * pwInBuffer, int dwInLength, int nChannels, int nCmpLevel)
+// ECX EDX
+{
+ WORD_AND_BYTE_ARRAY Wcmp;
+ BYTE_AND_WORD_PTR out; // Pointer to the output buffer
+ long SInt32Array1[2];
+ long SInt32Array2[2];
+ long SInt32Array3[2];
+ long nBytesRemains = dwOutLength; // Number of bytes remaining
+ long nWordsRemains; // Number of words remaining
+// unsigned char * pbSaveOutBuffer; // Copy of output buffer (actually not used)
+ unsigned long dwBitBuff;
+ unsigned long dwStopBit;
+ unsigned long dwBit;
+ unsigned long ebx;
+ unsigned long esi;
+ long nTableValue;
+ long nOneWord;
+ long var_1C;
+ long var_2C;
+ int nLength;
+ int nIndex;
+ int nValue;
+ int i, chnl;
+
+ // If less than 2 bytes remain, don't decompress anything
+// pbSaveOutBuffer = pbOutBuffer;
+ out.pb = pbOutBuffer;
+ if(nBytesRemains < 2)
+ return 2;
+
+ Wcmp.b[1] = (unsigned char)(nCmpLevel - 1);
+ Wcmp.b[0] = (unsigned char)0;
+
+ *out.pw++ = BSWAP_INT16_SIGNED(Wcmp.w);
+ if((out.pb - pbOutBuffer + (nChannels * 2)) > nBytesRemains)
+ return (int)(out.pb - pbOutBuffer + (nChannels * 2));
+
+ SInt32Array1[0] = SInt32Array1[1] = 0x2C;
+
+ for(i = 0; i < nChannels; i++)
+ {
+ nOneWord = BSWAP_INT16_SIGNED(*pwInBuffer++);
+ *out.pw++ = BSWAP_INT16_SIGNED((short)nOneWord);
+ SInt32Array2[i] = nOneWord;
+ }
+
+ // Weird. But it's there
+ nLength = dwInLength;
+ if(nLength < 0) // mov eax, dwInLength; cdq; sub eax, edx;
+ nLength++;
+
+ nLength = (nLength / 2) - (int)(out.pb - pbOutBuffer);
+ nLength = (nLength < 0) ? 0 : nLength;
+
+ nIndex = nChannels - 1; // edi
+ nWordsRemains = dwInLength / 2; // eax
+
+ // ebx - nChannels
+ // ecx - pwOutPos
+ for(chnl = nChannels; chnl < nWordsRemains; chnl++)
+ {
+ // 1500F030
+ if((out.pb - pbOutBuffer + 2) > nBytesRemains)
+ return (int)(out.pb - pbOutBuffer + 2);
+
+ // Switch index
+ if(nChannels == 2)
+ nIndex = (nIndex == 0) ? 1 : 0;
+
+ // Load one word from the input stream
+ nOneWord = BSWAP_INT16_SIGNED(*pwInBuffer++); // ecx - nOneWord
+ SInt32Array3[nIndex] = nOneWord;
+
+ // esi - SInt32Array2[nIndex]
+ // eax - nValue
+ nValue = nOneWord - SInt32Array2[nIndex];
+ nValue = (nValue < 0) ? ((nValue ^ 0xFFFFFFFF) + 1) : nValue;
+
+ ebx = (nOneWord >= SInt32Array2[nIndex]) ? 0 : 0x40;
+
+ // esi - SInt32Array2[nIndex]
+ // edx - step_table[SInt32Array2[nIndex]]
+ // edi - (step_table[SInt32Array1[nIndex]] >> nCmpLevel)
+ nTableValue = step_table[SInt32Array1[nIndex]];
+ dwStopBit = (unsigned long)nCmpLevel;
+
+ // edi - nIndex;
+ if(nValue < (nTableValue >> nCmpLevel))
+ {
+ if(SInt32Array1[nIndex] != 0)
+ SInt32Array1[nIndex]--;
+ *out.pb++ = 0x80;
+ }
+ else
+ {
+ while(nValue > nTableValue * 2)
+ {
+ if(SInt32Array1[nIndex] >= 0x58 || nLength == 0)
+ break;
+
+ SInt32Array1[nIndex] += 8;
+ if(SInt32Array1[nIndex] > 0x58)
+ SInt32Array1[nIndex] = 0x58;
+
+ nTableValue = step_table[SInt32Array1[nIndex]];
+ *out.pb++ = 0x81;
+ nLength--;
+ }
+
+ var_2C = nTableValue >> Wcmp.b[1];
+ dwBitBuff = 0;
+
+ esi = (1 << (dwStopBit - 2));
+ dwStopBit = (esi <= 0x20) ? esi : 0x20;
+
+ for(var_1C = 0, dwBit = 1; ; dwBit <<= 1)
+ {
+// esi = var_1C + nTableValue;
+ if((var_1C + nTableValue) <= nValue)
+ {
+ var_1C += nTableValue;
+ dwBitBuff |= dwBit;
+ }
+ if(dwBit == dwStopBit)
+ break;
+
+ nTableValue >>= 1;
+ }
+
+ nValue = SInt32Array2[nIndex];
+ if(ebx != 0)
+ {
+ nValue -= (var_1C + var_2C);
+ if(nValue < -32768)
+ nValue = -32768;
+ }
+ else
+ {
+ nValue += (var_1C + var_2C);
+ if(nValue > 32767)
+ nValue = 32767;
+ }
+
+ SInt32Array2[nIndex] = nValue;
+ *out.pb++ = (unsigned char)(dwBitBuff | ebx);
+ nTableValue = Table1503F120[dwBitBuff & 0x1F];
+ SInt32Array1[nIndex] = SInt32Array1[nIndex] + nTableValue;
+ if(SInt32Array1[nIndex] < 0)
+ SInt32Array1[nIndex] = 0;
+ else if(SInt32Array1[nIndex] > 0x58)
+ SInt32Array1[nIndex] = 0x58;
+ }
+ }
+
+ return (int)(out.pb - pbOutBuffer);
+}
+
+//----------------------------------------------------------------------------
+// DecompressADPCM
+
+// 1500F230
+int DecompressADPCM(unsigned char * pbOutBuffer, int dwOutLength, unsigned char * pbInBuffer, int dwInLength, int nChannels)
+{
+ BYTE_AND_WORD_PTR out; // Output buffer
+ BYTE_AND_WORD_PTR in;
+ unsigned char * pbInBufferEnd = (pbInBuffer + dwInLength);
+ long SInt32Array1[2];
+ long SInt32Array2[2];
+ long nOneWord;
+ int nIndex;
+ int i;
+
+ SInt32Array1[0] = SInt32Array1[1] = 0x2C;
+ out.pb = pbOutBuffer;
+ in.pb = pbInBuffer;
+ in.pw++;
+
+ // Fill the Uint32Array2 array by channel values.
+ for(i = 0; i < nChannels; i++)
+ {
+ nOneWord = BSWAP_INT16_SIGNED(*in.pw++);
+ SInt32Array2[i] = nOneWord;
+ if(dwOutLength < 2)
+ return (int)(out.pb - pbOutBuffer);
+
+ *out.pw++ = BSWAP_INT16_SIGNED((short)nOneWord);
+ dwOutLength -= sizeof(short);
+ }
+
+ // Get the initial index
+ nIndex = nChannels - 1;
+
+ // Perform the decompression
+ while(in.pb < pbInBufferEnd)
+ {
+ unsigned char nOneByte = *in.pb++;
+
+ // Switch index
+ if(nChannels == 2)
+ nIndex = (nIndex == 0) ? 1 : 0;
+
+ // 1500F2A2: Get one byte from input buffer
+ if(nOneByte & 0x80)
+ {
+ switch(nOneByte & 0x7F)
+ {
+ case 0: // 1500F315
+ if(SInt32Array1[nIndex] != 0)
+ SInt32Array1[nIndex]--;
+
+ if(dwOutLength < 2)
+ return (int)(out.pb - pbOutBuffer);
+
+ *out.pw++ = BSWAP_INT16_SIGNED((unsigned short)SInt32Array2[nIndex]);
+ dwOutLength -= sizeof(unsigned short);
+ break;
+
+ case 1: // 1500F2E8
+ SInt32Array1[nIndex] += 8;
+ if(SInt32Array1[nIndex] > 0x58)
+ SInt32Array1[nIndex] = 0x58;
+
+ if(nChannels == 2)
+ nIndex = (nIndex == 0) ? 1 : 0;
+ break;
+
+ case 2: // 1500F41E
+ break;
+
+ default: // 1500F2C4
+ SInt32Array1[nIndex] -= 8;
+ if(SInt32Array1[nIndex] < 0)
+ SInt32Array1[nIndex] = 0;
+
+ if(nChannels == 2)
+ nIndex = (nIndex == 0) ? 1 : 0;
+ break;
+ }
+ }
+ else
+ {
+ // 1500F349
+ long temp1 = step_table[SInt32Array1[nIndex]]; // EDI
+ long temp2 = temp1 >> pbInBuffer[1]; // ESI
+ long temp3 = SInt32Array2[nIndex]; // ECX
+
+ if(nOneByte & 0x01) // EBX = nOneByte
+ temp2 += (temp1 >> 0);
+
+ if(nOneByte & 0x02)
+ temp2 += (temp1 >> 1);
+
+ if(nOneByte & 0x04)
+ temp2 += (temp1 >> 2);
+
+ if(nOneByte & 0x08)
+ temp2 += (temp1 >> 3);
+
+ if(nOneByte & 0x10)
+ temp2 += (temp1 >> 4);
+
+ if(nOneByte & 0x20)
+ temp2 += (temp1 >> 5);
+
+ if(nOneByte & 0x40)
+ {
+ temp3 = temp3 - temp2;
+ if(temp3 <= -32768)
+ temp3 = -32768;
+ }
+ else
+ {
+ temp3 = temp3 + temp2;
+ if(temp3 >= 32767)
+ temp3 = 32767;
+ }
+
+ SInt32Array2[nIndex] = temp3;
+ if(dwOutLength < 2)
+ break;
+
+ // Store the output 16-bit value
+ *out.pw++ = BSWAP_INT16_SIGNED((short)SInt32Array2[nIndex]);
+ dwOutLength -= 2;
+
+ SInt32Array1[nIndex] += Table1503F120[nOneByte & 0x1F];
+
+ if(SInt32Array1[nIndex] < 0)
+ SInt32Array1[nIndex] = 0;
+ else if(SInt32Array1[nIndex] > 0x58)
+ SInt32Array1[nIndex] = 0x58;
+ }
+ }
+ return (int)(out.pb - pbOutBuffer);
+}
diff --git a/dep/StormLib/src/adpcm/adpcm.h b/dep/StormLib/src/adpcm/adpcm.h
new file mode 100644
index 00000000000..beb96159720
--- /dev/null
+++ b/dep/StormLib/src/adpcm/adpcm.h
@@ -0,0 +1,22 @@
+/*****************************************************************************/
+/* adpcm.h Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Header file for adpcm decompress functions */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 31.03.03 1.00 Lad The first version of adpcm.h */
+/*****************************************************************************/
+
+#ifndef __ADPCM_H__
+#define __ADPCM_H__
+
+//-----------------------------------------------------------------------------
+// Functions
+
+#include "../StormPort.h"
+
+int CompressADPCM (unsigned char * pbOutBuffer, int dwOutLength, short * pwInBuffer, int dwInLength, int nCmpType, int nChannels);
+int DecompressADPCM(unsigned char * pbOutBuffer, int dwOutLength, unsigned char * pbInBuffer, int dwInLength, int nChannels);
+
+#endif // __ADPCM_H__
diff --git a/dep/StormLib/src/bzip2/blocksort.c b/dep/StormLib/src/bzip2/blocksort.c
new file mode 100644
index 00000000000..bd2dec157fa
--- /dev/null
+++ b/dep/StormLib/src/bzip2/blocksort.c
@@ -0,0 +1,1094 @@
+
+/*-------------------------------------------------------------*/
+/*--- Block sorting machinery ---*/
+/*--- blocksort.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.5 of 10 December 2007
+ Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*---------------------------------------------*/
+/*--- Fallback O(N log(N)^2) sorting ---*/
+/*--- algorithm, for repetitive blocks ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+__inline__
+void fallbackSimpleSort ( UInt32* fmap,
+ UInt32* eclass,
+ Int32 lo,
+ Int32 hi )
+{
+ Int32 i, j, tmp;
+ UInt32 ec_tmp;
+
+ if (lo == hi) return;
+
+ if (hi - lo > 3) {
+ for ( i = hi-4; i >= lo; i-- ) {
+ tmp = fmap[i];
+ ec_tmp = eclass[tmp];
+ for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 )
+ fmap[j-4] = fmap[j];
+ fmap[j-4] = tmp;
+ }
+ }
+
+ for ( i = hi-1; i >= lo; i-- ) {
+ tmp = fmap[i];
+ ec_tmp = eclass[tmp];
+ for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ )
+ fmap[j-1] = fmap[j];
+ fmap[j-1] = tmp;
+ }
+}
+
+
+/*---------------------------------------------*/
+#define fswap(zz1, zz2) \
+ { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
+
+#define fvswap(zzp1, zzp2, zzn) \
+{ \
+ Int32 yyp1 = (zzp1); \
+ Int32 yyp2 = (zzp2); \
+ Int32 yyn = (zzn); \
+ while (yyn > 0) { \
+ fswap(fmap[yyp1], fmap[yyp2]); \
+ yyp1++; yyp2++; yyn--; \
+ } \
+}
+
+
+#define fmin(a,b) ((a) < (b)) ? (a) : (b)
+
+#define fpush(lz,hz) { stackLo[sp] = lz; \
+ stackHi[sp] = hz; \
+ sp++; }
+
+#define fpop(lz,hz) { sp--; \
+ lz = stackLo[sp]; \
+ hz = stackHi[sp]; }
+
+#define FALLBACK_QSORT_SMALL_THRESH 10
+#define FALLBACK_QSORT_STACK_SIZE 100
+
+
+static
+void fallbackQSort3 ( UInt32* fmap,
+ UInt32* eclass,
+ Int32 loSt,
+ Int32 hiSt )
+{
+ Int32 unLo, unHi, ltLo, gtHi, n, m;
+ Int32 sp, lo, hi;
+ UInt32 med, r, r3;
+ Int32 stackLo[FALLBACK_QSORT_STACK_SIZE];
+ Int32 stackHi[FALLBACK_QSORT_STACK_SIZE];
+
+ r = 0;
+
+ sp = 0;
+ fpush ( loSt, hiSt );
+
+ while (sp > 0) {
+
+ AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 );
+
+ fpop ( lo, hi );
+ if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) {
+ fallbackSimpleSort ( fmap, eclass, lo, hi );
+ continue;
+ }
+
+ /* Random partitioning. Median of 3 sometimes fails to
+ avoid bad cases. Median of 9 seems to help but
+ looks rather expensive. This too seems to work but
+ is cheaper. Guidance for the magic constants
+ 7621 and 32768 is taken from Sedgewick's algorithms
+ book, chapter 35.
+ */
+ r = ((r * 7621) + 1) % 32768;
+ r3 = r % 3;
+ if (r3 == 0) med = eclass[fmap[lo]]; else
+ if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else
+ med = eclass[fmap[hi]];
+
+ unLo = ltLo = lo;
+ unHi = gtHi = hi;
+
+ while (1) {
+ while (1) {
+ if (unLo > unHi) break;
+ n = (Int32)eclass[fmap[unLo]] - (Int32)med;
+ if (n == 0) {
+ fswap(fmap[unLo], fmap[ltLo]);
+ ltLo++; unLo++;
+ continue;
+ };
+ if (n > 0) break;
+ unLo++;
+ }
+ while (1) {
+ if (unLo > unHi) break;
+ n = (Int32)eclass[fmap[unHi]] - (Int32)med;
+ if (n == 0) {
+ fswap(fmap[unHi], fmap[gtHi]);
+ gtHi--; unHi--;
+ continue;
+ };
+ if (n < 0) break;
+ unHi--;
+ }
+ if (unLo > unHi) break;
+ fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--;
+ }
+
+ AssertD ( unHi == unLo-1, "fallbackQSort3(2)" );
+
+ if (gtHi < ltLo) continue;
+
+ n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n);
+ m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m);
+
+ n = lo + unLo - ltLo - 1;
+ m = hi - (gtHi - unHi) + 1;
+
+ if (n - lo > hi - m) {
+ fpush ( lo, n );
+ fpush ( m, hi );
+ } else {
+ fpush ( m, hi );
+ fpush ( lo, n );
+ }
+ }
+}
+
+#undef fmin
+#undef fpush
+#undef fpop
+#undef fswap
+#undef fvswap
+#undef FALLBACK_QSORT_SMALL_THRESH
+#undef FALLBACK_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+ nblock > 0
+ eclass exists for [0 .. nblock-1]
+ ((UChar*)eclass) [0 .. nblock-1] holds block
+ ptr exists for [0 .. nblock-1]
+
+ Post:
+ ((UChar*)eclass) [0 .. nblock-1] holds block
+ All other areas of eclass destroyed
+ fmap [0 .. nblock-1] holds sorted order
+ bhtab [ 0 .. 2+(nblock/32) ] destroyed
+*/
+
+#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31))
+#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31))
+#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31)))
+#define WORD_BH(zz) bhtab[(zz) >> 5]
+#define UNALIGNED_BH(zz) ((zz) & 0x01f)
+
+static
+void fallbackSort ( UInt32* fmap,
+ UInt32* eclass,
+ UInt32* bhtab,
+ Int32 nblock,
+ Int32 verb )
+{
+ Int32 ftab[257];
+ Int32 ftabCopy[256];
+ Int32 H, i, j, k, l, r, cc, cc1;
+ Int32 nNotDone;
+ Int32 nBhtab;
+ UChar* eclass8 = (UChar*)eclass;
+
+ /*--
+ Initial 1-char radix sort to generate
+ initial fmap and initial BH bits.
+ --*/
+ if (verb >= 4)
+ VPrintf0 ( " bucket sorting ...\n" );
+ for (i = 0; i < 257; i++) ftab[i] = 0;
+ for (i = 0; i < nblock; i++) ftab[eclass8[i]]++;
+ for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i];
+ for (i = 1; i < 257; i++) ftab[i] += ftab[i-1];
+
+ for (i = 0; i < nblock; i++) {
+ j = eclass8[i];
+ k = ftab[j] - 1;
+ ftab[j] = k;
+ fmap[k] = i;
+ }
+
+ nBhtab = 2 + (nblock / 32);
+ for (i = 0; i < nBhtab; i++) bhtab[i] = 0;
+ for (i = 0; i < 256; i++) SET_BH(ftab[i]);
+
+ /*--
+ Inductively refine the buckets. Kind-of an
+ "exponential radix sort" (!), inspired by the
+ Manber-Myers suffix array construction algorithm.
+ --*/
+
+ /*-- set sentinel bits for block-end detection --*/
+ for (i = 0; i < 32; i++) {
+ SET_BH(nblock + 2*i);
+ CLEAR_BH(nblock + 2*i + 1);
+ }
+
+ /*-- the log(N) loop --*/
+ H = 1;
+ while (1) {
+
+ if (verb >= 4)
+ VPrintf1 ( " depth %6d has ", H );
+
+ j = 0;
+ for (i = 0; i < nblock; i++) {
+ if (ISSET_BH(i)) j = i;
+ k = fmap[i] - H; if (k < 0) k += nblock;
+ eclass[k] = j;
+ }
+
+ nNotDone = 0;
+ r = -1;
+ while (1) {
+
+ /*-- find the next non-singleton bucket --*/
+ k = r + 1;
+ while (ISSET_BH(k) && UNALIGNED_BH(k)) k++;
+ if (ISSET_BH(k)) {
+ while (WORD_BH(k) == 0xffffffff) k += 32;
+ while (ISSET_BH(k)) k++;
+ }
+ l = k - 1;
+ if (l >= nblock) break;
+ while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++;
+ if (!ISSET_BH(k)) {
+ while (WORD_BH(k) == 0x00000000) k += 32;
+ while (!ISSET_BH(k)) k++;
+ }
+ r = k - 1;
+ if (r >= nblock) break;
+
+ /*-- now [l, r] bracket current bucket --*/
+ if (r > l) {
+ nNotDone += (r - l + 1);
+ fallbackQSort3 ( fmap, eclass, l, r );
+
+ /*-- scan bucket and generate header bits-- */
+ cc = -1;
+ for (i = l; i <= r; i++) {
+ cc1 = eclass[fmap[i]];
+ if (cc != cc1) { SET_BH(i); cc = cc1; };
+ }
+ }
+ }
+
+ if (verb >= 4)
+ VPrintf1 ( "%6d unresolved strings\n", nNotDone );
+
+ H *= 2;
+ if (H > nblock || nNotDone == 0) break;
+ }
+
+ /*--
+ Reconstruct the original block in
+ eclass8 [0 .. nblock-1], since the
+ previous phase destroyed it.
+ --*/
+ if (verb >= 4)
+ VPrintf0 ( " reconstructing block ...\n" );
+ j = 0;
+ for (i = 0; i < nblock; i++) {
+ while (ftabCopy[j] == 0) j++;
+ ftabCopy[j]--;
+ eclass8[fmap[i]] = (UChar)j;
+ }
+ AssertH ( j < 256, 1005 );
+}
+
+#undef SET_BH
+#undef CLEAR_BH
+#undef ISSET_BH
+#undef WORD_BH
+#undef UNALIGNED_BH
+
+
+/*---------------------------------------------*/
+/*--- The main, O(N^2 log(N)) sorting ---*/
+/*--- algorithm. Faster for "normal" ---*/
+/*--- non-repetitive blocks. ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+__inline__
+Bool mainGtU ( UInt32 i1,
+ UInt32 i2,
+ UChar* block,
+ UInt16* quadrant,
+ UInt32 nblock,
+ Int32* budget )
+{
+ Int32 k;
+ UChar c1, c2;
+ UInt16 s1, s2;
+
+ AssertD ( i1 != i2, "mainGtU" );
+ /* 1 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 2 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 3 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 4 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 5 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 6 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 7 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 8 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 9 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 10 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 11 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 12 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+
+ k = nblock + 8;
+
+ do {
+ /* 1 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 2 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 3 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 4 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 5 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 6 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 7 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 8 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+
+ if (i1 >= nblock) i1 -= nblock;
+ if (i2 >= nblock) i2 -= nblock;
+
+ k -= 8;
+ (*budget)--;
+ }
+ while (k >= 0);
+
+ return False;
+}
+
+
+/*---------------------------------------------*/
+/*--
+ Knuth's increments seem to work better
+ than Incerpi-Sedgewick here. Possibly
+ because the number of elems to sort is
+ usually small, typically <= 20.
+--*/
+static
+Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280,
+ 9841, 29524, 88573, 265720,
+ 797161, 2391484 };
+
+static
+void mainSimpleSort ( UInt32* ptr,
+ UChar* block,
+ UInt16* quadrant,
+ Int32 nblock,
+ Int32 lo,
+ Int32 hi,
+ Int32 d,
+ Int32* budget )
+{
+ Int32 i, j, h, bigN, hp;
+ UInt32 v;
+
+ bigN = hi - lo + 1;
+ if (bigN < 2) return;
+
+ hp = 0;
+ while (incs[hp] < bigN) hp++;
+ hp--;
+
+ for (; hp >= 0; hp--) {
+ h = incs[hp];
+
+ i = lo + h;
+ while (True) {
+
+ /*-- copy 1 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while ( mainGtU (
+ ptr[j-h]+d, v+d, block, quadrant, nblock, budget
+ ) ) {
+ ptr[j] = ptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) break;
+ }
+ ptr[j] = v;
+ i++;
+
+ /*-- copy 2 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while ( mainGtU (
+ ptr[j-h]+d, v+d, block, quadrant, nblock, budget
+ ) ) {
+ ptr[j] = ptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) break;
+ }
+ ptr[j] = v;
+ i++;
+
+ /*-- copy 3 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while ( mainGtU (
+ ptr[j-h]+d, v+d, block, quadrant, nblock, budget
+ ) ) {
+ ptr[j] = ptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) break;
+ }
+ ptr[j] = v;
+ i++;
+
+ if (*budget < 0) return;
+ }
+ }
+}
+
+
+/*---------------------------------------------*/
+/*--
+ The following is an implementation of
+ an elegant 3-way quicksort for strings,
+ described in a paper "Fast Algorithms for
+ Sorting and Searching Strings", by Robert
+ Sedgewick and Jon L. Bentley.
+--*/
+
+#define mswap(zz1, zz2) \
+ { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
+
+#define mvswap(zzp1, zzp2, zzn) \
+{ \
+ Int32 yyp1 = (zzp1); \
+ Int32 yyp2 = (zzp2); \
+ Int32 yyn = (zzn); \
+ while (yyn > 0) { \
+ mswap(ptr[yyp1], ptr[yyp2]); \
+ yyp1++; yyp2++; yyn--; \
+ } \
+}
+
+static
+__inline__
+UChar mmed3 ( UChar a, UChar b, UChar c )
+{
+ UChar t;
+ if (a > b) { t = a; a = b; b = t; };
+ if (b > c) {
+ b = c;
+ if (a > b) b = a;
+ }
+ return b;
+}
+
+#define mmin(a,b) ((a) < (b)) ? (a) : (b)
+
+#define mpush(lz,hz,dz) { stackLo[sp] = lz; \
+ stackHi[sp] = hz; \
+ stackD [sp] = dz; \
+ sp++; }
+
+#define mpop(lz,hz,dz) { sp--; \
+ lz = stackLo[sp]; \
+ hz = stackHi[sp]; \
+ dz = stackD [sp]; }
+
+
+#define mnextsize(az) (nextHi[az]-nextLo[az])
+
+#define mnextswap(az,bz) \
+ { Int32 tz; \
+ tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \
+ tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \
+ tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; }
+
+
+#define MAIN_QSORT_SMALL_THRESH 20
+#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT)
+#define MAIN_QSORT_STACK_SIZE 100
+
+static
+void mainQSort3 ( UInt32* ptr,
+ UChar* block,
+ UInt16* quadrant,
+ Int32 nblock,
+ Int32 loSt,
+ Int32 hiSt,
+ Int32 dSt,
+ Int32* budget )
+{
+ Int32 unLo, unHi, ltLo, gtHi, n, m, med;
+ Int32 sp, lo, hi, d;
+
+ Int32 stackLo[MAIN_QSORT_STACK_SIZE];
+ Int32 stackHi[MAIN_QSORT_STACK_SIZE];
+ Int32 stackD [MAIN_QSORT_STACK_SIZE];
+
+ Int32 nextLo[3];
+ Int32 nextHi[3];
+ Int32 nextD [3];
+
+ sp = 0;
+ mpush ( loSt, hiSt, dSt );
+
+ while (sp > 0) {
+
+ AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 );
+
+ mpop ( lo, hi, d );
+ if (hi - lo < MAIN_QSORT_SMALL_THRESH ||
+ d > MAIN_QSORT_DEPTH_THRESH) {
+ mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget );
+ if (*budget < 0) return;
+ continue;
+ }
+
+ med = (Int32)
+ mmed3 ( block[ptr[ lo ]+d],
+ block[ptr[ hi ]+d],
+ block[ptr[ (lo+hi)>>1 ]+d] );
+
+ unLo = ltLo = lo;
+ unHi = gtHi = hi;
+
+ while (True) {
+ while (True) {
+ if (unLo > unHi) break;
+ n = ((Int32)block[ptr[unLo]+d]) - med;
+ if (n == 0) {
+ mswap(ptr[unLo], ptr[ltLo]);
+ ltLo++; unLo++; continue;
+ };
+ if (n > 0) break;
+ unLo++;
+ }
+ while (True) {
+ if (unLo > unHi) break;
+ n = ((Int32)block[ptr[unHi]+d]) - med;
+ if (n == 0) {
+ mswap(ptr[unHi], ptr[gtHi]);
+ gtHi--; unHi--; continue;
+ };
+ if (n < 0) break;
+ unHi--;
+ }
+ if (unLo > unHi) break;
+ mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--;
+ }
+
+ AssertD ( unHi == unLo-1, "mainQSort3(2)" );
+
+ if (gtHi < ltLo) {
+ mpush(lo, hi, d+1 );
+ continue;
+ }
+
+ n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n);
+ m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m);
+
+ n = lo + unLo - ltLo - 1;
+ m = hi - (gtHi - unHi) + 1;
+
+ nextLo[0] = lo; nextHi[0] = n; nextD[0] = d;
+ nextLo[1] = m; nextHi[1] = hi; nextD[1] = d;
+ nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1;
+
+ if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
+ if (mnextsize(1) < mnextsize(2)) mnextswap(1,2);
+ if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
+
+ AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" );
+ AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" );
+
+ mpush (nextLo[0], nextHi[0], nextD[0]);
+ mpush (nextLo[1], nextHi[1], nextD[1]);
+ mpush (nextLo[2], nextHi[2], nextD[2]);
+ }
+}
+
+#undef mswap
+#undef mvswap
+#undef mpush
+#undef mpop
+#undef mmin
+#undef mnextsize
+#undef mnextswap
+#undef MAIN_QSORT_SMALL_THRESH
+#undef MAIN_QSORT_DEPTH_THRESH
+#undef MAIN_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+ nblock > N_OVERSHOOT
+ block32 exists for [0 .. nblock-1 +N_OVERSHOOT]
+ ((UChar*)block32) [0 .. nblock-1] holds block
+ ptr exists for [0 .. nblock-1]
+
+ Post:
+ ((UChar*)block32) [0 .. nblock-1] holds block
+ All other areas of block32 destroyed
+ ftab [0 .. 65536 ] destroyed
+ ptr [0 .. nblock-1] holds sorted order
+ if (*budget < 0), sorting was abandoned
+*/
+
+#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8])
+#define SETMASK (1 << 21)
+#define CLEARMASK (~(SETMASK))
+
+static
+void mainSort ( UInt32* ptr,
+ UChar* block,
+ UInt16* quadrant,
+ UInt32* ftab,
+ Int32 nblock,
+ Int32 verb,
+ Int32* budget )
+{
+ Int32 i, j, k, ss, sb;
+ Int32 runningOrder[256];
+ Bool bigDone[256];
+ Int32 copyStart[256];
+ Int32 copyEnd [256];
+ UChar c1;
+ Int32 numQSorted;
+ UInt16 s;
+ if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" );
+
+ /*-- set up the 2-byte frequency table --*/
+ for (i = 65536; i >= 0; i--) ftab[i] = 0;
+
+ j = block[0] << 8;
+ i = nblock-1;
+ for (; i >= 3; i -= 4) {
+ quadrant[i] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i]) << 8);
+ ftab[j]++;
+ quadrant[i-1] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i-1]) << 8);
+ ftab[j]++;
+ quadrant[i-2] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i-2]) << 8);
+ ftab[j]++;
+ quadrant[i-3] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i-3]) << 8);
+ ftab[j]++;
+ }
+ for (; i >= 0; i--) {
+ quadrant[i] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i]) << 8);
+ ftab[j]++;
+ }
+
+ /*-- (emphasises close relationship of block & quadrant) --*/
+ for (i = 0; i < BZ_N_OVERSHOOT; i++) {
+ block [nblock+i] = block[i];
+ quadrant[nblock+i] = 0;
+ }
+
+ if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" );
+
+ /*-- Complete the initial radix sort --*/
+ for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1];
+
+ s = block[0] << 8;
+ i = nblock-1;
+ for (; i >= 3; i -= 4) {
+ s = (s >> 8) | (block[i] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i;
+ s = (s >> 8) | (block[i-1] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i-1;
+ s = (s >> 8) | (block[i-2] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i-2;
+ s = (s >> 8) | (block[i-3] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i-3;
+ }
+ for (; i >= 0; i--) {
+ s = (s >> 8) | (block[i] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i;
+ }
+
+ /*--
+ Now ftab contains the first loc of every small bucket.
+ Calculate the running order, from smallest to largest
+ big bucket.
+ --*/
+ for (i = 0; i <= 255; i++) {
+ bigDone [i] = False;
+ runningOrder[i] = i;
+ }
+
+ {
+ Int32 vv;
+ Int32 h = 1;
+ do h = 3 * h + 1; while (h <= 256);
+ do {
+ h = h / 3;
+ for (i = h; i <= 255; i++) {
+ vv = runningOrder[i];
+ j = i;
+ while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) {
+ runningOrder[j] = runningOrder[j-h];
+ j = j - h;
+ if (j <= (h - 1)) goto zero;
+ }
+ zero:
+ runningOrder[j] = vv;
+ }
+ } while (h != 1);
+ }
+
+ /*--
+ The main sorting loop.
+ --*/
+
+ numQSorted = 0;
+
+ for (i = 0; i <= 255; i++) {
+
+ /*--
+ Process big buckets, starting with the least full.
+ Basically this is a 3-step process in which we call
+ mainQSort3 to sort the small buckets [ss, j], but
+ also make a big effort to avoid the calls if we can.
+ --*/
+ ss = runningOrder[i];
+
+ /*--
+ Step 1:
+ Complete the big bucket [ss] by quicksorting
+ any unsorted small buckets [ss, j], for j != ss.
+ Hopefully previous pointer-scanning phases have already
+ completed many of the small buckets [ss, j], so
+ we don't have to sort them at all.
+ --*/
+ for (j = 0; j <= 255; j++) {
+ if (j != ss) {
+ sb = (ss << 8) + j;
+ if ( ! (ftab[sb] & SETMASK) ) {
+ Int32 lo = ftab[sb] & CLEARMASK;
+ Int32 hi = (ftab[sb+1] & CLEARMASK) - 1;
+ if (hi > lo) {
+ if (verb >= 4)
+ VPrintf4 ( " qsort [0x%x, 0x%x] "
+ "done %d this %d\n",
+ ss, j, numQSorted, hi - lo + 1 );
+ mainQSort3 (
+ ptr, block, quadrant, nblock,
+ lo, hi, BZ_N_RADIX, budget
+ );
+ numQSorted += (hi - lo + 1);
+ if (*budget < 0) return;
+ }
+ }
+ ftab[sb] |= SETMASK;
+ }
+ }
+
+ AssertH ( !bigDone[ss], 1006 );
+
+ /*--
+ Step 2:
+ Now scan this big bucket [ss] so as to synthesise the
+ sorted order for small buckets [t, ss] for all t,
+ including, magically, the bucket [ss,ss] too.
+ This will avoid doing Real Work in subsequent Step 1's.
+ --*/
+ {
+ for (j = 0; j <= 255; j++) {
+ copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK;
+ copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1;
+ }
+ for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) {
+ k = ptr[j]-1; if (k < 0) k += nblock;
+ c1 = block[k];
+ if (!bigDone[c1])
+ ptr[ copyStart[c1]++ ] = k;
+ }
+ for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) {
+ k = ptr[j]-1; if (k < 0) k += nblock;
+ c1 = block[k];
+ if (!bigDone[c1])
+ ptr[ copyEnd[c1]-- ] = k;
+ }
+ }
+
+ AssertH ( (copyStart[ss]-1 == copyEnd[ss])
+ ||
+ /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1.
+ Necessity for this case is demonstrated by compressing
+ a sequence of approximately 48.5 million of character
+ 251; 1.0.0/1.0.1 will then die here. */
+ (copyStart[ss] == 0 && copyEnd[ss] == nblock-1),
+ 1007 )
+
+ for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK;
+
+ /*--
+ Step 3:
+ The [ss] big bucket is now done. Record this fact,
+ and update the quadrant descriptors. Remember to
+ update quadrants in the overshoot area too, if
+ necessary. The "if (i < 255)" test merely skips
+ this updating for the last bucket processed, since
+ updating for the last bucket is pointless.
+
+ The quadrant array provides a way to incrementally
+ cache sort orderings, as they appear, so as to
+ make subsequent comparisons in fullGtU() complete
+ faster. For repetitive blocks this makes a big
+ difference (but not big enough to be able to avoid
+ the fallback sorting mechanism, exponential radix sort).
+
+ The precise meaning is: at all times:
+
+ for 0 <= i < nblock and 0 <= j <= nblock
+
+ if block[i] != block[j],
+
+ then the relative values of quadrant[i] and
+ quadrant[j] are meaningless.
+
+ else {
+ if quadrant[i] < quadrant[j]
+ then the string starting at i lexicographically
+ precedes the string starting at j
+
+ else if quadrant[i] > quadrant[j]
+ then the string starting at j lexicographically
+ precedes the string starting at i
+
+ else
+ the relative ordering of the strings starting
+ at i and j has not yet been determined.
+ }
+ --*/
+ bigDone[ss] = True;
+
+ if (i < 255) {
+ Int32 bbStart = ftab[ss << 8] & CLEARMASK;
+ Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;
+ Int32 shifts = 0;
+
+ while ((bbSize >> shifts) > 65534) shifts++;
+
+ for (j = bbSize-1; j >= 0; j--) {
+ Int32 a2update = ptr[bbStart + j];
+ UInt16 qVal = (UInt16)(j >> shifts);
+ quadrant[a2update] = qVal;
+ if (a2update < BZ_N_OVERSHOOT)
+ quadrant[a2update + nblock] = qVal;
+ }
+ AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 );
+ }
+
+ }
+
+ if (verb >= 4)
+ VPrintf3 ( " %d pointers, %d sorted, %d scanned\n",
+ nblock, numQSorted, nblock - numQSorted );
+}
+
+#undef BIGFREQ
+#undef SETMASK
+#undef CLEARMASK
+
+
+/*---------------------------------------------*/
+/* Pre:
+ nblock > 0
+ arr2 exists for [0 .. nblock-1 +N_OVERSHOOT]
+ ((UChar*)arr2) [0 .. nblock-1] holds block
+ arr1 exists for [0 .. nblock-1]
+
+ Post:
+ ((UChar*)arr2) [0 .. nblock-1] holds block
+ All other areas of block destroyed
+ ftab [ 0 .. 65536 ] destroyed
+ arr1 [0 .. nblock-1] holds sorted order
+*/
+void BZ2_blockSort ( EState* s )
+{
+ UInt32* ptr = s->ptr;
+ UChar* block = s->block;
+ UInt32* ftab = s->ftab;
+ Int32 nblock = s->nblock;
+ Int32 verb = s->verbosity;
+ Int32 wfact = s->workFactor;
+ UInt16* quadrant;
+ Int32 budget;
+ Int32 budgetInit;
+ Int32 i;
+
+ if (nblock < 10000) {
+ fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
+ } else {
+ /* Calculate the location for quadrant, remembering to get
+ the alignment right. Assumes that &(block[0]) is at least
+ 2-byte aligned -- this should be ok since block is really
+ the first section of arr2.
+ */
+ i = nblock+BZ_N_OVERSHOOT;
+ if (i & 1) i++;
+ quadrant = (UInt16*)(&(block[i]));
+
+ /* (wfact-1) / 3 puts the default-factor-30
+ transition point at very roughly the same place as
+ with v0.1 and v0.9.0.
+ Not that it particularly matters any more, since the
+ resulting compressed stream is now the same regardless
+ of whether or not we use the main sort or fallback sort.
+ */
+ if (wfact < 1 ) wfact = 1;
+ if (wfact > 100) wfact = 100;
+ budgetInit = nblock * ((wfact-1) / 3);
+ budget = budgetInit;
+
+ mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget );
+ if (verb >= 3)
+ VPrintf3 ( " %d work, %d block, ratio %5.2f\n",
+ budgetInit - budget,
+ nblock,
+ (float)(budgetInit - budget) /
+ (float)(nblock==0 ? 1 : nblock) );
+ if (budget < 0) {
+ if (verb >= 2)
+ VPrintf0 ( " too repetitive; using fallback"
+ " sorting algorithm\n" );
+ fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
+ }
+ }
+
+ s->origPtr = -1;
+ for (i = 0; i < s->nblock; i++)
+ if (ptr[i] == 0)
+ { s->origPtr = i; break; };
+
+ AssertH( s->origPtr != -1, 1003 );
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end blocksort.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/dep/StormLib/src/bzip2/bzlib.c b/dep/StormLib/src/bzip2/bzlib.c
new file mode 100644
index 00000000000..b98f3e586bc
--- /dev/null
+++ b/dep/StormLib/src/bzip2/bzlib.c
@@ -0,0 +1,1573 @@
+
+/*-------------------------------------------------------------*/
+/*--- Library top-level functions. ---*/
+/*--- bzlib.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.5 of 10 December 2007
+ Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+/* CHANGES
+ 0.9.0 -- original version.
+ 0.9.0a/b -- no changes in this file.
+ 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress().
+ fixed bzWrite/bzRead to ignore zero-length requests.
+ fixed bzread to correctly handle read requests after EOF.
+ wrong parameter order in call to bzDecompressInit in
+ bzBuffToBuffDecompress. Fixed.
+*/
+
+#define _CRT_SECURE_NO_WARNINGS
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+/*--- Compression stuff ---*/
+/*---------------------------------------------------*/
+
+
+/*---------------------------------------------------*/
+#ifndef BZ_NO_STDIO
+void BZ2_bz__AssertH__fail ( int errcode )
+{
+ fprintf(stderr,
+ "\n\nbzip2/libbzip2: internal error number %d.\n"
+ "This is a bug in bzip2/libbzip2, %s.\n"
+ "Please report it to me at: jseward@bzip.org. If this happened\n"
+ "when you were using some program which uses libbzip2 as a\n"
+ "component, you should also report this bug to the author(s)\n"
+ "of that program. Please make an effort to report this bug;\n"
+ "timely and accurate bug reports eventually lead to higher\n"
+ "quality software. Thanks. Julian Seward, 10 December 2007.\n\n",
+ errcode,
+ BZ2_bzlibVersion()
+ );
+
+ if (errcode == 1007) {
+ fprintf(stderr,
+ "\n*** A special note about internal error number 1007 ***\n"
+ "\n"
+ "Experience suggests that a common cause of i.e. 1007\n"
+ "is unreliable memory or other hardware. The 1007 assertion\n"
+ "just happens to cross-check the results of huge numbers of\n"
+ "memory reads/writes, and so acts (unintendedly) as a stress\n"
+ "test of your memory system.\n"
+ "\n"
+ "I suggest the following: try compressing the file again,\n"
+ "possibly monitoring progress in detail with the -vv flag.\n"
+ "\n"
+ "* If the error cannot be reproduced, and/or happens at different\n"
+ " points in compression, you may have a flaky memory system.\n"
+ " Try a memory-test program. I have used Memtest86\n"
+ " (www.memtest86.com). At the time of writing it is free (GPLd).\n"
+ " Memtest86 tests memory much more thorougly than your BIOSs\n"
+ " power-on test, and may find failures that the BIOS doesn't.\n"
+ "\n"
+ "* If the error can be repeatably reproduced, this is a bug in\n"
+ " bzip2, and I would very much like to hear about it. Please\n"
+ " let me know, and, ideally, save a copy of the file causing the\n"
+ " problem -- without which I will be unable to investigate it.\n"
+ "\n"
+ );
+ }
+
+ exit(3);
+}
+#endif
+
+
+/*---------------------------------------------------*/
+static
+int bz_config_ok ( void )
+{
+ if (sizeof(int) != 4) return 0;
+ if (sizeof(short) != 2) return 0;
+ if (sizeof(char) != 1) return 0;
+ return 1;
+}
+
+
+/*---------------------------------------------------*/
+static
+void* default_bzalloc ( void* opaque, Int32 items, Int32 size )
+{
+ void* v = malloc ( items * size );
+ return v;
+}
+
+static
+void default_bzfree ( void* opaque, void* addr )
+{
+ if (addr != NULL) free ( addr );
+}
+
+
+/*---------------------------------------------------*/
+static
+void prepare_new_block ( EState* s )
+{
+ Int32 i;
+ s->nblock = 0;
+ s->numZ = 0;
+ s->state_out_pos = 0;
+ BZ_INITIALISE_CRC ( s->blockCRC );
+ for (i = 0; i < 256; i++) s->inUse[i] = False;
+ s->blockNo++;
+}
+
+
+/*---------------------------------------------------*/
+static
+void init_RL ( EState* s )
+{
+ s->state_in_ch = 256;
+ s->state_in_len = 0;
+}
+
+
+static
+Bool isempty_RL ( EState* s )
+{
+ if (s->state_in_ch < 256 && s->state_in_len > 0)
+ return False; else
+ return True;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompressInit)
+ ( bz_stream* strm,
+ int blockSize100k,
+ int verbosity,
+ int workFactor )
+{
+ Int32 n;
+ EState* s;
+
+ if (!bz_config_ok()) return BZ_CONFIG_ERROR;
+
+ if (strm == NULL ||
+ blockSize100k < 1 || blockSize100k > 9 ||
+ workFactor < 0 || workFactor > 250)
+ return BZ_PARAM_ERROR;
+
+ if (workFactor == 0) workFactor = 30;
+ if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
+ if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
+
+ s = BZALLOC( sizeof(EState) );
+ if (s == NULL) return BZ_MEM_ERROR;
+ s->strm = strm;
+
+ s->arr1 = NULL;
+ s->arr2 = NULL;
+ s->ftab = NULL;
+
+ n = 100000 * blockSize100k;
+ s->arr1 = BZALLOC( n * sizeof(UInt32) );
+ s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) );
+ s->ftab = BZALLOC( 65537 * sizeof(UInt32) );
+
+ if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) {
+ if (s->arr1 != NULL) BZFREE(s->arr1);
+ if (s->arr2 != NULL) BZFREE(s->arr2);
+ if (s->ftab != NULL) BZFREE(s->ftab);
+ if (s != NULL) BZFREE(s);
+ return BZ_MEM_ERROR;
+ }
+
+ s->blockNo = 0;
+ s->state = BZ_S_INPUT;
+ s->mode = BZ_M_RUNNING;
+ s->combinedCRC = 0;
+ s->blockSize100k = blockSize100k;
+ s->nblockMAX = 100000 * blockSize100k - 19;
+ s->verbosity = verbosity;
+ s->workFactor = workFactor;
+
+ s->block = (UChar*)s->arr2;
+ s->mtfv = (UInt16*)s->arr1;
+ s->zbits = NULL;
+ s->ptr = (UInt32*)s->arr1;
+
+ strm->state = s;
+ strm->total_in_lo32 = 0;
+ strm->total_in_hi32 = 0;
+ strm->total_out_lo32 = 0;
+ strm->total_out_hi32 = 0;
+ init_RL ( s );
+ prepare_new_block ( s );
+ return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+static
+void add_pair_to_block ( EState* s )
+{
+ Int32 i;
+ UChar ch = (UChar)(s->state_in_ch);
+ for (i = 0; i < s->state_in_len; i++) {
+ BZ_UPDATE_CRC( s->blockCRC, ch );
+ }
+ s->inUse[s->state_in_ch] = True;
+ switch (s->state_in_len) {
+ case 1:
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ break;
+ case 2:
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ break;
+ case 3:
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ break;
+ default:
+ s->inUse[s->state_in_len-4] = True;
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ s->block[s->nblock] = ((UChar)(s->state_in_len-4));
+ s->nblock++;
+ break;
+ }
+}
+
+
+/*---------------------------------------------------*/
+static
+void flush_RL ( EState* s )
+{
+ if (s->state_in_ch < 256) add_pair_to_block ( s );
+ init_RL ( s );
+}
+
+
+/*---------------------------------------------------*/
+#define ADD_CHAR_TO_BLOCK(zs,zchh0) \
+{ \
+ UInt32 zchh = (UInt32)(zchh0); \
+ /*-- fast track the common case --*/ \
+ if (zchh != zs->state_in_ch && \
+ zs->state_in_len == 1) { \
+ UChar ch = (UChar)(zs->state_in_ch); \
+ BZ_UPDATE_CRC( zs->blockCRC, ch ); \
+ zs->inUse[zs->state_in_ch] = True; \
+ zs->block[zs->nblock] = (UChar)ch; \
+ zs->nblock++; \
+ zs->state_in_ch = zchh; \
+ } \
+ else \
+ /*-- general, uncommon cases --*/ \
+ if (zchh != zs->state_in_ch || \
+ zs->state_in_len == 255) { \
+ if (zs->state_in_ch < 256) \
+ add_pair_to_block ( zs ); \
+ zs->state_in_ch = zchh; \
+ zs->state_in_len = 1; \
+ } else { \
+ zs->state_in_len++; \
+ } \
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool copy_input_until_stop ( EState* s )
+{
+ Bool progress_in = False;
+
+ if (s->mode == BZ_M_RUNNING) {
+
+ /*-- fast track the common case --*/
+ while (True) {
+ /*-- block full? --*/
+ if (s->nblock >= s->nblockMAX) break;
+ /*-- no input? --*/
+ if (s->strm->avail_in == 0) break;
+ progress_in = True;
+ ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) );
+ s->strm->next_in++;
+ s->strm->avail_in--;
+ s->strm->total_in_lo32++;
+ if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
+ }
+
+ } else {
+
+ /*-- general, uncommon case --*/
+ while (True) {
+ /*-- block full? --*/
+ if (s->nblock >= s->nblockMAX) break;
+ /*-- no input? --*/
+ if (s->strm->avail_in == 0) break;
+ /*-- flush/finish end? --*/
+ if (s->avail_in_expect == 0) break;
+ progress_in = True;
+ ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) );
+ s->strm->next_in++;
+ s->strm->avail_in--;
+ s->strm->total_in_lo32++;
+ if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
+ s->avail_in_expect--;
+ }
+ }
+ return progress_in;
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool copy_output_until_stop ( EState* s )
+{
+ Bool progress_out = False;
+
+ while (True) {
+
+ /*-- no output space? --*/
+ if (s->strm->avail_out == 0) break;
+
+ /*-- block done? --*/
+ if (s->state_out_pos >= s->numZ) break;
+
+ progress_out = True;
+ *(s->strm->next_out) = s->zbits[s->state_out_pos];
+ s->state_out_pos++;
+ s->strm->avail_out--;
+ s->strm->next_out++;
+ s->strm->total_out_lo32++;
+ if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+ }
+
+ return progress_out;
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool handle_compress ( bz_stream* strm )
+{
+ Bool progress_in = False;
+ Bool progress_out = False;
+ EState* s = strm->state;
+
+ while (True) {
+
+ if (s->state == BZ_S_OUTPUT) {
+ progress_out |= copy_output_until_stop ( s );
+ if (s->state_out_pos < s->numZ) break;
+ if (s->mode == BZ_M_FINISHING &&
+ s->avail_in_expect == 0 &&
+ isempty_RL(s)) break;
+ prepare_new_block ( s );
+ s->state = BZ_S_INPUT;
+ if (s->mode == BZ_M_FLUSHING &&
+ s->avail_in_expect == 0 &&
+ isempty_RL(s)) break;
+ }
+
+ if (s->state == BZ_S_INPUT) {
+ progress_in |= copy_input_until_stop ( s );
+ if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
+ flush_RL ( s );
+ BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) );
+ s->state = BZ_S_OUTPUT;
+ }
+ else
+ if (s->nblock >= s->nblockMAX) {
+ BZ2_compressBlock ( s, False );
+ s->state = BZ_S_OUTPUT;
+ }
+ else
+ if (s->strm->avail_in == 0) {
+ break;
+ }
+ }
+
+ }
+
+ return progress_in || progress_out;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action )
+{
+ Bool progress;
+ EState* s;
+ if (strm == NULL) return BZ_PARAM_ERROR;
+ s = strm->state;
+ if (s == NULL) return BZ_PARAM_ERROR;
+ if (s->strm != strm) return BZ_PARAM_ERROR;
+
+ preswitch:
+ switch (s->mode) {
+
+ case BZ_M_IDLE:
+ return BZ_SEQUENCE_ERROR;
+
+ case BZ_M_RUNNING:
+ if (action == BZ_RUN) {
+ progress = handle_compress ( strm );
+ return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;
+ }
+ else
+ if (action == BZ_FLUSH) {
+ s->avail_in_expect = strm->avail_in;
+ s->mode = BZ_M_FLUSHING;
+ goto preswitch;
+ }
+ else
+ if (action == BZ_FINISH) {
+ s->avail_in_expect = strm->avail_in;
+ s->mode = BZ_M_FINISHING;
+ goto preswitch;
+ }
+ else
+ return BZ_PARAM_ERROR;
+
+ case BZ_M_FLUSHING:
+ if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR;
+ if (s->avail_in_expect != s->strm->avail_in)
+ return BZ_SEQUENCE_ERROR;
+ progress = handle_compress ( strm );
+ if (s->avail_in_expect > 0 || !isempty_RL(s) ||
+ s->state_out_pos < s->numZ) return BZ_FLUSH_OK;
+ s->mode = BZ_M_RUNNING;
+ return BZ_RUN_OK;
+
+ case BZ_M_FINISHING:
+ if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR;
+ if (s->avail_in_expect != s->strm->avail_in)
+ return BZ_SEQUENCE_ERROR;
+ progress = handle_compress ( strm );
+ if (!progress) return BZ_SEQUENCE_ERROR;
+ if (s->avail_in_expect > 0 || !isempty_RL(s) ||
+ s->state_out_pos < s->numZ) return BZ_FINISH_OK;
+ s->mode = BZ_M_IDLE;
+ return BZ_STREAM_END;
+ }
+ return BZ_OK; /*--not reached--*/
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm )
+{
+ EState* s;
+ if (strm == NULL) return BZ_PARAM_ERROR;
+ s = strm->state;
+ if (s == NULL) return BZ_PARAM_ERROR;
+ if (s->strm != strm) return BZ_PARAM_ERROR;
+
+ if (s->arr1 != NULL) BZFREE(s->arr1);
+ if (s->arr2 != NULL) BZFREE(s->arr2);
+ if (s->ftab != NULL) BZFREE(s->ftab);
+ BZFREE(strm->state);
+
+ strm->state = NULL;
+
+ return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+/*--- Decompression stuff ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompressInit)
+ ( bz_stream* strm,
+ int verbosity,
+ int small )
+{
+ DState* s;
+
+ if (!bz_config_ok()) return BZ_CONFIG_ERROR;
+
+ if (strm == NULL) return BZ_PARAM_ERROR;
+ if (small != 0 && small != 1) return BZ_PARAM_ERROR;
+ if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
+
+ if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
+ if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
+
+ s = BZALLOC( sizeof(DState) );
+ if (s == NULL) return BZ_MEM_ERROR;
+ s->strm = strm;
+ strm->state = s;
+ s->state = BZ_X_MAGIC_1;
+ s->bsLive = 0;
+ s->bsBuff = 0;
+ s->calculatedCombinedCRC = 0;
+ strm->total_in_lo32 = 0;
+ strm->total_in_hi32 = 0;
+ strm->total_out_lo32 = 0;
+ strm->total_out_hi32 = 0;
+ s->smallDecompress = (Bool)small;
+ s->ll4 = NULL;
+ s->ll16 = NULL;
+ s->tt = NULL;
+ s->currBlockNo = 0;
+ s->verbosity = verbosity;
+
+ return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+/* Return True iff data corruption is discovered.
+ Returns False if there is no problem.
+*/
+static
+Bool unRLE_obuf_to_output_FAST ( DState* s )
+{
+ UChar k1;
+
+ if (s->blockRandomised) {
+
+ while (True) {
+ /* try to finish existing run */
+ while (True) {
+ if (s->strm->avail_out == 0) return False;
+ if (s->state_out_len == 0) break;
+ *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+ BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+ s->state_out_len--;
+ s->strm->next_out++;
+ s->strm->avail_out--;
+ s->strm->total_out_lo32++;
+ if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+ }
+
+ /* can a new run be started? */
+ if (s->nblock_used == s->save_nblock+1) return False;
+
+ /* Only caused by corrupt data stream? */
+ if (s->nblock_used > s->save_nblock+1)
+ return True;
+
+ s->state_out_len = 1;
+ s->state_out_ch = s->k0;
+ BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ s->state_out_len = 2;
+ BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ s->state_out_len = 3;
+ BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ s->state_out_len = ((Int32)k1) + 4;
+ BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK;
+ s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
+ }
+
+ } else {
+
+ /* restore */
+ UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC;
+ UChar c_state_out_ch = s->state_out_ch;
+ Int32 c_state_out_len = s->state_out_len;
+ Int32 c_nblock_used = s->nblock_used;
+ Int32 c_k0 = s->k0;
+ UInt32* c_tt = s->tt;
+ UInt32 c_tPos = s->tPos;
+ char* cs_next_out = s->strm->next_out;
+ unsigned int cs_avail_out = s->strm->avail_out;
+ Int32 ro_blockSize100k = s->blockSize100k;
+ /* end restore */
+
+ UInt32 avail_out_INIT = cs_avail_out;
+ Int32 s_save_nblockPP = s->save_nblock+1;
+ unsigned int total_out_lo32_old;
+
+ while (True) {
+
+ /* try to finish existing run */
+ if (c_state_out_len > 0) {
+ while (True) {
+ if (cs_avail_out == 0) goto return_notr;
+ if (c_state_out_len == 1) break;
+ *( (UChar*)(cs_next_out) ) = c_state_out_ch;
+ BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
+ c_state_out_len--;
+ cs_next_out++;
+ cs_avail_out--;
+ }
+ s_state_out_len_eq_one:
+ {
+ if (cs_avail_out == 0) {
+ c_state_out_len = 1; goto return_notr;
+ };
+ *( (UChar*)(cs_next_out) ) = c_state_out_ch;
+ BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
+ cs_next_out++;
+ cs_avail_out--;
+ }
+ }
+ /* Only caused by corrupt data stream? */
+ if (c_nblock_used > s_save_nblockPP)
+ return True;
+
+ /* can a new run be started? */
+ if (c_nblock_used == s_save_nblockPP) {
+ c_state_out_len = 0; goto return_notr;
+ };
+ c_state_out_ch = c_k0;
+ BZ_GET_FAST_C(k1); c_nblock_used++;
+ if (k1 != c_k0) {
+ c_k0 = k1; goto s_state_out_len_eq_one;
+ };
+ if (c_nblock_used == s_save_nblockPP)
+ goto s_state_out_len_eq_one;
+
+ c_state_out_len = 2;
+ BZ_GET_FAST_C(k1); c_nblock_used++;
+ if (c_nblock_used == s_save_nblockPP) continue;
+ if (k1 != c_k0) { c_k0 = k1; continue; };
+
+ c_state_out_len = 3;
+ BZ_GET_FAST_C(k1); c_nblock_used++;
+ if (c_nblock_used == s_save_nblockPP) continue;
+ if (k1 != c_k0) { c_k0 = k1; continue; };
+
+ BZ_GET_FAST_C(k1); c_nblock_used++;
+ c_state_out_len = ((Int32)k1) + 4;
+ BZ_GET_FAST_C(c_k0); c_nblock_used++;
+ }
+
+ return_notr:
+ total_out_lo32_old = s->strm->total_out_lo32;
+ s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
+ if (s->strm->total_out_lo32 < total_out_lo32_old)
+ s->strm->total_out_hi32++;
+
+ /* save */
+ s->calculatedBlockCRC = c_calculatedBlockCRC;
+ s->state_out_ch = c_state_out_ch;
+ s->state_out_len = c_state_out_len;
+ s->nblock_used = c_nblock_used;
+ s->k0 = c_k0;
+ s->tt = c_tt;
+ s->tPos = c_tPos;
+ s->strm->next_out = cs_next_out;
+ s->strm->avail_out = cs_avail_out;
+ /* end save */
+ }
+ return False;
+}
+
+
+
+/*---------------------------------------------------*/
+__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab )
+{
+ Int32 nb, na, mid;
+ nb = 0;
+ na = 256;
+ do {
+ mid = (nb + na) >> 1;
+ if (indx >= cftab[mid]) nb = mid; else na = mid;
+ }
+ while (na - nb != 1);
+ return nb;
+}
+
+
+/*---------------------------------------------------*/
+/* Return True iff data corruption is discovered.
+ Returns False if there is no problem.
+*/
+static
+Bool unRLE_obuf_to_output_SMALL ( DState* s )
+{
+ UChar k1;
+
+ if (s->blockRandomised) {
+
+ while (True) {
+ /* try to finish existing run */
+ while (True) {
+ if (s->strm->avail_out == 0) return False;
+ if (s->state_out_len == 0) break;
+ *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+ BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+ s->state_out_len--;
+ s->strm->next_out++;
+ s->strm->avail_out--;
+ s->strm->total_out_lo32++;
+ if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+ }
+
+ /* can a new run be started? */
+ if (s->nblock_used == s->save_nblock+1) return False;
+
+ /* Only caused by corrupt data stream? */
+ if (s->nblock_used > s->save_nblock+1)
+ return True;
+
+ s->state_out_len = 1;
+ s->state_out_ch = s->k0;
+ BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ s->state_out_len = 2;
+ BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ s->state_out_len = 3;
+ BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ s->state_out_len = ((Int32)k1) + 4;
+ BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK;
+ s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
+ }
+
+ } else {
+
+ while (True) {
+ /* try to finish existing run */
+ while (True) {
+ if (s->strm->avail_out == 0) return False;
+ if (s->state_out_len == 0) break;
+ *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+ BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+ s->state_out_len--;
+ s->strm->next_out++;
+ s->strm->avail_out--;
+ s->strm->total_out_lo32++;
+ if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+ }
+
+ /* can a new run be started? */
+ if (s->nblock_used == s->save_nblock+1) return False;
+
+ /* Only caused by corrupt data stream? */
+ if (s->nblock_used > s->save_nblock+1)
+ return True;
+
+ s->state_out_len = 1;
+ s->state_out_ch = s->k0;
+ BZ_GET_SMALL(k1); s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ s->state_out_len = 2;
+ BZ_GET_SMALL(k1); s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ s->state_out_len = 3;
+ BZ_GET_SMALL(k1); s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ BZ_GET_SMALL(k1); s->nblock_used++;
+ s->state_out_len = ((Int32)k1) + 4;
+ BZ_GET_SMALL(s->k0); s->nblock_used++;
+ }
+
+ }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
+{
+ Bool corrupt;
+ DState* s;
+ if (strm == NULL) return BZ_PARAM_ERROR;
+ s = strm->state;
+ if (s == NULL) return BZ_PARAM_ERROR;
+ if (s->strm != strm) return BZ_PARAM_ERROR;
+
+ while (True) {
+ if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
+ if (s->state == BZ_X_OUTPUT) {
+ if (s->smallDecompress)
+ corrupt = unRLE_obuf_to_output_SMALL ( s ); else
+ corrupt = unRLE_obuf_to_output_FAST ( s );
+ if (corrupt) return BZ_DATA_ERROR;
+ if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
+ BZ_FINALISE_CRC ( s->calculatedBlockCRC );
+ if (s->verbosity >= 3)
+ VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC,
+ s->calculatedBlockCRC );
+ if (s->verbosity >= 2) VPrintf0 ( "]" );
+ if (s->calculatedBlockCRC != s->storedBlockCRC)
+ return BZ_DATA_ERROR;
+ s->calculatedCombinedCRC
+ = (s->calculatedCombinedCRC << 1) |
+ (s->calculatedCombinedCRC >> 31);
+ s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
+ s->state = BZ_X_BLKHDR_1;
+ } else {
+ return BZ_OK;
+ }
+ }
+ if (s->state >= BZ_X_MAGIC_1) {
+ Int32 r = BZ2_decompress ( s );
+ if (r == BZ_STREAM_END) {
+ if (s->verbosity >= 3)
+ VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x",
+ s->storedCombinedCRC, s->calculatedCombinedCRC );
+ if (s->calculatedCombinedCRC != s->storedCombinedCRC)
+ return BZ_DATA_ERROR;
+ return r;
+ }
+ if (s->state != BZ_X_OUTPUT) return r;
+ }
+ }
+
+ AssertH ( 0, 6001 );
+
+ return 0; /*NOTREACHED*/
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm )
+{
+ DState* s;
+ if (strm == NULL) return BZ_PARAM_ERROR;
+ s = strm->state;
+ if (s == NULL) return BZ_PARAM_ERROR;
+ if (s->strm != strm) return BZ_PARAM_ERROR;
+
+ if (s->tt != NULL) BZFREE(s->tt);
+ if (s->ll16 != NULL) BZFREE(s->ll16);
+ if (s->ll4 != NULL) BZFREE(s->ll4);
+
+ BZFREE(strm->state);
+ strm->state = NULL;
+
+ return BZ_OK;
+}
+
+
+#ifndef BZ_NO_STDIO
+/*---------------------------------------------------*/
+/*--- File I/O stuff ---*/
+/*---------------------------------------------------*/
+
+#define BZ_SETERR(eee) \
+{ \
+ if (bzerror != NULL) *bzerror = eee; \
+ if (bzf != NULL) bzf->lastErr = eee; \
+}
+
+typedef
+ struct {
+ FILE* handle;
+ Char buf[BZ_MAX_UNUSED];
+ Int32 bufN;
+ Bool writing;
+ bz_stream strm;
+ Int32 lastErr;
+ Bool initialisedOk;
+ }
+ bzFile;
+
+
+/*---------------------------------------------*/
+static Bool myfeof ( FILE* f )
+{
+ Int32 c = fgetc ( f );
+ if (c == EOF) return True;
+ ungetc ( c, f );
+ return False;
+}
+
+
+/*---------------------------------------------------*/
+BZFILE* BZ_API(BZ2_bzWriteOpen)
+ ( int* bzerror,
+ FILE* f,
+ int blockSize100k,
+ int verbosity,
+ int workFactor )
+{
+ Int32 ret;
+ bzFile* bzf = NULL;
+
+ BZ_SETERR(BZ_OK);
+
+ if (f == NULL ||
+ (blockSize100k < 1 || blockSize100k > 9) ||
+ (workFactor < 0 || workFactor > 250) ||
+ (verbosity < 0 || verbosity > 4))
+ { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
+
+ if (ferror(f))
+ { BZ_SETERR(BZ_IO_ERROR); return NULL; };
+
+ bzf = malloc ( sizeof(bzFile) );
+ if (bzf == NULL)
+ { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
+
+ BZ_SETERR(BZ_OK);
+ bzf->initialisedOk = False;
+ bzf->bufN = 0;
+ bzf->handle = f;
+ bzf->writing = True;
+ bzf->strm.bzalloc = NULL;
+ bzf->strm.bzfree = NULL;
+ bzf->strm.opaque = NULL;
+
+ if (workFactor == 0) workFactor = 30;
+ ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k,
+ verbosity, workFactor );
+ if (ret != BZ_OK)
+ { BZ_SETERR(ret); free(bzf); return NULL; };
+
+ bzf->strm.avail_in = 0;
+ bzf->initialisedOk = True;
+ return bzf;
+}
+
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzWrite)
+ ( int* bzerror,
+ BZFILE* b,
+ void* buf,
+ int len )
+{
+ Int32 n, n2, ret;
+ bzFile* bzf = (bzFile*)b;
+
+ BZ_SETERR(BZ_OK);
+ if (bzf == NULL || buf == NULL || len < 0)
+ { BZ_SETERR(BZ_PARAM_ERROR); return; };
+ if (!(bzf->writing))
+ { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+ if (ferror(bzf->handle))
+ { BZ_SETERR(BZ_IO_ERROR); return; };
+
+ if (len == 0)
+ { BZ_SETERR(BZ_OK); return; };
+
+ bzf->strm.avail_in = len;
+ bzf->strm.next_in = buf;
+
+ while (True) {
+ bzf->strm.avail_out = BZ_MAX_UNUSED;
+ bzf->strm.next_out = bzf->buf;
+ ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN );
+ if (ret != BZ_RUN_OK)
+ { BZ_SETERR(ret); return; };
+
+ if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
+ n = BZ_MAX_UNUSED - bzf->strm.avail_out;
+ n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
+ n, bzf->handle );
+ if (n != n2 || ferror(bzf->handle))
+ { BZ_SETERR(BZ_IO_ERROR); return; };
+ }
+
+ if (bzf->strm.avail_in == 0)
+ { BZ_SETERR(BZ_OK); return; };
+ }
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzWriteClose)
+ ( int* bzerror,
+ BZFILE* b,
+ int abandon,
+ unsigned int* nbytes_in,
+ unsigned int* nbytes_out )
+{
+ BZ2_bzWriteClose64 ( bzerror, b, abandon,
+ nbytes_in, NULL, nbytes_out, NULL );
+}
+
+
+void BZ_API(BZ2_bzWriteClose64)
+ ( int* bzerror,
+ BZFILE* b,
+ int abandon,
+ unsigned int* nbytes_in_lo32,
+ unsigned int* nbytes_in_hi32,
+ unsigned int* nbytes_out_lo32,
+ unsigned int* nbytes_out_hi32 )
+{
+ Int32 n, n2, ret;
+ bzFile* bzf = (bzFile*)b;
+
+ if (bzf == NULL)
+ { BZ_SETERR(BZ_OK); return; };
+ if (!(bzf->writing))
+ { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+ if (ferror(bzf->handle))
+ { BZ_SETERR(BZ_IO_ERROR); return; };
+
+ if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0;
+ if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0;
+ if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0;
+ if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0;
+
+ if ((!abandon) && bzf->lastErr == BZ_OK) {
+ while (True) {
+ bzf->strm.avail_out = BZ_MAX_UNUSED;
+ bzf->strm.next_out = bzf->buf;
+ ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH );
+ if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
+ { BZ_SETERR(ret); return; };
+
+ if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
+ n = BZ_MAX_UNUSED - bzf->strm.avail_out;
+ n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
+ n, bzf->handle );
+ if (n != n2 || ferror(bzf->handle))
+ { BZ_SETERR(BZ_IO_ERROR); return; };
+ }
+
+ if (ret == BZ_STREAM_END) break;
+ }
+ }
+
+ if ( !abandon && !ferror ( bzf->handle ) ) {
+ fflush ( bzf->handle );
+ if (ferror(bzf->handle))
+ { BZ_SETERR(BZ_IO_ERROR); return; };
+ }
+
+ if (nbytes_in_lo32 != NULL)
+ *nbytes_in_lo32 = bzf->strm.total_in_lo32;
+ if (nbytes_in_hi32 != NULL)
+ *nbytes_in_hi32 = bzf->strm.total_in_hi32;
+ if (nbytes_out_lo32 != NULL)
+ *nbytes_out_lo32 = bzf->strm.total_out_lo32;
+ if (nbytes_out_hi32 != NULL)
+ *nbytes_out_hi32 = bzf->strm.total_out_hi32;
+
+ BZ_SETERR(BZ_OK);
+ BZ2_bzCompressEnd ( &(bzf->strm) );
+ free ( bzf );
+}
+
+
+/*---------------------------------------------------*/
+BZFILE* BZ_API(BZ2_bzReadOpen)
+ ( int* bzerror,
+ FILE* f,
+ int verbosity,
+ int small,
+ void* unused,
+ int nUnused )
+{
+ bzFile* bzf = NULL;
+ int ret;
+
+ BZ_SETERR(BZ_OK);
+
+ if (f == NULL ||
+ (small != 0 && small != 1) ||
+ (verbosity < 0 || verbosity > 4) ||
+ (unused == NULL && nUnused != 0) ||
+ (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
+ { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
+
+ if (ferror(f))
+ { BZ_SETERR(BZ_IO_ERROR); return NULL; };
+
+ bzf = malloc ( sizeof(bzFile) );
+ if (bzf == NULL)
+ { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
+
+ BZ_SETERR(BZ_OK);
+
+ bzf->initialisedOk = False;
+ bzf->handle = f;
+ bzf->bufN = 0;
+ bzf->writing = False;
+ bzf->strm.bzalloc = NULL;
+ bzf->strm.bzfree = NULL;
+ bzf->strm.opaque = NULL;
+
+ while (nUnused > 0) {
+ bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++;
+ unused = ((void*)( 1 + ((UChar*)(unused)) ));
+ nUnused--;
+ }
+
+ ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small );
+ if (ret != BZ_OK)
+ { BZ_SETERR(ret); free(bzf); return NULL; };
+
+ bzf->strm.avail_in = bzf->bufN;
+ bzf->strm.next_in = bzf->buf;
+
+ bzf->initialisedOk = True;
+ return bzf;
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b )
+{
+ bzFile* bzf = (bzFile*)b;
+
+ BZ_SETERR(BZ_OK);
+ if (bzf == NULL)
+ { BZ_SETERR(BZ_OK); return; };
+
+ if (bzf->writing)
+ { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+
+ if (bzf->initialisedOk)
+ (void)BZ2_bzDecompressEnd ( &(bzf->strm) );
+ free ( bzf );
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzRead)
+ ( int* bzerror,
+ BZFILE* b,
+ void* buf,
+ int len )
+{
+ Int32 n, ret;
+ bzFile* bzf = (bzFile*)b;
+
+ BZ_SETERR(BZ_OK);
+
+ if (bzf == NULL || buf == NULL || len < 0)
+ { BZ_SETERR(BZ_PARAM_ERROR); return 0; };
+
+ if (bzf->writing)
+ { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; };
+
+ if (len == 0)
+ { BZ_SETERR(BZ_OK); return 0; };
+
+ bzf->strm.avail_out = len;
+ bzf->strm.next_out = buf;
+
+ while (True) {
+
+ if (ferror(bzf->handle))
+ { BZ_SETERR(BZ_IO_ERROR); return 0; };
+
+ if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) {
+ n = fread ( bzf->buf, sizeof(UChar),
+ BZ_MAX_UNUSED, bzf->handle );
+ if (ferror(bzf->handle))
+ { BZ_SETERR(BZ_IO_ERROR); return 0; };
+ bzf->bufN = n;
+ bzf->strm.avail_in = bzf->bufN;
+ bzf->strm.next_in = bzf->buf;
+ }
+
+ ret = BZ2_bzDecompress ( &(bzf->strm) );
+
+ if (ret != BZ_OK && ret != BZ_STREAM_END)
+ { BZ_SETERR(ret); return 0; };
+
+ if (ret == BZ_OK && myfeof(bzf->handle) &&
+ bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0)
+ { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; };
+
+ if (ret == BZ_STREAM_END)
+ { BZ_SETERR(BZ_STREAM_END);
+ return len - bzf->strm.avail_out; };
+ if (bzf->strm.avail_out == 0)
+ { BZ_SETERR(BZ_OK); return len; };
+
+ }
+
+ return 0; /*not reached*/
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzReadGetUnused)
+ ( int* bzerror,
+ BZFILE* b,
+ void** unused,
+ int* nUnused )
+{
+ bzFile* bzf = (bzFile*)b;
+ if (bzf == NULL)
+ { BZ_SETERR(BZ_PARAM_ERROR); return; };
+ if (bzf->lastErr != BZ_STREAM_END)
+ { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+ if (unused == NULL || nUnused == NULL)
+ { BZ_SETERR(BZ_PARAM_ERROR); return; };
+
+ BZ_SETERR(BZ_OK);
+ *nUnused = bzf->strm.avail_in;
+ *unused = bzf->strm.next_in;
+}
+#endif
+
+
+/*---------------------------------------------------*/
+/*--- Misc convenience stuff ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzBuffToBuffCompress)
+ ( char* dest,
+ unsigned int* destLen,
+ char* source,
+ unsigned int sourceLen,
+ int blockSize100k,
+ int verbosity,
+ int workFactor )
+{
+ bz_stream strm;
+ int ret;
+
+ if (dest == NULL || destLen == NULL ||
+ source == NULL ||
+ blockSize100k < 1 || blockSize100k > 9 ||
+ verbosity < 0 || verbosity > 4 ||
+ workFactor < 0 || workFactor > 250)
+ return BZ_PARAM_ERROR;
+
+ if (workFactor == 0) workFactor = 30;
+ strm.bzalloc = NULL;
+ strm.bzfree = NULL;
+ strm.opaque = NULL;
+ ret = BZ2_bzCompressInit ( &strm, blockSize100k,
+ verbosity, workFactor );
+ if (ret != BZ_OK) return ret;
+
+ strm.next_in = source;
+ strm.next_out = dest;
+ strm.avail_in = sourceLen;
+ strm.avail_out = *destLen;
+
+ ret = BZ2_bzCompress ( &strm, BZ_FINISH );
+ if (ret == BZ_FINISH_OK) goto output_overflow;
+ if (ret != BZ_STREAM_END) goto errhandler;
+
+ /* normal termination */
+ *destLen -= strm.avail_out;
+ BZ2_bzCompressEnd ( &strm );
+ return BZ_OK;
+
+ output_overflow:
+ BZ2_bzCompressEnd ( &strm );
+ return BZ_OUTBUFF_FULL;
+
+ errhandler:
+ BZ2_bzCompressEnd ( &strm );
+ return ret;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzBuffToBuffDecompress)
+ ( char* dest,
+ unsigned int* destLen,
+ char* source,
+ unsigned int sourceLen,
+ int small,
+ int verbosity )
+{
+ bz_stream strm;
+ int ret;
+
+ if (dest == NULL || destLen == NULL ||
+ source == NULL ||
+ (small != 0 && small != 1) ||
+ verbosity < 0 || verbosity > 4)
+ return BZ_PARAM_ERROR;
+
+ strm.bzalloc = NULL;
+ strm.bzfree = NULL;
+ strm.opaque = NULL;
+ ret = BZ2_bzDecompressInit ( &strm, verbosity, small );
+ if (ret != BZ_OK) return ret;
+
+ strm.next_in = source;
+ strm.next_out = dest;
+ strm.avail_in = sourceLen;
+ strm.avail_out = *destLen;
+
+ ret = BZ2_bzDecompress ( &strm );
+ if (ret == BZ_OK) goto output_overflow_or_eof;
+ if (ret != BZ_STREAM_END) goto errhandler;
+
+ /* normal termination */
+ *destLen -= strm.avail_out;
+ BZ2_bzDecompressEnd ( &strm );
+ return BZ_OK;
+
+ output_overflow_or_eof:
+ if (strm.avail_out > 0) {
+ BZ2_bzDecompressEnd ( &strm );
+ return BZ_UNEXPECTED_EOF;
+ } else {
+ BZ2_bzDecompressEnd ( &strm );
+ return BZ_OUTBUFF_FULL;
+ };
+
+ errhandler:
+ BZ2_bzDecompressEnd ( &strm );
+ return ret;
+}
+
+
+/*---------------------------------------------------*/
+/*--
+ Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
+ to support better zlib compatibility.
+ This code is not _officially_ part of libbzip2 (yet);
+ I haven't tested it, documented it, or considered the
+ threading-safeness of it.
+ If this code breaks, please contact both Yoshioka and me.
+--*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+/*--
+ return version like "0.9.5d, 4-Sept-1999".
+--*/
+const char * BZ_API(BZ2_bzlibVersion)(void)
+{
+ return BZ_VERSION;
+}
+
+
+#ifndef BZ_NO_STDIO
+/*---------------------------------------------------*/
+
+#if defined(_WIN32) || defined(OS2) || defined(MSDOS)
+# include <fcntl.h>
+# include <io.h>
+# define SET_BINARY_MODE(file) _setmode(_fileno(file),O_BINARY)
+#else
+# define SET_BINARY_MODE(file)
+#endif
+static
+BZFILE * bzopen_or_bzdopen
+ ( const char *path, /* no use when bzdopen */
+ int fd, /* no use when bzdopen */
+ const char *mode,
+ int open_mode) /* bzopen: 0, bzdopen:1 */
+{
+ int bzerr;
+ char unused[BZ_MAX_UNUSED];
+ int blockSize100k = 9;
+ int writing = 0;
+ char mode2[10] = "";
+ FILE *fp = NULL;
+ BZFILE *bzfp = NULL;
+ int verbosity = 0;
+ int workFactor = 30;
+ int smallMode = 0;
+ int nUnused = 0;
+
+ if (mode == NULL) return NULL;
+ while (*mode) {
+ switch (*mode) {
+ case 'r':
+ writing = 0; break;
+ case 'w':
+ writing = 1; break;
+ case 's':
+ smallMode = 1; break;
+ default:
+ if (isdigit((int)(*mode))) {
+ blockSize100k = *mode-BZ_HDR_0;
+ }
+ }
+ mode++;
+ }
+ strcat(mode2, writing ? "w" : "r" );
+ strcat(mode2,"b"); /* binary mode */
+
+ if (open_mode==0) {
+ if (path==NULL || strcmp(path,"")==0) {
+ fp = (writing ? stdout : stdin);
+ SET_BINARY_MODE(fp);
+ } else {
+ fp = fopen(path,mode2);
+ }
+ } else {
+#ifdef BZ_STRICT_ANSI
+ fp = NULL;
+#else
+ fp = _fdopen(fd,mode2);
+#endif
+ }
+ if (fp == NULL) return NULL;
+
+ if (writing) {
+ /* Guard against total chaos and anarchy -- JRS */
+ if (blockSize100k < 1) blockSize100k = 1;
+ if (blockSize100k > 9) blockSize100k = 9;
+ bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k,
+ verbosity,workFactor);
+ } else {
+ bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode,
+ unused,nUnused);
+ }
+ if (bzfp == NULL) {
+ if (fp != stdin && fp != stdout) fclose(fp);
+ return NULL;
+ }
+ return bzfp;
+}
+
+
+/*---------------------------------------------------*/
+/*--
+ open file for read or write.
+ ex) bzopen("file","w9")
+ case path="" or NULL => use stdin or stdout.
+--*/
+BZFILE * BZ_API(BZ2_bzopen)
+ ( const char *path,
+ const char *mode )
+{
+ return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0);
+}
+
+
+/*---------------------------------------------------*/
+BZFILE * BZ_API(BZ2_bzdopen)
+ ( int fd,
+ const char *mode )
+{
+ return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1);
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len )
+{
+ int bzerr, nread;
+ if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0;
+ nread = BZ2_bzRead(&bzerr,b,buf,len);
+ if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) {
+ return nread;
+ } else {
+ return -1;
+ }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len )
+{
+ int bzerr;
+
+ BZ2_bzWrite(&bzerr,b,buf,len);
+ if(bzerr == BZ_OK){
+ return len;
+ }else{
+ return -1;
+ }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzflush) (BZFILE *b)
+{
+ /* do nothing now... */
+ return 0;
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzclose) (BZFILE* b)
+{
+ int bzerr;
+ FILE *fp;
+
+ if (b==NULL) {return;}
+ fp = ((bzFile *)b)->handle;
+ if(((bzFile*)b)->writing){
+ BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
+ if(bzerr != BZ_OK){
+ BZ2_bzWriteClose(NULL,b,1,NULL,NULL);
+ }
+ }else{
+ BZ2_bzReadClose(&bzerr,b);
+ }
+ if(fp!=stdin && fp!=stdout){
+ fclose(fp);
+ }
+}
+
+
+/*---------------------------------------------------*/
+/*--
+ return last error code
+--*/
+static const char *bzerrorstrings[] = {
+ "OK"
+ ,"SEQUENCE_ERROR"
+ ,"PARAM_ERROR"
+ ,"MEM_ERROR"
+ ,"DATA_ERROR"
+ ,"DATA_ERROR_MAGIC"
+ ,"IO_ERROR"
+ ,"UNEXPECTED_EOF"
+ ,"OUTBUFF_FULL"
+ ,"CONFIG_ERROR"
+ ,"???" /* for future */
+ ,"???" /* for future */
+ ,"???" /* for future */
+ ,"???" /* for future */
+ ,"???" /* for future */
+ ,"???" /* for future */
+};
+
+
+const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum)
+{
+ int err = ((bzFile *)b)->lastErr;
+
+ if(err>0) err = 0;
+ *errnum = err;
+ return bzerrorstrings[err*-1];
+}
+#endif
+
+
+/*-------------------------------------------------------------*/
+/*--- end bzlib.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/dep/StormLib/src/bzip2/bzlib.h b/dep/StormLib/src/bzip2/bzlib.h
new file mode 100644
index 00000000000..c5b75d6d8ff
--- /dev/null
+++ b/dep/StormLib/src/bzip2/bzlib.h
@@ -0,0 +1,282 @@
+
+/*-------------------------------------------------------------*/
+/*--- Public header file for the library. ---*/
+/*--- bzlib.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.5 of 10 December 2007
+ Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+#ifndef _BZLIB_H
+#define _BZLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BZ_RUN 0
+#define BZ_FLUSH 1
+#define BZ_FINISH 2
+
+#define BZ_OK 0
+#define BZ_RUN_OK 1
+#define BZ_FLUSH_OK 2
+#define BZ_FINISH_OK 3
+#define BZ_STREAM_END 4
+#define BZ_SEQUENCE_ERROR (-1)
+#define BZ_PARAM_ERROR (-2)
+#define BZ_MEM_ERROR (-3)
+#define BZ_DATA_ERROR (-4)
+#define BZ_DATA_ERROR_MAGIC (-5)
+#define BZ_IO_ERROR (-6)
+#define BZ_UNEXPECTED_EOF (-7)
+#define BZ_OUTBUFF_FULL (-8)
+#define BZ_CONFIG_ERROR (-9)
+
+typedef
+ struct {
+ char *next_in;
+ unsigned int avail_in;
+ unsigned int total_in_lo32;
+ unsigned int total_in_hi32;
+
+ char *next_out;
+ unsigned int avail_out;
+ unsigned int total_out_lo32;
+ unsigned int total_out_hi32;
+
+ void *state;
+
+ void *(*bzalloc)(void *,int,int);
+ void (*bzfree)(void *,void *);
+ void *opaque;
+ }
+ bz_stream;
+
+
+#ifndef BZ_IMPORT
+#define BZ_EXPORT
+#endif
+
+#ifndef BZ_NO_STDIO
+/* Need a definitition for FILE */
+#include <stdio.h>
+#endif
+
+#ifdef _WIN32
+# include <windows.h>
+# ifdef small
+ /* windows.h define small to char */
+# undef small
+# endif
+# ifdef BZ_EXPORT
+# define BZ_API(func) WINAPI func
+# define BZ_EXTERN extern
+# else
+ /* import windows dll dynamically */
+# define BZ_API(func) (WINAPI * func)
+# define BZ_EXTERN
+# endif
+#else
+# define BZ_API(func) func
+# define BZ_EXTERN extern
+#endif
+
+
+/*-- Core (low-level) library functions --*/
+
+BZ_EXTERN int BZ_API(BZ2_bzCompressInit) (
+ bz_stream* strm,
+ int blockSize100k,
+ int verbosity,
+ int workFactor
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompress) (
+ bz_stream* strm,
+ int action
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) (
+ bz_stream* strm
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) (
+ bz_stream *strm,
+ int verbosity,
+ int small
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompress) (
+ bz_stream* strm
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) (
+ bz_stream *strm
+ );
+
+
+
+/*-- High(er) level library functions --*/
+
+#ifndef BZ_NO_STDIO
+#define BZ_MAX_UNUSED 5000
+
+typedef void BZFILE;
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) (
+ int* bzerror,
+ FILE* f,
+ int verbosity,
+ int small,
+ void* unused,
+ int nUnused
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadClose) (
+ int* bzerror,
+ BZFILE* b
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) (
+ int* bzerror,
+ BZFILE* b,
+ void** unused,
+ int* nUnused
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzRead) (
+ int* bzerror,
+ BZFILE* b,
+ void* buf,
+ int len
+ );
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) (
+ int* bzerror,
+ FILE* f,
+ int blockSize100k,
+ int verbosity,
+ int workFactor
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzWrite) (
+ int* bzerror,
+ BZFILE* b,
+ void* buf,
+ int len
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose) (
+ int* bzerror,
+ BZFILE* b,
+ int abandon,
+ unsigned int* nbytes_in,
+ unsigned int* nbytes_out
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) (
+ int* bzerror,
+ BZFILE* b,
+ int abandon,
+ unsigned int* nbytes_in_lo32,
+ unsigned int* nbytes_in_hi32,
+ unsigned int* nbytes_out_lo32,
+ unsigned int* nbytes_out_hi32
+ );
+#endif
+
+
+/*-- Utility functions --*/
+
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) (
+ char* dest,
+ unsigned int* destLen,
+ char* source,
+ unsigned int sourceLen,
+ int blockSize100k,
+ int verbosity,
+ int workFactor
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) (
+ char* dest,
+ unsigned int* destLen,
+ char* source,
+ unsigned int sourceLen,
+ int small,
+ int verbosity
+ );
+
+
+/*--
+ Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
+ to support better zlib compatibility.
+ This code is not _officially_ part of libbzip2 (yet);
+ I haven't tested it, documented it, or considered the
+ threading-safeness of it.
+ If this code breaks, please contact both Yoshioka and me.
+--*/
+
+BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
+ void
+ );
+
+#ifndef BZ_NO_STDIO
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
+ const char *path,
+ const char *mode
+ );
+
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
+ int fd,
+ const char *mode
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzread) (
+ BZFILE* b,
+ void* buf,
+ int len
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzwrite) (
+ BZFILE* b,
+ void* buf,
+ int len
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzflush) (
+ BZFILE* b
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzclose) (
+ BZFILE* b
+ );
+
+BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
+ BZFILE *b,
+ int *errnum
+ );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*-------------------------------------------------------------*/
+/*--- end bzlib.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/dep/StormLib/src/bzip2/bzlib_private.h b/dep/StormLib/src/bzip2/bzlib_private.h
new file mode 100644
index 00000000000..23427879b18
--- /dev/null
+++ b/dep/StormLib/src/bzip2/bzlib_private.h
@@ -0,0 +1,509 @@
+
+/*-------------------------------------------------------------*/
+/*--- Private header file for the library. ---*/
+/*--- bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.5 of 10 December 2007
+ Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+#ifndef _BZLIB_PRIVATE_H
+#define _BZLIB_PRIVATE_H
+
+#include <stdlib.h>
+
+#ifndef BZ_NO_STDIO
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#endif
+
+#include "bzlib.h"
+
+
+
+/*-- General stuff. --*/
+
+#define BZ_VERSION "1.0.5, 10-Dec-2007"
+
+typedef char Char;
+typedef unsigned char Bool;
+typedef unsigned char UChar;
+typedef int Int32;
+typedef unsigned int UInt32;
+typedef short Int16;
+typedef unsigned short UInt16;
+
+#define True ((Bool)1)
+#define False ((Bool)0)
+
+#ifndef __GNUC__
+#define __inline__ /* */
+#endif
+
+#ifndef BZ_NO_STDIO
+
+extern void BZ2_bz__AssertH__fail ( int errcode );
+#define AssertH(cond,errcode) \
+ { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); }
+
+#if BZ_DEBUG
+#define AssertD(cond,msg) \
+ { if (!(cond)) { \
+ fprintf ( stderr, \
+ "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\
+ exit(1); \
+ }}
+#else
+#define AssertD(cond,msg) /* */
+#endif
+
+#define VPrintf0(zf) \
+ fprintf(stderr,zf)
+#define VPrintf1(zf,za1) \
+ fprintf(stderr,zf,za1)
+#define VPrintf2(zf,za1,za2) \
+ fprintf(stderr,zf,za1,za2)
+#define VPrintf3(zf,za1,za2,za3) \
+ fprintf(stderr,zf,za1,za2,za3)
+#define VPrintf4(zf,za1,za2,za3,za4) \
+ fprintf(stderr,zf,za1,za2,za3,za4)
+#define VPrintf5(zf,za1,za2,za3,za4,za5) \
+ fprintf(stderr,zf,za1,za2,za3,za4,za5)
+
+#else
+
+extern void bz_internal_error ( int errcode );
+#define AssertH(cond,errcode) \
+ { if (!(cond)) bz_internal_error ( errcode ); }
+#define AssertD(cond,msg) do { } while (0)
+#define VPrintf0(zf) do { } while (0)
+#define VPrintf1(zf,za1) do { } while (0)
+#define VPrintf2(zf,za1,za2) do { } while (0)
+#define VPrintf3(zf,za1,za2,za3) do { } while (0)
+#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0)
+#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0)
+
+#endif
+
+
+#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1)
+#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp))
+
+
+/*-- Header bytes. --*/
+
+#define BZ_HDR_B 0x42 /* 'B' */
+#define BZ_HDR_Z 0x5a /* 'Z' */
+#define BZ_HDR_h 0x68 /* 'h' */
+#define BZ_HDR_0 0x30 /* '0' */
+
+/*-- Constants for the back end. --*/
+
+#define BZ_MAX_ALPHA_SIZE 258
+#define BZ_MAX_CODE_LEN 23
+
+#define BZ_RUNA 0
+#define BZ_RUNB 1
+
+#define BZ_N_GROUPS 6
+#define BZ_G_SIZE 50
+#define BZ_N_ITERS 4
+
+#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
+
+
+
+/*-- Stuff for randomising repetitive blocks. --*/
+
+extern Int32 BZ2_rNums[512];
+
+#define BZ_RAND_DECLS \
+ Int32 rNToGo; \
+ Int32 rTPos \
+
+#define BZ_RAND_INIT_MASK \
+ s->rNToGo = 0; \
+ s->rTPos = 0 \
+
+#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0)
+
+#define BZ_RAND_UPD_MASK \
+ if (s->rNToGo == 0) { \
+ s->rNToGo = BZ2_rNums[s->rTPos]; \
+ s->rTPos++; \
+ if (s->rTPos == 512) s->rTPos = 0; \
+ } \
+ s->rNToGo--;
+
+
+
+/*-- Stuff for doing CRCs. --*/
+
+extern UInt32 BZ2_crc32Table[256];
+
+#define BZ_INITIALISE_CRC(crcVar) \
+{ \
+ crcVar = 0xffffffffL; \
+}
+
+#define BZ_FINALISE_CRC(crcVar) \
+{ \
+ crcVar = ~(crcVar); \
+}
+
+#define BZ_UPDATE_CRC(crcVar,cha) \
+{ \
+ crcVar = (crcVar << 8) ^ \
+ BZ2_crc32Table[(crcVar >> 24) ^ \
+ ((UChar)cha)]; \
+}
+
+
+
+/*-- States and modes for compression. --*/
+
+#define BZ_M_IDLE 1
+#define BZ_M_RUNNING 2
+#define BZ_M_FLUSHING 3
+#define BZ_M_FINISHING 4
+
+#define BZ_S_OUTPUT 1
+#define BZ_S_INPUT 2
+
+#define BZ_N_RADIX 2
+#define BZ_N_QSORT 12
+#define BZ_N_SHELL 18
+#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
+
+
+
+
+/*-- Structure holding all the compression-side stuff. --*/
+
+typedef
+ struct {
+ /* pointer back to the struct bz_stream */
+ bz_stream* strm;
+
+ /* mode this stream is in, and whether inputting */
+ /* or outputting data */
+ Int32 mode;
+ Int32 state;
+
+ /* remembers avail_in when flush/finish requested */
+ UInt32 avail_in_expect;
+
+ /* for doing the block sorting */
+ UInt32* arr1;
+ UInt32* arr2;
+ UInt32* ftab;
+ Int32 origPtr;
+
+ /* aliases for arr1 and arr2 */
+ UInt32* ptr;
+ UChar* block;
+ UInt16* mtfv;
+ UChar* zbits;
+
+ /* for deciding when to use the fallback sorting algorithm */
+ Int32 workFactor;
+
+ /* run-length-encoding of the input */
+ UInt32 state_in_ch;
+ Int32 state_in_len;
+ BZ_RAND_DECLS;
+
+ /* input and output limits and current posns */
+ Int32 nblock;
+ Int32 nblockMAX;
+ Int32 numZ;
+ Int32 state_out_pos;
+
+ /* map of bytes used in block */
+ Int32 nInUse;
+ Bool inUse[256];
+ UChar unseqToSeq[256];
+
+ /* the buffer for bit stream creation */
+ UInt32 bsBuff;
+ Int32 bsLive;
+
+ /* block and combined CRCs */
+ UInt32 blockCRC;
+ UInt32 combinedCRC;
+
+ /* misc administratium */
+ Int32 verbosity;
+ Int32 blockNo;
+ Int32 blockSize100k;
+
+ /* stuff for coding the MTF values */
+ Int32 nMTF;
+ Int32 mtfFreq [BZ_MAX_ALPHA_SIZE];
+ UChar selector [BZ_MAX_SELECTORS];
+ UChar selectorMtf[BZ_MAX_SELECTORS];
+
+ UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ /* second dimension: only 3 needed; 4 makes index calculations faster */
+ UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4];
+
+ }
+ EState;
+
+
+
+/*-- externs for compression. --*/
+
+extern void
+BZ2_blockSort ( EState* );
+
+extern void
+BZ2_compressBlock ( EState*, Bool );
+
+extern void
+BZ2_bsInitWrite ( EState* );
+
+extern void
+BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 );
+
+extern void
+BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 );
+
+
+
+/*-- states for decompression. --*/
+
+#define BZ_X_IDLE 1
+#define BZ_X_OUTPUT 2
+
+#define BZ_X_MAGIC_1 10
+#define BZ_X_MAGIC_2 11
+#define BZ_X_MAGIC_3 12
+#define BZ_X_MAGIC_4 13
+#define BZ_X_BLKHDR_1 14
+#define BZ_X_BLKHDR_2 15
+#define BZ_X_BLKHDR_3 16
+#define BZ_X_BLKHDR_4 17
+#define BZ_X_BLKHDR_5 18
+#define BZ_X_BLKHDR_6 19
+#define BZ_X_BCRC_1 20
+#define BZ_X_BCRC_2 21
+#define BZ_X_BCRC_3 22
+#define BZ_X_BCRC_4 23
+#define BZ_X_RANDBIT 24
+#define BZ_X_ORIGPTR_1 25
+#define BZ_X_ORIGPTR_2 26
+#define BZ_X_ORIGPTR_3 27
+#define BZ_X_MAPPING_1 28
+#define BZ_X_MAPPING_2 29
+#define BZ_X_SELECTOR_1 30
+#define BZ_X_SELECTOR_2 31
+#define BZ_X_SELECTOR_3 32
+#define BZ_X_CODING_1 33
+#define BZ_X_CODING_2 34
+#define BZ_X_CODING_3 35
+#define BZ_X_MTF_1 36
+#define BZ_X_MTF_2 37
+#define BZ_X_MTF_3 38
+#define BZ_X_MTF_4 39
+#define BZ_X_MTF_5 40
+#define BZ_X_MTF_6 41
+#define BZ_X_ENDHDR_2 42
+#define BZ_X_ENDHDR_3 43
+#define BZ_X_ENDHDR_4 44
+#define BZ_X_ENDHDR_5 45
+#define BZ_X_ENDHDR_6 46
+#define BZ_X_CCRC_1 47
+#define BZ_X_CCRC_2 48
+#define BZ_X_CCRC_3 49
+#define BZ_X_CCRC_4 50
+
+
+
+/*-- Constants for the fast MTF decoder. --*/
+
+#define MTFA_SIZE 4096
+#define MTFL_SIZE 16
+
+
+
+/*-- Structure holding all the decompression-side stuff. --*/
+
+typedef
+ struct {
+ /* pointer back to the struct bz_stream */
+ bz_stream* strm;
+
+ /* state indicator for this stream */
+ Int32 state;
+
+ /* for doing the final run-length decoding */
+ UChar state_out_ch;
+ Int32 state_out_len;
+ Bool blockRandomised;
+ BZ_RAND_DECLS;
+
+ /* the buffer for bit stream reading */
+ UInt32 bsBuff;
+ Int32 bsLive;
+
+ /* misc administratium */
+ Int32 blockSize100k;
+ Bool smallDecompress;
+ Int32 currBlockNo;
+ Int32 verbosity;
+
+ /* for undoing the Burrows-Wheeler transform */
+ Int32 origPtr;
+ UInt32 tPos;
+ Int32 k0;
+ Int32 unzftab[256];
+ Int32 nblock_used;
+ Int32 cftab[257];
+ Int32 cftabCopy[257];
+
+ /* for undoing the Burrows-Wheeler transform (FAST) */
+ UInt32 *tt;
+
+ /* for undoing the Burrows-Wheeler transform (SMALL) */
+ UInt16 *ll16;
+ UChar *ll4;
+
+ /* stored and calculated CRCs */
+ UInt32 storedBlockCRC;
+ UInt32 storedCombinedCRC;
+ UInt32 calculatedBlockCRC;
+ UInt32 calculatedCombinedCRC;
+
+ /* map of bytes used in block */
+ Int32 nInUse;
+ Bool inUse[256];
+ Bool inUse16[16];
+ UChar seqToUnseq[256];
+
+ /* for decoding the MTF values */
+ UChar mtfa [MTFA_SIZE];
+ Int32 mtfbase[256 / MTFL_SIZE];
+ UChar selector [BZ_MAX_SELECTORS];
+ UChar selectorMtf[BZ_MAX_SELECTORS];
+ UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+
+ Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ Int32 minLens[BZ_N_GROUPS];
+
+ /* save area for scalars in the main decompress code */
+ Int32 save_i;
+ Int32 save_j;
+ Int32 save_t;
+ Int32 save_alphaSize;
+ Int32 save_nGroups;
+ Int32 save_nSelectors;
+ Int32 save_EOB;
+ Int32 save_groupNo;
+ Int32 save_groupPos;
+ Int32 save_nextSym;
+ Int32 save_nblockMAX;
+ Int32 save_nblock;
+ Int32 save_es;
+ Int32 save_N;
+ Int32 save_curr;
+ Int32 save_zt;
+ Int32 save_zn;
+ Int32 save_zvec;
+ Int32 save_zj;
+ Int32 save_gSel;
+ Int32 save_gMinlen;
+ Int32* save_gLimit;
+ Int32* save_gBase;
+ Int32* save_gPerm;
+
+ }
+ DState;
+
+
+
+/*-- Macros for decompression. --*/
+
+#define BZ_GET_FAST(cccc) \
+ /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+ if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
+ s->tPos = s->tt[s->tPos]; \
+ cccc = (UChar)(s->tPos & 0xff); \
+ s->tPos >>= 8;
+
+#define BZ_GET_FAST_C(cccc) \
+ /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+ if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \
+ c_tPos = c_tt[c_tPos]; \
+ cccc = (UChar)(c_tPos & 0xff); \
+ c_tPos >>= 8;
+
+#define SET_LL4(i,n) \
+ { if (((i) & 0x1) == 0) \
+ s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \
+ s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \
+ }
+
+#define GET_LL4(i) \
+ ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF)
+
+#define SET_LL(i,n) \
+ { s->ll16[i] = (UInt16)(n & 0x0000ffff); \
+ SET_LL4(i, n >> 16); \
+ }
+
+#define GET_LL(i) \
+ (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16))
+
+#define BZ_GET_SMALL(cccc) \
+ /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+ if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
+ cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \
+ s->tPos = GET_LL(s->tPos);
+
+
+/*-- externs for decompression. --*/
+
+extern Int32
+BZ2_indexIntoF ( Int32, Int32* );
+
+extern Int32
+BZ2_decompress ( DState* );
+
+extern void
+BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*,
+ Int32, Int32, Int32 );
+
+
+#endif
+
+
+/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/
+
+#ifdef BZ_NO_STDIO
+#ifndef NULL
+#define NULL 0
+#endif
+#endif
+
+
+/*-------------------------------------------------------------*/
+/*--- end bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/dep/StormLib/src/bzip2/compress.c b/dep/StormLib/src/bzip2/compress.c
new file mode 100644
index 00000000000..8c80a079700
--- /dev/null
+++ b/dep/StormLib/src/bzip2/compress.c
@@ -0,0 +1,672 @@
+
+/*-------------------------------------------------------------*/
+/*--- Compression machinery (not incl block sorting) ---*/
+/*--- compress.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.5 of 10 December 2007
+ Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+/* CHANGES
+ 0.9.0 -- original version.
+ 0.9.0a/b -- no changes in this file.
+ 0.9.0c -- changed setting of nGroups in sendMTFValues()
+ so as to do a bit better on small files
+*/
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+/*--- Bit stream I/O ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+void BZ2_bsInitWrite ( EState* s )
+{
+ s->bsLive = 0;
+ s->bsBuff = 0;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsFinishWrite ( EState* s )
+{
+ while (s->bsLive > 0) {
+ s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24);
+ s->numZ++;
+ s->bsBuff <<= 8;
+ s->bsLive -= 8;
+ }
+}
+
+
+/*---------------------------------------------------*/
+#define bsNEEDW(nz) \
+{ \
+ while (s->bsLive >= 8) { \
+ s->zbits[s->numZ] \
+ = (UChar)(s->bsBuff >> 24); \
+ s->numZ++; \
+ s->bsBuff <<= 8; \
+ s->bsLive -= 8; \
+ } \
+}
+
+
+/*---------------------------------------------------*/
+static
+__inline__
+void bsW ( EState* s, Int32 n, UInt32 v )
+{
+ bsNEEDW ( n );
+ s->bsBuff |= (v << (32 - s->bsLive - n));
+ s->bsLive += n;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutUInt32 ( EState* s, UInt32 u )
+{
+ bsW ( s, 8, (u >> 24) & 0xffL );
+ bsW ( s, 8, (u >> 16) & 0xffL );
+ bsW ( s, 8, (u >> 8) & 0xffL );
+ bsW ( s, 8, u & 0xffL );
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutUChar ( EState* s, UChar c )
+{
+ bsW( s, 8, (UInt32)c );
+}
+
+
+/*---------------------------------------------------*/
+/*--- The back end proper ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+static
+void makeMaps_e ( EState* s )
+{
+ Int32 i;
+ s->nInUse = 0;
+ for (i = 0; i < 256; i++)
+ if (s->inUse[i]) {
+ s->unseqToSeq[i] = s->nInUse;
+ s->nInUse++;
+ }
+}
+
+
+/*---------------------------------------------------*/
+static
+void generateMTFValues ( EState* s )
+{
+ UChar yy[256];
+ Int32 i, j;
+ Int32 zPend;
+ Int32 wr;
+ Int32 EOB;
+
+ /*
+ After sorting (eg, here),
+ s->arr1 [ 0 .. s->nblock-1 ] holds sorted order,
+ and
+ ((UChar*)s->arr2) [ 0 .. s->nblock-1 ]
+ holds the original block data.
+
+ The first thing to do is generate the MTF values,
+ and put them in
+ ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ].
+ Because there are strictly fewer or equal MTF values
+ than block values, ptr values in this area are overwritten
+ with MTF values only when they are no longer needed.
+
+ The final compressed bitstream is generated into the
+ area starting at
+ (UChar*) (&((UChar*)s->arr2)[s->nblock])
+
+ These storage aliases are set up in bzCompressInit(),
+ except for the last one, which is arranged in
+ compressBlock().
+ */
+ UInt32* ptr = s->ptr;
+ UChar* block = s->block;
+ UInt16* mtfv = s->mtfv;
+
+ makeMaps_e ( s );
+ EOB = s->nInUse+1;
+
+ for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0;
+
+ wr = 0;
+ zPend = 0;
+ for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i;
+
+ for (i = 0; i < s->nblock; i++) {
+ UChar ll_i;
+ AssertD ( wr <= i, "generateMTFValues(1)" );
+ j = ptr[i]-1; if (j < 0) j += s->nblock;
+ ll_i = s->unseqToSeq[block[j]];
+ AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" );
+
+ if (yy[0] == ll_i) {
+ zPend++;
+ } else {
+
+ if (zPend > 0) {
+ zPend--;
+ while (True) {
+ if (zPend & 1) {
+ mtfv[wr] = BZ_RUNB; wr++;
+ s->mtfFreq[BZ_RUNB]++;
+ } else {
+ mtfv[wr] = BZ_RUNA; wr++;
+ s->mtfFreq[BZ_RUNA]++;
+ }
+ if (zPend < 2) break;
+ zPend = (zPend - 2) / 2;
+ };
+ zPend = 0;
+ }
+ {
+ register UChar rtmp;
+ register UChar* ryy_j;
+ register UChar rll_i;
+ rtmp = yy[1];
+ yy[1] = yy[0];
+ ryy_j = &(yy[1]);
+ rll_i = ll_i;
+ while ( rll_i != rtmp ) {
+ register UChar rtmp2;
+ ryy_j++;
+ rtmp2 = rtmp;
+ rtmp = *ryy_j;
+ *ryy_j = rtmp2;
+ };
+ yy[0] = rtmp;
+ j = ryy_j - &(yy[0]);
+ mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++;
+ }
+
+ }
+ }
+
+ if (zPend > 0) {
+ zPend--;
+ while (True) {
+ if (zPend & 1) {
+ mtfv[wr] = BZ_RUNB; wr++;
+ s->mtfFreq[BZ_RUNB]++;
+ } else {
+ mtfv[wr] = BZ_RUNA; wr++;
+ s->mtfFreq[BZ_RUNA]++;
+ }
+ if (zPend < 2) break;
+ zPend = (zPend - 2) / 2;
+ };
+ zPend = 0;
+ }
+
+ mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++;
+
+ s->nMTF = wr;
+}
+
+
+/*---------------------------------------------------*/
+#define BZ_LESSER_ICOST 0
+#define BZ_GREATER_ICOST 15
+
+static
+void sendMTFValues ( EState* s )
+{
+ Int32 v, t, i, j, gs, ge, totc, bt, bc, iter;
+ Int32 nSelectors, alphaSize, minLen, maxLen, selCtr;
+ Int32 nGroups, nBytes;
+
+ /*--
+ UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ is a global since the decoder also needs it.
+
+ Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ are also globals only used in this proc.
+ Made global to keep stack frame size small.
+ --*/
+
+
+ UInt16 cost[BZ_N_GROUPS];
+ Int32 fave[BZ_N_GROUPS];
+
+ UInt16* mtfv = s->mtfv;
+
+ if (s->verbosity >= 3)
+ VPrintf3( " %d in block, %d after MTF & 1-2 coding, "
+ "%d+2 syms in use\n",
+ s->nblock, s->nMTF, s->nInUse );
+
+ alphaSize = s->nInUse+2;
+ for (t = 0; t < BZ_N_GROUPS; t++)
+ for (v = 0; v < alphaSize; v++)
+ s->len[t][v] = BZ_GREATER_ICOST;
+
+ /*--- Decide how many coding tables to use ---*/
+ AssertH ( s->nMTF > 0, 3001 );
+ if (s->nMTF < 200) nGroups = 2; else
+ if (s->nMTF < 600) nGroups = 3; else
+ if (s->nMTF < 1200) nGroups = 4; else
+ if (s->nMTF < 2400) nGroups = 5; else
+ nGroups = 6;
+
+ /*--- Generate an initial set of coding tables ---*/
+ {
+ Int32 nPart, remF, tFreq, aFreq;
+
+ nPart = nGroups;
+ remF = s->nMTF;
+ gs = 0;
+ while (nPart > 0) {
+ tFreq = remF / nPart;
+ ge = gs-1;
+ aFreq = 0;
+ while (aFreq < tFreq && ge < alphaSize-1) {
+ ge++;
+ aFreq += s->mtfFreq[ge];
+ }
+
+ if (ge > gs
+ && nPart != nGroups && nPart != 1
+ && ((nGroups-nPart) % 2 == 1)) {
+ aFreq -= s->mtfFreq[ge];
+ ge--;
+ }
+
+ if (s->verbosity >= 3)
+ VPrintf5( " initial group %d, [%d .. %d], "
+ "has %d syms (%4.1f%%)\n",
+ nPart, gs, ge, aFreq,
+ (100.0 * (float)aFreq) / (float)(s->nMTF) );
+
+ for (v = 0; v < alphaSize; v++)
+ if (v >= gs && v <= ge)
+ s->len[nPart-1][v] = BZ_LESSER_ICOST; else
+ s->len[nPart-1][v] = BZ_GREATER_ICOST;
+
+ nPart--;
+ gs = ge+1;
+ remF -= aFreq;
+ }
+ }
+
+ /*---
+ Iterate up to BZ_N_ITERS times to improve the tables.
+ ---*/
+ for (iter = 0; iter < BZ_N_ITERS; iter++) {
+
+ for (t = 0; t < nGroups; t++) fave[t] = 0;
+
+ for (t = 0; t < nGroups; t++)
+ for (v = 0; v < alphaSize; v++)
+ s->rfreq[t][v] = 0;
+
+ /*---
+ Set up an auxiliary length table which is used to fast-track
+ the common case (nGroups == 6).
+ ---*/
+ if (nGroups == 6) {
+ for (v = 0; v < alphaSize; v++) {
+ s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
+ s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
+ s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
+ }
+ }
+
+ nSelectors = 0;
+ totc = 0;
+ gs = 0;
+ while (True) {
+
+ /*--- Set group start & end marks. --*/
+ if (gs >= s->nMTF) break;
+ ge = gs + BZ_G_SIZE - 1;
+ if (ge >= s->nMTF) ge = s->nMTF-1;
+
+ /*--
+ Calculate the cost of this group as coded
+ by each of the coding tables.
+ --*/
+ for (t = 0; t < nGroups; t++) cost[t] = 0;
+
+ if (nGroups == 6 && 50 == ge-gs+1) {
+ /*--- fast track the common case ---*/
+ register UInt32 cost01, cost23, cost45;
+ register UInt16 icv;
+ cost01 = cost23 = cost45 = 0;
+
+# define BZ_ITER(nn) \
+ icv = mtfv[gs+(nn)]; \
+ cost01 += s->len_pack[icv][0]; \
+ cost23 += s->len_pack[icv][1]; \
+ cost45 += s->len_pack[icv][2]; \
+
+ BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4);
+ BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9);
+ BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
+ BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
+ BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
+ BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
+ BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
+ BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
+ BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
+ BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
+
+# undef BZ_ITER
+
+ cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
+ cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
+ cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
+
+ } else {
+ /*--- slow version which correctly handles all situations ---*/
+ for (i = gs; i <= ge; i++) {
+ UInt16 icv = mtfv[i];
+ for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv];
+ }
+ }
+
+ /*--
+ Find the coding table which is best for this group,
+ and record its identity in the selector table.
+ --*/
+ bc = 999999999; bt = -1;
+ for (t = 0; t < nGroups; t++)
+ if (cost[t] < bc) { bc = cost[t]; bt = t; };
+ totc += bc;
+ fave[bt]++;
+ s->selector[nSelectors] = bt;
+ nSelectors++;
+
+ /*--
+ Increment the symbol frequencies for the selected table.
+ --*/
+ if (nGroups == 6 && 50 == ge-gs+1) {
+ /*--- fast track the common case ---*/
+
+# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++
+
+ BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4);
+ BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9);
+ BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
+ BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
+ BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
+ BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
+ BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
+ BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
+ BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
+ BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
+
+# undef BZ_ITUR
+
+ } else {
+ /*--- slow version which correctly handles all situations ---*/
+ for (i = gs; i <= ge; i++)
+ s->rfreq[bt][ mtfv[i] ]++;
+ }
+
+ gs = ge+1;
+ }
+ if (s->verbosity >= 3) {
+ VPrintf2 ( " pass %d: size is %d, grp uses are ",
+ iter+1, totc/8 );
+ for (t = 0; t < nGroups; t++)
+ VPrintf1 ( "%d ", fave[t] );
+ VPrintf0 ( "\n" );
+ }
+
+ /*--
+ Recompute the tables based on the accumulated frequencies.
+ --*/
+ /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See
+ comment in huffman.c for details. */
+ for (t = 0; t < nGroups; t++)
+ BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]),
+ alphaSize, 17 /*20*/ );
+ }
+
+
+ AssertH( nGroups < 8, 3002 );
+ AssertH( nSelectors < 32768 &&
+ nSelectors <= (2 + (900000 / BZ_G_SIZE)),
+ 3003 );
+
+
+ /*--- Compute MTF values for the selectors. ---*/
+ {
+ UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
+ for (i = 0; i < nGroups; i++) pos[i] = i;
+ for (i = 0; i < nSelectors; i++) {
+ ll_i = s->selector[i];
+ j = 0;
+ tmp = pos[j];
+ while ( ll_i != tmp ) {
+ j++;
+ tmp2 = tmp;
+ tmp = pos[j];
+ pos[j] = tmp2;
+ };
+ pos[0] = tmp;
+ s->selectorMtf[i] = j;
+ }
+ };
+
+ /*--- Assign actual codes for the tables. --*/
+ for (t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (i = 0; i < alphaSize; i++) {
+ if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+ if (s->len[t][i] < minLen) minLen = s->len[t][i];
+ }
+ AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
+ AssertH ( !(minLen < 1), 3005 );
+ BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]),
+ minLen, maxLen, alphaSize );
+ }
+
+ /*--- Transmit the mapping table. ---*/
+ {
+ Bool inUse16[16];
+ for (i = 0; i < 16; i++) {
+ inUse16[i] = False;
+ for (j = 0; j < 16; j++)
+ if (s->inUse[i * 16 + j]) inUse16[i] = True;
+ }
+
+ nBytes = s->numZ;
+ for (i = 0; i < 16; i++)
+ if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0);
+
+ for (i = 0; i < 16; i++)
+ if (inUse16[i])
+ for (j = 0; j < 16; j++) {
+ if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0);
+ }
+
+ if (s->verbosity >= 3)
+ VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes );
+ }
+
+ /*--- Now the selectors. ---*/
+ nBytes = s->numZ;
+ bsW ( s, 3, nGroups );
+ bsW ( s, 15, nSelectors );
+ for (i = 0; i < nSelectors; i++) {
+ for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1);
+ bsW(s,1,0);
+ }
+ if (s->verbosity >= 3)
+ VPrintf1( "selectors %d, ", s->numZ-nBytes );
+
+ /*--- Now the coding tables. ---*/
+ nBytes = s->numZ;
+
+ for (t = 0; t < nGroups; t++) {
+ Int32 curr = s->len[t][0];
+ bsW ( s, 5, curr );
+ for (i = 0; i < alphaSize; i++) {
+ while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ };
+ while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ };
+ bsW ( s, 1, 0 );
+ }
+ }
+
+ if (s->verbosity >= 3)
+ VPrintf1 ( "code lengths %d, ", s->numZ-nBytes );
+
+ /*--- And finally, the block data proper ---*/
+ nBytes = s->numZ;
+ selCtr = 0;
+ gs = 0;
+ while (True) {
+ if (gs >= s->nMTF) break;
+ ge = gs + BZ_G_SIZE - 1;
+ if (ge >= s->nMTF) ge = s->nMTF-1;
+ AssertH ( s->selector[selCtr] < nGroups, 3006 );
+
+ if (nGroups == 6 && 50 == ge-gs+1) {
+ /*--- fast track the common case ---*/
+ UInt16 mtfv_i;
+ UChar* s_len_sel_selCtr
+ = &(s->len[s->selector[selCtr]][0]);
+ Int32* s_code_sel_selCtr
+ = &(s->code[s->selector[selCtr]][0]);
+
+# define BZ_ITAH(nn) \
+ mtfv_i = mtfv[gs+(nn)]; \
+ bsW ( s, \
+ s_len_sel_selCtr[mtfv_i], \
+ s_code_sel_selCtr[mtfv_i] )
+
+ BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4);
+ BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9);
+ BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
+ BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
+ BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
+ BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
+ BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
+ BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
+ BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
+ BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
+
+# undef BZ_ITAH
+
+ } else {
+ /*--- slow version which correctly handles all situations ---*/
+ for (i = gs; i <= ge; i++) {
+ bsW ( s,
+ s->len [s->selector[selCtr]] [mtfv[i]],
+ s->code [s->selector[selCtr]] [mtfv[i]] );
+ }
+ }
+
+
+ gs = ge+1;
+ selCtr++;
+ }
+ AssertH( selCtr == nSelectors, 3007 );
+
+ if (s->verbosity >= 3)
+ VPrintf1( "codes %d\n", s->numZ-nBytes );
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_compressBlock ( EState* s, Bool is_last_block )
+{
+ if (s->nblock > 0) {
+
+ BZ_FINALISE_CRC ( s->blockCRC );
+ s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
+ s->combinedCRC ^= s->blockCRC;
+ if (s->blockNo > 1) s->numZ = 0;
+
+ if (s->verbosity >= 2)
+ VPrintf4( " block %d: crc = 0x%08x, "
+ "combined CRC = 0x%08x, size = %d\n",
+ s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
+
+ BZ2_blockSort ( s );
+ }
+
+ s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]);
+
+ /*-- If this is the first block, create the stream header. --*/
+ if (s->blockNo == 1) {
+ BZ2_bsInitWrite ( s );
+ bsPutUChar ( s, BZ_HDR_B );
+ bsPutUChar ( s, BZ_HDR_Z );
+ bsPutUChar ( s, BZ_HDR_h );
+ bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) );
+ }
+
+ if (s->nblock > 0) {
+
+ bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 );
+ bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 );
+ bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 );
+
+ /*-- Now the block's CRC, so it is in a known place. --*/
+ bsPutUInt32 ( s, s->blockCRC );
+
+ /*--
+ Now a single bit indicating (non-)randomisation.
+ As of version 0.9.5, we use a better sorting algorithm
+ which makes randomisation unnecessary. So always set
+ the randomised bit to 'no'. Of course, the decoder
+ still needs to be able to handle randomised blocks
+ so as to maintain backwards compatibility with
+ older versions of bzip2.
+ --*/
+ bsW(s,1,0);
+
+ bsW ( s, 24, s->origPtr );
+ generateMTFValues ( s );
+ sendMTFValues ( s );
+ }
+
+
+ /*-- If this is the last block, add the stream trailer. --*/
+ if (is_last_block) {
+
+ bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 );
+ bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 );
+ bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
+ bsPutUInt32 ( s, s->combinedCRC );
+ if (s->verbosity >= 2)
+ VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC );
+ bsFinishWrite ( s );
+ }
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end compress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/dep/StormLib/src/bzip2/crctable.c b/dep/StormLib/src/bzip2/crctable.c
new file mode 100644
index 00000000000..215687b2c05
--- /dev/null
+++ b/dep/StormLib/src/bzip2/crctable.c
@@ -0,0 +1,104 @@
+
+/*-------------------------------------------------------------*/
+/*--- Table for doing CRCs ---*/
+/*--- crctable.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.5 of 10 December 2007
+ Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*--
+ I think this is an implementation of the AUTODIN-II,
+ Ethernet & FDDI 32-bit CRC standard. Vaguely derived
+ from code by Rob Warnock, in Section 51 of the
+ comp.compression FAQ.
+--*/
+
+UInt32 BZ2_crc32Table[256] = {
+
+ /*-- Ugly, innit? --*/
+
+ 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
+ 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
+ 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
+ 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
+ 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
+ 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
+ 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
+ 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
+ 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
+ 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
+ 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
+ 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
+ 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
+ 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
+ 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
+ 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
+ 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
+ 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
+ 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
+ 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
+ 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
+ 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
+ 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
+ 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
+ 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
+ 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
+ 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
+ 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
+ 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
+ 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
+ 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
+ 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
+ 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
+ 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
+ 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
+ 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
+ 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
+ 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
+ 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
+ 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
+ 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
+ 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
+ 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
+ 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
+ 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
+ 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
+ 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
+ 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
+ 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
+ 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
+ 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
+ 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
+ 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
+ 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
+ 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
+ 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
+ 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
+ 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
+ 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
+ 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
+ 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
+ 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
+ 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
+ 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
+};
+
+
+/*-------------------------------------------------------------*/
+/*--- end crctable.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/dep/StormLib/src/bzip2/decompress.c b/dep/StormLib/src/bzip2/decompress.c
new file mode 100644
index 00000000000..bba5e0fa36d
--- /dev/null
+++ b/dep/StormLib/src/bzip2/decompress.c
@@ -0,0 +1,626 @@
+
+/*-------------------------------------------------------------*/
+/*--- Decompression machinery ---*/
+/*--- decompress.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.5 of 10 December 2007
+ Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+static
+void makeMaps_d ( DState* s )
+{
+ Int32 i;
+ s->nInUse = 0;
+ for (i = 0; i < 256; i++)
+ if (s->inUse[i]) {
+ s->seqToUnseq[s->nInUse] = i;
+ s->nInUse++;
+ }
+}
+
+
+/*---------------------------------------------------*/
+#define RETURN(rrr) \
+ { retVal = rrr; goto save_state_and_return; };
+
+#define GET_BITS(lll,vvv,nnn) \
+ case lll: s->state = lll; \
+ while (True) { \
+ if (s->bsLive >= nnn) { \
+ UInt32 v; \
+ v = (s->bsBuff >> \
+ (s->bsLive-nnn)) & ((1 << nnn)-1); \
+ s->bsLive -= nnn; \
+ vvv = v; \
+ break; \
+ } \
+ if (s->strm->avail_in == 0) RETURN(BZ_OK); \
+ s->bsBuff \
+ = (s->bsBuff << 8) | \
+ ((UInt32) \
+ (*((UChar*)(s->strm->next_in)))); \
+ s->bsLive += 8; \
+ s->strm->next_in++; \
+ s->strm->avail_in--; \
+ s->strm->total_in_lo32++; \
+ if (s->strm->total_in_lo32 == 0) \
+ s->strm->total_in_hi32++; \
+ }
+
+#define GET_UCHAR(lll,uuu) \
+ GET_BITS(lll,uuu,8)
+
+#define GET_BIT(lll,uuu) \
+ GET_BITS(lll,uuu,1)
+
+/*---------------------------------------------------*/
+#define GET_MTF_VAL(label1,label2,lval) \
+{ \
+ if (groupPos == 0) { \
+ groupNo++; \
+ if (groupNo >= nSelectors) \
+ RETURN(BZ_DATA_ERROR); \
+ groupPos = BZ_G_SIZE; \
+ gSel = s->selector[groupNo]; \
+ gMinlen = s->minLens[gSel]; \
+ gLimit = &(s->limit[gSel][0]); \
+ gPerm = &(s->perm[gSel][0]); \
+ gBase = &(s->base[gSel][0]); \
+ } \
+ groupPos--; \
+ zn = gMinlen; \
+ GET_BITS(label1, zvec, zn); \
+ while (1) { \
+ if (zn > 20 /* the longest code */) \
+ RETURN(BZ_DATA_ERROR); \
+ if (zvec <= gLimit[zn]) break; \
+ zn++; \
+ GET_BIT(label2, zj); \
+ zvec = (zvec << 1) | zj; \
+ }; \
+ if (zvec - gBase[zn] < 0 \
+ || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \
+ RETURN(BZ_DATA_ERROR); \
+ lval = gPerm[zvec - gBase[zn]]; \
+}
+
+
+/*---------------------------------------------------*/
+Int32 BZ2_decompress ( DState* s )
+{
+ UChar uc;
+ Int32 retVal;
+ Int32 minLen, maxLen;
+ bz_stream* strm = s->strm;
+
+ /* stuff that needs to be saved/restored */
+ Int32 i;
+ Int32 j;
+ Int32 t;
+ Int32 alphaSize;
+ Int32 nGroups;
+ Int32 nSelectors;
+ Int32 EOB;
+ Int32 groupNo;
+ Int32 groupPos;
+ Int32 nextSym;
+ Int32 nblockMAX;
+ Int32 nblock;
+ Int32 es;
+ Int32 N;
+ Int32 curr;
+ Int32 zt;
+ Int32 zn;
+ Int32 zvec;
+ Int32 zj;
+ Int32 gSel;
+ Int32 gMinlen;
+ Int32* gLimit;
+ Int32* gBase;
+ Int32* gPerm;
+
+ if (s->state == BZ_X_MAGIC_1) {
+ /*initialise the save area*/
+ s->save_i = 0;
+ s->save_j = 0;
+ s->save_t = 0;
+ s->save_alphaSize = 0;
+ s->save_nGroups = 0;
+ s->save_nSelectors = 0;
+ s->save_EOB = 0;
+ s->save_groupNo = 0;
+ s->save_groupPos = 0;
+ s->save_nextSym = 0;
+ s->save_nblockMAX = 0;
+ s->save_nblock = 0;
+ s->save_es = 0;
+ s->save_N = 0;
+ s->save_curr = 0;
+ s->save_zt = 0;
+ s->save_zn = 0;
+ s->save_zvec = 0;
+ s->save_zj = 0;
+ s->save_gSel = 0;
+ s->save_gMinlen = 0;
+ s->save_gLimit = NULL;
+ s->save_gBase = NULL;
+ s->save_gPerm = NULL;
+ }
+
+ /*restore from the save area*/
+ i = s->save_i;
+ j = s->save_j;
+ t = s->save_t;
+ alphaSize = s->save_alphaSize;
+ nGroups = s->save_nGroups;
+ nSelectors = s->save_nSelectors;
+ EOB = s->save_EOB;
+ groupNo = s->save_groupNo;
+ groupPos = s->save_groupPos;
+ nextSym = s->save_nextSym;
+ nblockMAX = s->save_nblockMAX;
+ nblock = s->save_nblock;
+ es = s->save_es;
+ N = s->save_N;
+ curr = s->save_curr;
+ zt = s->save_zt;
+ zn = s->save_zn;
+ zvec = s->save_zvec;
+ zj = s->save_zj;
+ gSel = s->save_gSel;
+ gMinlen = s->save_gMinlen;
+ gLimit = s->save_gLimit;
+ gBase = s->save_gBase;
+ gPerm = s->save_gPerm;
+
+ retVal = BZ_OK;
+
+ switch (s->state) {
+
+ GET_UCHAR(BZ_X_MAGIC_1, uc);
+ if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC);
+
+ GET_UCHAR(BZ_X_MAGIC_2, uc);
+ if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC);
+
+ GET_UCHAR(BZ_X_MAGIC_3, uc)
+ if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC);
+
+ GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
+ if (s->blockSize100k < (BZ_HDR_0 + 1) ||
+ s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC);
+ s->blockSize100k -= BZ_HDR_0;
+
+ if (s->smallDecompress) {
+ s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
+ s->ll4 = BZALLOC(
+ ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar)
+ );
+ if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
+ } else {
+ s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
+ if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
+ }
+
+ GET_UCHAR(BZ_X_BLKHDR_1, uc);
+
+ if (uc == 0x17) goto endhdr_2;
+ if (uc != 0x31) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_2, uc);
+ if (uc != 0x41) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_3, uc);
+ if (uc != 0x59) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_4, uc);
+ if (uc != 0x26) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_5, uc);
+ if (uc != 0x53) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_6, uc);
+ if (uc != 0x59) RETURN(BZ_DATA_ERROR);
+
+ s->currBlockNo++;
+ if (s->verbosity >= 2)
+ VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo );
+
+ s->storedBlockCRC = 0;
+ GET_UCHAR(BZ_X_BCRC_1, uc);
+ s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_BCRC_2, uc);
+ s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_BCRC_3, uc);
+ s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_BCRC_4, uc);
+ s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+
+ GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
+
+ s->origPtr = 0;
+ GET_UCHAR(BZ_X_ORIGPTR_1, uc);
+ s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+ GET_UCHAR(BZ_X_ORIGPTR_2, uc);
+ s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+ GET_UCHAR(BZ_X_ORIGPTR_3, uc);
+ s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+
+ if (s->origPtr < 0)
+ RETURN(BZ_DATA_ERROR);
+ if (s->origPtr > 10 + 100000*s->blockSize100k)
+ RETURN(BZ_DATA_ERROR);
+
+ /*--- Receive the mapping table ---*/
+ for (i = 0; i < 16; i++) {
+ GET_BIT(BZ_X_MAPPING_1, uc);
+ if (uc == 1)
+ s->inUse16[i] = True; else
+ s->inUse16[i] = False;
+ }
+
+ for (i = 0; i < 256; i++) s->inUse[i] = False;
+
+ for (i = 0; i < 16; i++)
+ if (s->inUse16[i])
+ for (j = 0; j < 16; j++) {
+ GET_BIT(BZ_X_MAPPING_2, uc);
+ if (uc == 1) s->inUse[i * 16 + j] = True;
+ }
+ makeMaps_d ( s );
+ if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
+ alphaSize = s->nInUse+2;
+
+ /*--- Now the selectors ---*/
+ GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
+ if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR);
+ GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
+ if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
+ for (i = 0; i < nSelectors; i++) {
+ j = 0;
+ while (True) {
+ GET_BIT(BZ_X_SELECTOR_3, uc);
+ if (uc == 0) break;
+ j++;
+ if (j >= nGroups) RETURN(BZ_DATA_ERROR);
+ }
+ s->selectorMtf[i] = j;
+ }
+
+ /*--- Undo the MTF values for the selectors. ---*/
+ {
+ UChar pos[BZ_N_GROUPS], tmp, v;
+ for (v = 0; v < nGroups; v++) pos[v] = v;
+
+ for (i = 0; i < nSelectors; i++) {
+ v = s->selectorMtf[i];
+ tmp = pos[v];
+ while (v > 0) { pos[v] = pos[v-1]; v--; }
+ pos[0] = tmp;
+ s->selector[i] = tmp;
+ }
+ }
+
+ /*--- Now the coding tables ---*/
+ for (t = 0; t < nGroups; t++) {
+ GET_BITS(BZ_X_CODING_1, curr, 5);
+ for (i = 0; i < alphaSize; i++) {
+ while (True) {
+ if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
+ GET_BIT(BZ_X_CODING_2, uc);
+ if (uc == 0) break;
+ GET_BIT(BZ_X_CODING_3, uc);
+ if (uc == 0) curr++; else curr--;
+ }
+ s->len[t][i] = curr;
+ }
+ }
+
+ /*--- Create the Huffman decoding tables ---*/
+ for (t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (i = 0; i < alphaSize; i++) {
+ if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+ if (s->len[t][i] < minLen) minLen = s->len[t][i];
+ }
+ BZ2_hbCreateDecodeTables (
+ &(s->limit[t][0]),
+ &(s->base[t][0]),
+ &(s->perm[t][0]),
+ &(s->len[t][0]),
+ minLen, maxLen, alphaSize
+ );
+ s->minLens[t] = minLen;
+ }
+
+ /*--- Now the MTF values ---*/
+
+ EOB = s->nInUse+1;
+ nblockMAX = 100000 * s->blockSize100k;
+ groupNo = -1;
+ groupPos = 0;
+
+ for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
+
+ /*-- MTF init --*/
+ {
+ Int32 ii, jj, kk;
+ kk = MTFA_SIZE-1;
+ for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
+ for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
+ s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
+ kk--;
+ }
+ s->mtfbase[ii] = kk + 1;
+ }
+ }
+ /*-- end MTF init --*/
+
+ nblock = 0;
+ GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
+
+ while (True) {
+
+ if (nextSym == EOB) break;
+
+ if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
+
+ es = -1;
+ N = 1;
+ do {
+ if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
+ if (nextSym == BZ_RUNB) es = es + (1+1) * N;
+ N = N * 2;
+ GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
+ }
+ while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
+
+ es++;
+ uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
+ s->unzftab[uc] += es;
+
+ if (s->smallDecompress)
+ while (es > 0) {
+ if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+ s->ll16[nblock] = (UInt16)uc;
+ nblock++;
+ es--;
+ }
+ else
+ while (es > 0) {
+ if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+ s->tt[nblock] = (UInt32)uc;
+ nblock++;
+ es--;
+ };
+
+ continue;
+
+ } else {
+
+ if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+
+ /*-- uc = MTF ( nextSym-1 ) --*/
+ {
+ Int32 ii, jj, kk, pp, lno, off;
+ UInt32 nn;
+ nn = (UInt32)(nextSym - 1);
+
+ if (nn < MTFL_SIZE) {
+ /* avoid general-case expense */
+ pp = s->mtfbase[0];
+ uc = s->mtfa[pp+nn];
+ while (nn > 3) {
+ Int32 z = pp+nn;
+ s->mtfa[(z) ] = s->mtfa[(z)-1];
+ s->mtfa[(z)-1] = s->mtfa[(z)-2];
+ s->mtfa[(z)-2] = s->mtfa[(z)-3];
+ s->mtfa[(z)-3] = s->mtfa[(z)-4];
+ nn -= 4;
+ }
+ while (nn > 0) {
+ s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--;
+ };
+ s->mtfa[pp] = uc;
+ } else {
+ /* general case */
+ lno = nn / MTFL_SIZE;
+ off = nn % MTFL_SIZE;
+ pp = s->mtfbase[lno] + off;
+ uc = s->mtfa[pp];
+ while (pp > s->mtfbase[lno]) {
+ s->mtfa[pp] = s->mtfa[pp-1]; pp--;
+ };
+ s->mtfbase[lno]++;
+ while (lno > 0) {
+ s->mtfbase[lno]--;
+ s->mtfa[s->mtfbase[lno]]
+ = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
+ lno--;
+ }
+ s->mtfbase[0]--;
+ s->mtfa[s->mtfbase[0]] = uc;
+ if (s->mtfbase[0] == 0) {
+ kk = MTFA_SIZE-1;
+ for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
+ for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
+ s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
+ kk--;
+ }
+ s->mtfbase[ii] = kk + 1;
+ }
+ }
+ }
+ }
+ /*-- end uc = MTF ( nextSym-1 ) --*/
+
+ s->unzftab[s->seqToUnseq[uc]]++;
+ if (s->smallDecompress)
+ s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
+ s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]);
+ nblock++;
+
+ GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
+ continue;
+ }
+ }
+
+ /* Now we know what nblock is, we can do a better sanity
+ check on s->origPtr.
+ */
+ if (s->origPtr < 0 || s->origPtr >= nblock)
+ RETURN(BZ_DATA_ERROR);
+
+ /*-- Set up cftab to facilitate generation of T^(-1) --*/
+ s->cftab[0] = 0;
+ for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
+ for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
+ for (i = 0; i <= 256; i++) {
+ if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
+ /* s->cftab[i] can legitimately be == nblock */
+ RETURN(BZ_DATA_ERROR);
+ }
+ }
+
+ s->state_out_len = 0;
+ s->state_out_ch = 0;
+ BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
+ s->state = BZ_X_OUTPUT;
+ if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
+
+ if (s->smallDecompress) {
+
+ /*-- Make a copy of cftab, used in generation of T --*/
+ for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
+
+ /*-- compute the T vector --*/
+ for (i = 0; i < nblock; i++) {
+ uc = (UChar)(s->ll16[i]);
+ SET_LL(i, s->cftabCopy[uc]);
+ s->cftabCopy[uc]++;
+ }
+
+ /*-- Compute T^(-1) by pointer reversal on T --*/
+ i = s->origPtr;
+ j = GET_LL(i);
+ do {
+ Int32 tmp = GET_LL(j);
+ SET_LL(j, i);
+ i = j;
+ j = tmp;
+ }
+ while (i != s->origPtr);
+
+ s->tPos = s->origPtr;
+ s->nblock_used = 0;
+ if (s->blockRandomised) {
+ BZ_RAND_INIT_MASK;
+ BZ_GET_SMALL(s->k0); s->nblock_used++;
+ BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
+ } else {
+ BZ_GET_SMALL(s->k0); s->nblock_used++;
+ }
+
+ } else {
+
+ /*-- compute the T^(-1) vector --*/
+ for (i = 0; i < nblock; i++) {
+ uc = (UChar)(s->tt[i] & 0xff);
+ s->tt[s->cftab[uc]] |= (i << 8);
+ s->cftab[uc]++;
+ }
+
+ s->tPos = s->tt[s->origPtr] >> 8;
+ s->nblock_used = 0;
+ if (s->blockRandomised) {
+ BZ_RAND_INIT_MASK;
+ BZ_GET_FAST(s->k0); s->nblock_used++;
+ BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
+ } else {
+ BZ_GET_FAST(s->k0); s->nblock_used++;
+ }
+
+ }
+
+ RETURN(BZ_OK);
+
+
+
+ endhdr_2:
+
+ GET_UCHAR(BZ_X_ENDHDR_2, uc);
+ if (uc != 0x72) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_ENDHDR_3, uc);
+ if (uc != 0x45) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_ENDHDR_4, uc);
+ if (uc != 0x38) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_ENDHDR_5, uc);
+ if (uc != 0x50) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_ENDHDR_6, uc);
+ if (uc != 0x90) RETURN(BZ_DATA_ERROR);
+
+ s->storedCombinedCRC = 0;
+ GET_UCHAR(BZ_X_CCRC_1, uc);
+ s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_CCRC_2, uc);
+ s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_CCRC_3, uc);
+ s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_CCRC_4, uc);
+ s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+
+ s->state = BZ_X_IDLE;
+ RETURN(BZ_STREAM_END);
+
+ default: AssertH ( False, 4001 );
+ }
+
+ AssertH ( False, 4002 );
+
+ save_state_and_return:
+
+ s->save_i = i;
+ s->save_j = j;
+ s->save_t = t;
+ s->save_alphaSize = alphaSize;
+ s->save_nGroups = nGroups;
+ s->save_nSelectors = nSelectors;
+ s->save_EOB = EOB;
+ s->save_groupNo = groupNo;
+ s->save_groupPos = groupPos;
+ s->save_nextSym = nextSym;
+ s->save_nblockMAX = nblockMAX;
+ s->save_nblock = nblock;
+ s->save_es = es;
+ s->save_N = N;
+ s->save_curr = curr;
+ s->save_zt = zt;
+ s->save_zn = zn;
+ s->save_zvec = zvec;
+ s->save_zj = zj;
+ s->save_gSel = gSel;
+ s->save_gMinlen = gMinlen;
+ s->save_gLimit = gLimit;
+ s->save_gBase = gBase;
+ s->save_gPerm = gPerm;
+
+ return retVal;
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end decompress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/dep/StormLib/src/bzip2/huffman.c b/dep/StormLib/src/bzip2/huffman.c
new file mode 100644
index 00000000000..87e79e38af0
--- /dev/null
+++ b/dep/StormLib/src/bzip2/huffman.c
@@ -0,0 +1,205 @@
+
+/*-------------------------------------------------------------*/
+/*--- Huffman coding low-level stuff ---*/
+/*--- huffman.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.5 of 10 December 2007
+ Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*---------------------------------------------------*/
+#define WEIGHTOF(zz0) ((zz0) & 0xffffff00)
+#define DEPTHOF(zz1) ((zz1) & 0x000000ff)
+#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
+
+#define ADDWEIGHTS(zw1,zw2) \
+ (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \
+ (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
+
+#define UPHEAP(z) \
+{ \
+ Int32 zz, tmp; \
+ zz = z; tmp = heap[zz]; \
+ while (weight[tmp] < weight[heap[zz >> 1]]) { \
+ heap[zz] = heap[zz >> 1]; \
+ zz >>= 1; \
+ } \
+ heap[zz] = tmp; \
+}
+
+#define DOWNHEAP(z) \
+{ \
+ Int32 zz, yy, tmp; \
+ zz = z; tmp = heap[zz]; \
+ while (True) { \
+ yy = zz << 1; \
+ if (yy > nHeap) break; \
+ if (yy < nHeap && \
+ weight[heap[yy+1]] < weight[heap[yy]]) \
+ yy++; \
+ if (weight[tmp] < weight[heap[yy]]) break; \
+ heap[zz] = heap[yy]; \
+ zz = yy; \
+ } \
+ heap[zz] = tmp; \
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbMakeCodeLengths ( UChar *len,
+ Int32 *freq,
+ Int32 alphaSize,
+ Int32 maxLen )
+{
+ /*--
+ Nodes and heap entries run from 1. Entry 0
+ for both the heap and nodes is a sentinel.
+ --*/
+ Int32 nNodes, nHeap, n1, n2, i, j, k;
+ Bool tooLong;
+
+ Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ];
+ Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ];
+ Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ];
+
+ for (i = 0; i < alphaSize; i++)
+ weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+
+ while (True) {
+
+ nNodes = alphaSize;
+ nHeap = 0;
+
+ heap[0] = 0;
+ weight[0] = 0;
+ parent[0] = -2;
+
+ for (i = 1; i <= alphaSize; i++) {
+ parent[i] = -1;
+ nHeap++;
+ heap[nHeap] = i;
+ UPHEAP(nHeap);
+ }
+
+ AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 );
+
+ while (nHeap > 1) {
+ n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
+ n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
+ nNodes++;
+ parent[n1] = parent[n2] = nNodes;
+ weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
+ parent[nNodes] = -1;
+ nHeap++;
+ heap[nHeap] = nNodes;
+ UPHEAP(nHeap);
+ }
+
+ AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 );
+
+ tooLong = False;
+ for (i = 1; i <= alphaSize; i++) {
+ j = 0;
+ k = i;
+ while (parent[k] >= 0) { k = parent[k]; j++; }
+ len[i-1] = j;
+ if (j > maxLen) tooLong = True;
+ }
+
+ if (! tooLong) break;
+
+ /* 17 Oct 04: keep-going condition for the following loop used
+ to be 'i < alphaSize', which missed the last element,
+ theoretically leading to the possibility of the compressor
+ looping. However, this count-scaling step is only needed if
+ one of the generated Huffman code words is longer than
+ maxLen, which up to and including version 1.0.2 was 20 bits,
+ which is extremely unlikely. In version 1.0.3 maxLen was
+ changed to 17 bits, which has minimal effect on compression
+ ratio, but does mean this scaling step is used from time to
+ time, enough to verify that it works.
+
+ This means that bzip2-1.0.3 and later will only produce
+ Huffman codes with a maximum length of 17 bits. However, in
+ order to preserve backwards compatibility with bitstreams
+ produced by versions pre-1.0.3, the decompressor must still
+ handle lengths of up to 20. */
+
+ for (i = 1; i <= alphaSize; i++) {
+ j = weight[i] >> 8;
+ j = 1 + (j / 2);
+ weight[i] = j << 8;
+ }
+ }
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbAssignCodes ( Int32 *code,
+ UChar *length,
+ Int32 minLen,
+ Int32 maxLen,
+ Int32 alphaSize )
+{
+ Int32 n, vec, i;
+
+ vec = 0;
+ for (n = minLen; n <= maxLen; n++) {
+ for (i = 0; i < alphaSize; i++)
+ if (length[i] == n) { code[i] = vec; vec++; };
+ vec <<= 1;
+ }
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbCreateDecodeTables ( Int32 *limit,
+ Int32 *base,
+ Int32 *perm,
+ UChar *length,
+ Int32 minLen,
+ Int32 maxLen,
+ Int32 alphaSize )
+{
+ Int32 pp, i, j, vec;
+
+ pp = 0;
+ for (i = minLen; i <= maxLen; i++)
+ for (j = 0; j < alphaSize; j++)
+ if (length[j] == i) { perm[pp] = j; pp++; };
+
+ for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0;
+ for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
+
+ for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1];
+
+ for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0;
+ vec = 0;
+
+ for (i = minLen; i <= maxLen; i++) {
+ vec += (base[i+1] - base[i]);
+ limit[i] = vec-1;
+ vec <<= 1;
+ }
+ for (i = minLen + 1; i <= maxLen; i++)
+ base[i] = ((limit[i-1] + 1) << 1) - base[i];
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end huffman.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/dep/StormLib/src/bzip2/randtable.c b/dep/StormLib/src/bzip2/randtable.c
new file mode 100644
index 00000000000..068b76367bc
--- /dev/null
+++ b/dep/StormLib/src/bzip2/randtable.c
@@ -0,0 +1,84 @@
+
+/*-------------------------------------------------------------*/
+/*--- Table for randomising repetitive blocks ---*/
+/*--- randtable.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.5 of 10 December 2007
+ Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------*/
+Int32 BZ2_rNums[512] = {
+ 619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
+ 985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
+ 733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
+ 419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
+ 878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
+ 862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
+ 150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
+ 170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
+ 73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
+ 909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
+ 641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
+ 161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
+ 382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
+ 98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
+ 227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
+ 469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
+ 184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
+ 715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
+ 951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
+ 652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
+ 645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
+ 609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
+ 653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
+ 411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
+ 170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
+ 857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
+ 669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
+ 944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
+ 344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
+ 897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
+ 433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
+ 686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
+ 946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
+ 978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
+ 680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
+ 707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
+ 297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
+ 134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
+ 343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
+ 140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
+ 170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
+ 369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
+ 804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
+ 896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
+ 661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
+ 768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
+ 61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
+ 372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
+ 780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
+ 920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
+ 645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
+ 936, 638
+};
+
+
+/*-------------------------------------------------------------*/
+/*--- end randtable.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/dep/StormLib/src/huffman/huff.cpp b/dep/StormLib/src/huffman/huff.cpp
new file mode 100644
index 00000000000..66a46b3fa55
--- /dev/null
+++ b/dep/StormLib/src/huffman/huff.cpp
@@ -0,0 +1,1303 @@
+/*****************************************************************************/
+/* huffman.cpp Copyright (c) Ladislav Zezula 1998-2003 */
+/*---------------------------------------------------------------------------*/
+/* This module contains Huffmann (de)compression methods */
+/* */
+/* Authors : Ladislav Zezula (ladik@zezula.net) */
+/* ShadowFlare (BlakFlare@hotmail.com) */
+/* */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* xx.xx.xx 1.00 Lad The first version of dcmp.cpp */
+/* 03.05.03 1.00 Lad Added compression methods */
+/* 19.11.03 1.01 Dan Big endian handling */
+/* 08.12.03 2.01 Dan High-memory handling (> 0x80000000) */
+/*****************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+
+#include "huff.h"
+
+// Special for Mac - we have to know if normal pointer greater or less
+// than 0x80000000. This variable is used in the PTR_VALID and PTR_INVALID
+// macros
+static long mul = 1;
+
+#define PTR_VALID(ptr) (((LONG_PTR)(ptr) * mul) > 0)
+#define PTR_INVALID(ptr) (((LONG_PTR)(ptr) * mul) < 0)
+#define PTR_INVALID_OR_NULL(ptr) (((LONG_PTR)(ptr) * mul) <= 0)
+
+
+//-----------------------------------------------------------------------------
+// Methods of the THTreeItem struct
+
+// 1501DB70
+THTreeItem * THTreeItem::Call1501DB70(THTreeItem * pLast)
+{
+ if(pLast == NULL)
+ pLast = this + 1;
+ return pLast;
+}
+
+// Gets previous Huffman tree item (?)
+THTreeItem * THTreeItem::GetPrevItem(LONG_PTR value)
+{
+ if(PTR_INVALID(prev))
+ return PTR_NOT(prev);
+
+ if(value == -1 || PTR_INVALID(value))
+ value = (LONG_PTR)(this - next->prev);
+ return prev + value;
+
+// OLD VERSION
+// if(PTR_INT(value) < 0)
+// value = PTR_INT((item - item->next->prev));
+// return (THTreeItem *)((char *)prev + value);
+}
+
+// 1500F5E0
+void THTreeItem::ClearItemLinks()
+{
+ next = prev = NULL;
+}
+
+// 1500BC90
+void THTreeItem::RemoveItem()
+{
+ THTreeItem * pTemp; // EDX
+
+ if(next != NULL)
+ {
+ pTemp = prev;
+
+ if(PTR_INVALID_OR_NULL(pTemp))
+ pTemp = PTR_NOT(pTemp);
+ else
+ pTemp += (this - next->prev);
+
+ pTemp->next = next;
+ next->prev = prev;
+ next = prev = NULL;
+ }
+}
+
+/*
+// OLD VERSION : Removes item from the tree (?)
+static void RemoveItem(THTreeItem * item)
+{
+ THTreeItem * next = item->next; // ESI
+ THTreeItem * prev = item->prev; // EDX
+
+ if(next == NULL)
+ return;
+
+ if(PTR_INT(prev) < 0)
+ prev = PTR_NOT(prev);
+ else
+ // ??? usually item == next->prev, so what is it ?
+ prev = (THTreeItem *)((unsigned char *)prev + (unsigned long)((unsigned char *)item - (unsigned char *)(next->prev)));
+
+ // Remove HTree item from the chain
+ prev->next = next; // Sets the 'first' pointer
+ next->prev = item->prev;
+
+ // Invalidate pointers
+ item->next = NULL;
+ item->prev = NULL;
+}
+*/
+
+//-----------------------------------------------------------------------------
+// TOutputStream functions
+
+void TOutputStream::PutBits(unsigned long dwBuff, unsigned int nPutBits)
+{
+ dwBitBuff |= (dwBuff << nBits);
+ nBits += nPutBits;
+
+ // Flush completed bytes
+ while(nBits >= 8)
+ {
+ if(cbOutSize != 0)
+ {
+ *pbOutPos++ = (unsigned char)dwBitBuff;
+ cbOutSize--;
+ }
+
+ dwBitBuff >>= 8;
+ nBits -= 8;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// TInputStream functions
+
+// Gets one bit from input stream
+unsigned long TInputStream::GetBit()
+{
+ unsigned long dwOneBit = 0;
+
+ // Ensure that the input stream is reloaded, if there are no bits left
+ if(BitCount == 0)
+ {
+ // Refill the bit buffer
+ BitBuffer = *pbInBuffer++;
+ BitCount = 8;
+ }
+
+ // Copy the bit from bit buffer to the variable
+ dwOneBit = (BitBuffer & 0x01);
+ BitBuffer >>= 1;
+ BitCount--;
+
+ return dwOneBit;
+}
+
+// Gets 7 bits from the stream. DOES NOT remove the bits from input stream
+unsigned long TInputStream::Get7Bits()
+{
+ unsigned long dwReloadByte = 0;
+
+ // If there is not enough bits to get the value,
+ // we have to add 8 more bits from the input buffer
+ if(BitCount < 7)
+ {
+ dwReloadByte = *pbInBuffer++;
+ BitBuffer |= dwReloadByte << BitCount;
+ BitCount += 8;
+ }
+
+ // Return the first available 7 bits. DO NOT remove them from the input stream
+ return (BitBuffer & 0x7F);
+}
+
+// Gets the whole byte from the input stream.
+unsigned long TInputStream::Get8Bits()
+{
+ unsigned long dwReloadByte = 0;
+ unsigned long dwOneByte = 0;
+
+ // If there is not enough bits to get the value,
+ // we have to add 8 more bits from the input buffer
+ if(BitCount < 8)
+ {
+ dwReloadByte = *pbInBuffer++;
+ BitBuffer |= dwReloadByte << BitCount;
+ BitCount += 8;
+ }
+
+ // Return the lowest 8 its
+ dwOneByte = (BitBuffer & 0xFF);
+ BitBuffer >>= 8;
+ BitCount -= 8;
+ return dwOneByte;
+}
+
+void TInputStream::SkipBits(unsigned int dwBitsToSkip)
+{
+ unsigned long dwReloadByte = 0;
+
+ // If there is not enough bits in the buffer,
+ // we have to add 8 more bits from the input buffer
+ if(BitCount < dwBitsToSkip)
+ {
+ dwReloadByte = *pbInBuffer++;
+ BitBuffer |= dwReloadByte << BitCount;
+ BitCount += 8;
+ }
+
+ // Skip the remaining bits
+ BitBuffer >>= dwBitsToSkip;
+ BitCount -= dwBitsToSkip;
+}
+
+//-----------------------------------------------------------------------------
+// Functions for huffmann tree items
+
+// Inserts item into the tree (?)
+static void InsertItem(THTreeItem ** itemPtr, THTreeItem * item, unsigned long nWhere, THTreeItem * item2)
+{
+ THTreeItem * next = item->next; // EDI - next to the first item
+ THTreeItem * prev = item->prev; // ESI - prev to the first item
+ THTreeItem * prev2; // Pointer to previous item
+ LONG_PTR next2; // Pointer to the next item
+
+ // The same code like in RemoveItem(item);
+ if(next != 0) // If the first item already has next one
+ {
+ if(PTR_INVALID(prev))
+ prev = PTR_NOT(prev);
+ else
+ prev += (item - next->prev);
+
+ // 150083C1
+ // Remove the item from the tree
+ prev->next = next;
+ next->prev = prev;
+
+ // Invalidate 'prev' and 'next' pointer
+ item->next = 0;
+ item->prev = 0;
+ }
+
+ if(item2 == NULL) // EDX - If the second item is not entered,
+ item2 = PTR_PTR(&itemPtr[1]); // take the first tree item
+
+ switch(nWhere)
+ {
+ case SWITCH_ITEMS : // Switch the two items
+ item->next = item2->next; // item2->next (Pointer to pointer to first)
+ item->prev = item2->next->prev;
+ item2->next->prev = item;
+ item2->next = item; // Set the first item
+ return;
+
+ case INSERT_ITEM: // Insert as the last item
+ item->next = item2; // Set next item (or pointer to pointer to first item)
+ item->prev = item2->prev; // Set prev item (or last item in the tree)
+
+ next2 = PTR_INT(itemPtr[0]);// Usually NULL
+ prev2 = item2->prev; // Prev item to the second (or last tree item)
+
+ if(PTR_INVALID(prev2))
+ {
+ if(prev != NULL)
+ {
+ prev2 = PTR_NOT(prev);
+ if(prev2 != NULL)
+ {
+ prev2->next = item;
+ item2->prev = item; // Next after last item
+ }
+ }
+ return;
+ }
+
+ if(PTR_INVALID(next2))
+ next2 = (LONG_PTR)(item2 - item2->next->prev);
+// next2 = (THTreeItem *)(unsigned long)((unsigned char *)item2 - (unsigned char *)(item2->next->prev));
+
+// prev2 = (THTreeItem *)((char *)prev2 + (unsigned long)next2);// ???
+ prev2 += next2;
+ prev2->next = item;
+ item2->prev = item; // Set the next/last item
+ return;
+
+ default:
+ return;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// THuffmannTree class functions
+
+THuffmannTree::THuffmannTree()
+{
+ // We have to check if the "this" pointer is less than zero
+ if((LONG_PTR)this < 0)
+ mul = -1;
+}
+
+void THuffmannTree::InitTree(bool bCompression)
+{
+ THTreeItem * pItem;
+ unsigned int nCount;
+
+ // Clear links for all the items in the tree
+ for(pItem = items0008, nCount = 0x203; nCount != 0; pItem++, nCount--)
+ pItem->ClearItemLinks();
+
+ pItem3050 = NULL;
+ pItem3054 = PTR_PTR(&pItem3054);
+ pItem3058 = PTR_NOT(pItem3054);
+
+ pItem305C = NULL;
+ pFirst = PTR_PTR(&pFirst);
+ pLast = PTR_NOT(pFirst);
+
+ offs0004 = 1;
+ nItems = 0;
+
+ // Clear all TQDecompress items. Do this only if preparing for decompression
+ if(bCompression == false)
+ {
+ for(nCount = 0; nCount < sizeof(qd3474) / sizeof(TQDecompress); nCount++)
+ qd3474[nCount].offs00 = 0;
+ }
+}
+
+// Builds Huffman tree. Called with the first 8 bits loaded from input stream
+void THuffmannTree::BuildTree(unsigned int nCmpType)
+{
+ unsigned long maxByte; // [ESP+10] - The greatest character found in table
+ THTreeItem ** itemPtr; // [ESP+14] - Pointer to Huffman tree item pointer array
+ unsigned char * byteArray; // [ESP+1C] - Pointer to unsigned char in Table1502A630
+ THTreeItem * child1;
+ unsigned long i; // egcs in linux doesn't like multiple for loops without an explicit i
+
+ // Loop while pointer has a valid value
+ while(PTR_VALID(pLast)) // ESI - Last entry
+ {
+ THTreeItem * temp; // EAX
+
+ if(pLast->next != NULL) // ESI->next
+ pLast->RemoveItem();
+ // EDI = &offs3054
+ pItem3058 = PTR_PTR(&pItem3054); // [EDI+4]
+ pLast->prev = pItem3058; // EAX
+
+ temp = PTR_PTR(&pItem3054)->GetPrevItem(PTR_INT(&pItem3050));
+
+ temp->next = pLast;
+ pItem3054 = pLast;
+ }
+
+ // Clear all pointers in HTree item array
+ memset(items306C, 0, sizeof(items306C));
+
+ maxByte = 0; // Greatest character found init to zero.
+ itemPtr = (THTreeItem **)&items306C; // Pointer to current entry in HTree item pointer array
+
+ // Ensure we have low 8 bits only
+ nCmpType &= 0xFF;
+ byteArray = Table1502A630 + nCmpType * 258; // EDI also
+
+ for(i = 0; i < 0x100; i++, itemPtr++)
+ {
+ THTreeItem * item = pItem3058; // Item to be created
+ THTreeItem * pItem3 = pItem3058;
+ unsigned char oneByte = byteArray[i];
+
+ // Skip all the bytes which are zero.
+ if(byteArray[i] == 0)
+ continue;
+
+ // If not valid pointer, take the first available item in the array
+ if(PTR_INVALID_OR_NULL(item))
+ item = &items0008[nItems++];
+
+ // Insert this item as the top of the tree
+ InsertItem(&pItem305C, item, SWITCH_ITEMS, NULL);
+
+ item->parent = NULL; // Invalidate child and parent
+ item->child = NULL;
+ *itemPtr = item; // Store pointer into pointer array
+
+ item->dcmpByte = i; // Store counter
+ item->byteValue = oneByte; // Store byte value
+ if(oneByte >= maxByte)
+ {
+ maxByte = oneByte;
+ continue;
+ }
+
+ // Find the first item which has byte value greater than current one byte
+ if(PTR_VALID(pItem3 = pLast)) // EDI - Pointer to the last item
+ {
+ // 15006AF7
+ if(pItem3 != NULL)
+ {
+ do // 15006AFB
+ {
+ if(pItem3->byteValue >= oneByte)
+ goto _15006B09;
+ pItem3 = pItem3->prev;
+ }
+ while(PTR_VALID(pItem3));
+ }
+ }
+ pItem3 = NULL;
+
+ // 15006B09
+ _15006B09:
+ if(item->next != NULL)
+ item->RemoveItem();
+
+ // 15006B15
+ if(pItem3 == NULL)
+ pItem3 = PTR_PTR(&pFirst);
+
+ // 15006B1F
+ item->next = pItem3->next;
+ item->prev = pItem3->next->prev;
+ pItem3->next->prev = item;
+ pItem3->next = item;
+ }
+
+ // 15006B4A
+ for(; i < 0x102; i++)
+ {
+ THTreeItem ** itemPtr = &items306C[i]; // EDI
+
+ // 15006B59
+ THTreeItem * item = pItem3058; // ESI
+ if(PTR_INVALID_OR_NULL(item))
+ item = &items0008[nItems++];
+
+ InsertItem(&pItem305C, item, INSERT_ITEM, NULL);
+
+ // 15006B89
+ item->dcmpByte = i;
+ item->byteValue = 1;
+ item->parent = NULL;
+ item->child = NULL;
+ *itemPtr++ = item;
+ }
+
+ // 15006BAA
+ if(PTR_VALID(child1 = pLast)) // EDI - last item (first child to item
+ {
+ THTreeItem * child2; // EBP
+ THTreeItem * item; // ESI
+
+ // 15006BB8
+ while(PTR_VALID(child2 = child1->prev))
+ {
+ if(PTR_INVALID_OR_NULL(item = pItem3058))
+ item = &items0008[nItems++];
+
+ // 15006BE3
+ InsertItem(&pItem305C, item, SWITCH_ITEMS, NULL);
+
+ // 15006BF3
+ item->parent = NULL;
+ item->child = NULL;
+
+ //EDX = child2->byteValue + child1->byteValue;
+ //EAX = child1->byteValue;
+ //ECX = maxByte; // The greatest character (0xFF usually)
+
+ item->byteValue = child1->byteValue + child2->byteValue; // 0x02
+ item->child = child1; // Prev item in the
+ child1->parent = item;
+ child2->parent = item;
+
+ // EAX = item->byteValue;
+ if(item->byteValue >= maxByte)
+ maxByte = item->byteValue;
+ else
+ {
+ THTreeItem * pItem2 = child2->prev; // EDI
+
+ // 15006C2D
+ while(PTR_VALID(pItem2))
+ {
+ if(pItem2->byteValue >= item->byteValue)
+ goto _15006C3B;
+ pItem2 = pItem2->prev;
+ }
+ pItem2 = NULL;
+
+ _15006C3B:
+ if(item->next != 0)
+ {
+ THTreeItem * temp4 = item->GetPrevItem(-1);
+
+ temp4->next = item->next; // The first item changed
+ item->next->prev = item->prev; // First->prev changed to negative value
+ item->next = NULL;
+ item->prev = NULL;
+ }
+
+ // 15006C62
+ if(pItem2 == NULL)
+ pItem2 = PTR_PTR(&pFirst);
+
+ item->next = pItem2->next; // Set item with 0x100 byte value
+ item->prev = pItem2->next->prev; // Set item with 0x17 byte value
+ pItem2->next->prev = item; // Changed prev of item with
+ pItem2->next = item;
+ }
+
+ // 15006C7B
+ if(PTR_INVALID_OR_NULL(child1 = child2->prev))
+ break;
+ }
+ }
+ // 15006C88
+ offs0004 = 1;
+}
+/*
+// Modifies Huffman tree. Adds new item and changes
+void THuffmannTree::ModifyTree(unsigned long dwIndex)
+{
+ THTreeItem * pItem1 = pItem3058; // ESI
+ THTreeItem * pSaveLast = (PTR_INT(pLast) <= 0) ? NULL : pLast; // EBX
+ THTreeItem * temp; // EAX
+
+ // Prepare the first item to insert to the tree
+ if(PTR_INT(pItem1) <= 0)
+ pItem1 = &items0008[nItems++];
+
+ // If item has any next item, remove it from the chain
+ if(pItem1->next != NULL)
+ {
+ THTreeItem * temp = pItem1->GetPrevItem(-1); // EAX
+
+ temp->next = pItem1->next;
+ pItem1->next->prev = pItem1->prev;
+ pItem1->next = NULL;
+ pItem1->prev = NULL;
+ }
+
+ pItem1->next = PTR_PTR(&pFirst);
+ pItem1->prev = pLast;
+ temp = pItem1->next->GetPrevItem(PTR_INT(pItem305C));
+
+ // 150068E9
+ temp->next = pItem1;
+ pLast = pItem1;
+
+ pItem1->parent = NULL;
+ pItem1->child = NULL;
+
+ // 150068F6
+ pItem1->dcmpByte = pSaveLast->dcmpByte; // Copy item index
+ pItem1->byteValue = pSaveLast->byteValue; // Copy item byte value
+ pItem1->parent = pSaveLast; // Set parent to last item
+ items306C[pSaveLast->dcmpByte] = pItem1; // Insert item into item pointer array
+
+ // Prepare the second item to insert into the tree
+ if(PTR_INT((pItem1 = pItem3058)) <= 0)
+ pItem1 = &items0008[nItems++];
+
+ // 1500692E
+ if(pItem1->next != NULL)
+ {
+ temp = pItem1->GetPrevItem(-1); // EAX
+
+ temp->next = pItem1->next;
+ pItem1->next->prev = pItem1->prev;
+ pItem1->next = NULL;
+ pItem1->prev = NULL;
+ }
+ // 1500694C
+ pItem1->next = PTR_PTR(&pFirst);
+ pItem1->prev = pLast;
+ temp = pItem1->next->GetPrevItem(PTR_INT(pItem305C));
+
+ // 15006968
+ temp->next = pItem1;
+ pLast = pItem1;
+
+ // 1500696E
+ pItem1->child = NULL;
+ pItem1->dcmpByte = dwIndex;
+ pItem1->byteValue = 0;
+ pItem1->parent = pSaveLast;
+ pSaveLast->child = pItem1;
+ items306C[dwIndex] = pItem1;
+
+ do
+ {
+ THTreeItem * pItem2 = pItem1;
+ THTreeItem * pItem3;
+ unsigned long byteValue;
+
+ // 15006993
+ byteValue = ++pItem1->byteValue;
+
+ // Pass through all previous which have its value greater than byteValue
+ while(PTR_INT((pItem3 = pItem2->prev)) > 0) // EBX
+ {
+ if(pItem3->byteValue >= byteValue)
+ goto _150069AE;
+
+ pItem2 = pItem2->prev;
+ }
+ // 150069AC
+ pItem3 = NULL;
+
+ _150069AE:
+ if(pItem2 == pItem1)
+ continue;
+
+ // 150069B2
+ // Switch pItem2 with item
+ InsertItem(&pItem305C, pItem2, SWITCH_ITEMS, pItem1);
+ InsertItem(&pItem305C, pItem1, SWITCH_ITEMS, pItem3);
+
+ // 150069D0
+ // Switch parents of pItem1 and pItem2
+ temp = pItem2->parent->child;
+ if(pItem1 == pItem1->parent->child)
+ pItem1->parent->child = pItem2;
+
+ if(pItem2 == temp)
+ pItem2->parent->child = pItem1;
+
+ // 150069ED
+ // Switch parents of pItem1 and pItem3
+ temp = pItem1->parent;
+ pItem1 ->parent = pItem2->parent;
+ pItem2->parent = temp;
+ offs0004++;
+ }
+ while(PTR_INT((pItem1 = pItem1->parent)) > 0);
+}
+
+void THuffmannTree::UninitTree()
+{
+ while(PTR_INT(pLast) > 0)
+ {
+ pItem = pItem305C->Call1501DB70(pLast);
+ pItem->RemoveItem();
+ }
+
+ for(pItem = pFirst; PTR_INT(pItem3058) > 0; pItem = pItem3058)
+ pItem->RemoveItem();
+ PTR_PTR(&pItem3054)->RemoveItem();
+
+ for(pItem = items0008 + 0x203, nCount = 0x203; nCount != 0; nCount--)
+ {
+ pItem--;
+ pItem->RemoveItem();
+ pItem->RemoveItem();
+ }
+}
+*/
+
+THTreeItem * THuffmannTree::Call1500E740(unsigned int nValue)
+{
+ THTreeItem * pItem1 = pItem3058; // EDX
+ THTreeItem * pItem2; // EAX
+ THTreeItem * pNext;
+ THTreeItem * pPrev;
+ THTreeItem ** ppItem;
+
+ if(PTR_INVALID_OR_NULL(pItem1) || (pItem2 = pItem1) == NULL)
+ {
+ if((pItem2 = &items0008[nItems++]) != NULL)
+ pItem1 = pItem2;
+ else
+ pItem1 = pFirst;
+ }
+ else
+ pItem1 = pItem2;
+
+ pNext = pItem1->next;
+ if(pNext != NULL)
+ {
+ pPrev = pItem1->prev;
+ if(PTR_INVALID_OR_NULL(pPrev))
+ pPrev = PTR_NOT(pPrev);
+ else
+ pPrev += (pItem1 - pItem1->next->prev);
+
+ pPrev->next = pNext;
+ pNext->prev = pPrev;
+ pItem1->next = NULL;
+ pItem1->prev = NULL;
+ }
+
+ ppItem = &pFirst; // esi
+ if(nValue > 1)
+ {
+ // ecx = pFirst->next;
+ pItem1->next = *ppItem;
+ pItem1->prev = (*ppItem)->prev;
+
+ (*ppItem)->prev = pItem2;
+ *ppItem = pItem1;
+
+ pItem2->parent = NULL;
+ pItem2->child = NULL;
+ }
+ else
+ {
+ pItem1->next = (THTreeItem *)ppItem;
+ pItem1->prev = ppItem[1];
+ // edi = pItem305C;
+ pPrev = ppItem[1]; // ecx
+ if(PTR_INVALID_OR_NULL(pPrev))
+ {
+ pPrev = PTR_NOT(pPrev);
+ pPrev->next = pItem1;
+ pPrev->prev = pItem2;
+
+ pItem2->parent = NULL;
+ pItem2->child = NULL;
+ }
+ else
+ {
+ if(PTR_INVALID(pItem305C))
+ pPrev += (THTreeItem *)ppItem - (*ppItem)->prev;
+ else
+ pPrev += PTR_INT(pItem305C);
+
+ pPrev->next = pItem1;
+ ppItem[1] = pItem2;
+ pItem2->parent = NULL;
+ pItem2->child = NULL;
+ }
+ }
+ return pItem2;
+}
+
+void THuffmannTree::Call1500E820(THTreeItem * pItem)
+{
+ THTreeItem * pItem1; // edi
+ THTreeItem * pItem2 = NULL; // eax
+ THTreeItem * pItem3; // edx
+ THTreeItem * pPrev; // ebx
+
+ for(; pItem != NULL; pItem = pItem->parent)
+ {
+ pItem->byteValue++;
+
+ for(pItem1 = pItem; ; pItem1 = pPrev)
+ {
+ pPrev = pItem1->prev;
+ if(PTR_INVALID_OR_NULL(pPrev))
+ {
+ pPrev = NULL;
+ break;
+ }
+
+ if(pPrev->byteValue >= pItem->byteValue)
+ break;
+ }
+
+ if(pItem1 == pItem)
+ continue;
+
+ if(pItem1->next != NULL)
+ {
+ pItem2 = pItem1->GetPrevItem(-1);
+ pItem2->next = pItem1->next;
+ pItem1->next->prev = pItem1->prev;
+ pItem1->next = NULL;
+ pItem1->prev = NULL;
+ }
+
+ pItem2 = pItem->next;
+ pItem1->next = pItem2;
+ pItem1->prev = pItem2->prev;
+ pItem2->prev = pItem1;
+ pItem->next = pItem1;
+ if((pItem2 = pItem1) != NULL)
+ {
+ pItem2 = pItem->GetPrevItem(-1);
+ pItem2->next = pItem->next;
+ pItem->next->prev = pItem->prev;
+ pItem->next = NULL;
+ pItem->prev = NULL;
+ }
+
+ if(pPrev == NULL)
+ pPrev = PTR_PTR(&pFirst);
+
+ pItem2 = pPrev->next;
+ pItem->next = pItem2;
+ pItem->prev = pItem2->prev;
+ pItem2->prev = pItem;
+ pPrev->next = pItem;
+
+ pItem3 = pItem1->parent->child;
+ pItem2 = pItem->parent;
+ if(pItem2->child == pItem)
+ pItem2->child = pItem1;
+ if(pItem3 == pItem1)
+ pItem1->parent->child = pItem;
+
+ pItem2 = pItem->parent;
+ pItem->parent = pItem1->parent;
+ pItem1->parent = pItem2;
+ offs0004++;
+ }
+}
+
+// 1500E920
+unsigned int THuffmannTree::DoCompression(TOutputStream * os, unsigned char * pbInBuffer, int nInLength, int nCmpType)
+{
+ THTreeItem * pItem1;
+ THTreeItem * pItem2;
+ THTreeItem * pItem3;
+ THTreeItem * pTemp;
+ unsigned long dwBitBuff;
+ unsigned int nBits;
+ unsigned int nBit;
+
+ BuildTree(nCmpType);
+ bIsCmp0 = (nCmpType == 0);
+
+ // Store the compression type into output buffer
+ os->dwBitBuff |= (nCmpType << os->nBits);
+ os->nBits += 8;
+
+ // Flush completed bytes
+ while(os->nBits >= 8)
+ {
+ if(os->cbOutSize != 0)
+ {
+ *os->pbOutPos++ = (unsigned char)os->dwBitBuff;
+ os->cbOutSize--;
+ }
+
+ os->dwBitBuff >>= 8;
+ os->nBits -= 8;
+ }
+
+ for(; nInLength != 0; nInLength--)
+ {
+ unsigned char bOneByte = *pbInBuffer++;
+
+ if((pItem1 = items306C[bOneByte]) == NULL)
+ {
+ pItem2 = items306C[0x101]; // ecx
+ pItem3 = pItem2->parent; // eax
+ dwBitBuff = 0;
+ nBits = 0;
+
+ for(; pItem3 != NULL; pItem3 = pItem3->parent)
+ {
+ nBit = (pItem3->child != pItem2) ? 1 : 0;
+ dwBitBuff = (dwBitBuff << 1) | nBit;
+ nBits++;
+ pItem2 = pItem3;
+ }
+ os->PutBits(dwBitBuff, nBits);
+
+ // Store the loaded byte into output stream
+ os->dwBitBuff |= (bOneByte << os->nBits);
+ os->nBits += 8;
+
+ // Flush the whole byte(s)
+ while(os->nBits >= 8)
+ {
+ if(os->cbOutSize != 0)
+ {
+ *os->pbOutPos++ = (unsigned char)os->dwBitBuff;
+ os->cbOutSize--;
+ }
+ os->dwBitBuff >>= 8;
+ os->nBits -= 8;
+ }
+
+ pItem1 = (PTR_INVALID_OR_NULL(pLast)) ? NULL : pLast;
+ pItem2 = Call1500E740(1);
+ pItem2->dcmpByte = pItem1->dcmpByte;
+ pItem2->byteValue = pItem1->byteValue;
+ pItem2->parent = pItem1;
+ items306C[pItem2->dcmpByte] = pItem2;
+
+ pItem2 = Call1500E740(1);
+ pItem2->dcmpByte = bOneByte;
+ pItem2->byteValue = 0;
+ pItem2->parent = pItem1;
+ items306C[pItem2->dcmpByte] = pItem2;
+ pItem1->child = pItem2;
+
+ Call1500E820(pItem2);
+
+ if(bIsCmp0 != 0)
+ {
+ Call1500E820(items306C[bOneByte]);
+ continue;
+ }
+
+ for(pItem1 = items306C[bOneByte]; pItem1 != NULL; pItem1 = pItem1->parent)
+ {
+ pItem1->byteValue++;
+ pItem2 = pItem1;
+
+ for(;;)
+ {
+ pItem3 = pItem2->prev;
+ if(PTR_INVALID_OR_NULL(pItem3))
+ {
+ pItem3 = NULL;
+ break;
+ }
+ if(pItem3->byteValue >= pItem1->byteValue)
+ break;
+ pItem2 = pItem3;
+ }
+
+ if(pItem2 != pItem1)
+ {
+ InsertItem(&pItem305C, pItem2, SWITCH_ITEMS, pItem1);
+ InsertItem(&pItem305C, pItem1, SWITCH_ITEMS, pItem3);
+
+ pItem3 = pItem2->parent->child;
+ if(pItem1->parent->child == pItem1)
+ pItem1->parent->child = pItem2;
+
+ if(pItem3 == pItem2)
+ pItem2->parent->child = pItem1;
+
+ pTemp = pItem1->parent;
+ pItem1->parent = pItem2->parent;
+ pItem2->parent = pTemp;
+ offs0004++;
+ }
+ }
+ }
+// 1500EB62
+ else
+ {
+ dwBitBuff = 0;
+ nBits = 0;
+ for(pItem2 = pItem1->parent; pItem2 != NULL; pItem2 = pItem2->parent)
+ {
+ nBit = (pItem2->child != pItem1) ? 1 : 0;
+ dwBitBuff = (dwBitBuff << 1) | nBit;
+ nBits++;
+ pItem1 = pItem2;
+ }
+ os->PutBits(dwBitBuff, nBits);
+ }
+
+// 1500EB98
+ if(bIsCmp0 != 0)
+ Call1500E820(items306C[bOneByte]); // 1500EB9D
+// 1500EBAF
+ } // for(; nInLength != 0; nInLength--)
+
+// 1500EBB8
+ pItem1 = items306C[0x100];
+ dwBitBuff = 0;
+ nBits = 0;
+ for(pItem2 = pItem1->parent; pItem2 != NULL; pItem2 = pItem2->parent)
+ {
+ nBit = (pItem2->child != pItem1) ? 1 : 0;
+ dwBitBuff = (dwBitBuff << 1) | nBit;
+ nBits++;
+ pItem1 = pItem2;
+ }
+
+// 1500EBE6
+ os->PutBits(dwBitBuff, nBits);
+
+// 1500EBEF
+ // Flush the remaining bits
+ while(os->nBits != 0)
+ {
+ if(os->cbOutSize != 0)
+ {
+ *os->pbOutPos++ = (unsigned char)os->dwBitBuff;
+ os->cbOutSize--;
+ }
+ os->dwBitBuff >>= 8;
+ os->nBits -= ((os->nBits > 8) ? 8 : os->nBits);
+ }
+
+ return (unsigned int)(os->pbOutPos - os->pbOutBuffer);
+}
+
+// Decompression using Huffman tree (1500E450)
+unsigned int THuffmannTree::DoDecompression(unsigned char * pbOutBuffer, unsigned int dwOutLength, TInputStream * is)
+{
+ TQDecompress * qd;
+ THTreeItem * pItem1;
+ THTreeItem * pItem2;
+ unsigned char * pbOutPos = pbOutBuffer;
+ unsigned long nBitCount;
+ unsigned int nDcmpByte = 0;
+ unsigned int n8Bits; // 8 bits loaded from input stream
+ unsigned int n7Bits; // 7 bits loaded from input stream
+ bool bHasQdEntry;
+
+ // Test the output length. Must not be NULL.
+ if(dwOutLength == 0)
+ return 0;
+
+ // Get the compression type from the input stream
+ n8Bits = is->Get8Bits();
+
+ // Build the Huffman tree
+ BuildTree(n8Bits);
+ bIsCmp0 = (n8Bits == 0) ? 1 : 0;
+
+ for(;;)
+ {
+ // Security check: If we are at the end of the input buffer,
+ // it means that the data is corrupt
+ if(is->BitCount == 0 && is->pbInBuffer >= is->pbInBufferEnd)
+ return 0;
+
+ // Get 7 bits from input stream
+ n7Bits = is->Get7Bits();
+
+ // Try to use quick decompression. Check TQDecompress array for corresponding item.
+ // If found, ise the result byte instead.
+ qd = &qd3474[n7Bits];
+
+ // If there is a quick-pass possible (ebx)
+ bHasQdEntry = (qd->offs00 >= offs0004) ? true : false;
+
+ // If we can use quick decompress, use it.
+ if(bHasQdEntry)
+ {
+ if(qd->nBits > 7)
+ {
+ is->SkipBits(7);
+ pItem1 = qd->pItem;
+ goto _1500E549;
+ }
+ is->SkipBits(qd->nBits);
+ nDcmpByte = qd->dcmpByte;
+ }
+ else
+ {
+ pItem1 = pFirst->next->prev;
+ if(PTR_INVALID_OR_NULL(pItem1))
+ pItem1 = NULL;
+_1500E549:
+ nBitCount = 0;
+ pItem2 = NULL;
+
+ do
+ {
+ if(pItem1 == NULL)
+ return 0;
+
+ pItem1 = pItem1->child; // Move down by one level
+ if(is->GetBit()) // If current bit is set, move to previous
+ pItem1 = pItem1->prev;
+
+ if(++nBitCount == 7) // If we are at 7th bit, save current HTree item.
+ pItem2 = pItem1;
+ }
+ while(pItem1->child != NULL); // Walk until tree has no deeper level
+
+ if(bHasQdEntry == false)
+ {
+ if(nBitCount > 7)
+ {
+ qd->offs00 = offs0004;
+ qd->nBits = nBitCount;
+ qd->pItem = pItem2;
+ }
+ else
+ {
+ unsigned long nIndex = n7Bits & (0xFFFFFFFF >> (32 - nBitCount));
+ unsigned long nAdd = (1 << nBitCount);
+
+ for(qd = &qd3474[nIndex]; nIndex <= 0x7F; nIndex += nAdd, qd += nAdd)
+ {
+ qd->offs00 = offs0004;
+ qd->nBits = nBitCount;
+ qd->dcmpByte = pItem1->dcmpByte;
+ }
+ }
+ }
+ nDcmpByte = pItem1->dcmpByte;
+ }
+
+ if(nDcmpByte == 0x101) // Huffman tree needs to be modified
+ {
+ n8Bits = is->Get8Bits();
+ pItem1 = (PTR_INVALID_OR_NULL(pLast)) ? NULL : pLast;
+
+ pItem2 = Call1500E740(1);
+ pItem2->parent = pItem1;
+ pItem2->dcmpByte = pItem1->dcmpByte;
+ pItem2->byteValue = pItem1->byteValue;
+ items306C[pItem2->dcmpByte] = pItem2;
+
+ pItem2 = Call1500E740(1);
+ pItem2->parent = pItem1;
+ pItem2->dcmpByte = n8Bits;
+ pItem2->byteValue = 0;
+ items306C[pItem2->dcmpByte] = pItem2;
+
+ pItem1->child = pItem2;
+ Call1500E820(pItem2);
+ if(bIsCmp0 == 0)
+ Call1500E820(items306C[n8Bits]);
+
+ nDcmpByte = n8Bits;
+ }
+
+ if(nDcmpByte == 0x100)
+ break;
+
+ *pbOutPos++ = (unsigned char)nDcmpByte;
+ if(--dwOutLength == 0)
+ break;
+
+ if(bIsCmp0)
+ Call1500E820(items306C[nDcmpByte]);
+ }
+
+ return (unsigned int)(pbOutPos - pbOutBuffer);
+}
+
+
+// Table for (de)compression. Every compression type has 258 entries
+unsigned char THuffmannTree::Table1502A630[] =
+{
+ // Data for compression type 0x00
+ 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00,
+
+ // Data for compression type 0x01
+ 0x54, 0x16, 0x16, 0x0D, 0x0C, 0x08, 0x06, 0x05, 0x06, 0x05, 0x06, 0x03, 0x04, 0x04, 0x03, 0x05,
+ 0x0E, 0x0B, 0x14, 0x13, 0x13, 0x09, 0x0B, 0x06, 0x05, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02,
+ 0x0D, 0x07, 0x09, 0x06, 0x06, 0x04, 0x03, 0x02, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02,
+ 0x09, 0x06, 0x04, 0x04, 0x04, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x04,
+ 0x08, 0x03, 0x04, 0x07, 0x09, 0x05, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02,
+ 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02,
+ 0x06, 0x0A, 0x08, 0x08, 0x06, 0x07, 0x04, 0x03, 0x04, 0x04, 0x02, 0x02, 0x04, 0x02, 0x03, 0x03,
+ 0x04, 0x03, 0x07, 0x07, 0x09, 0x06, 0x04, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x0A, 0x02, 0x02, 0x03, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x03, 0x05, 0x02, 0x03,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x04, 0x04, 0x07, 0x09, 0x08, 0x0C, 0x02,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03,
+ 0x04, 0x01, 0x02, 0x04, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x4B,
+ 0x00, 0x00,
+
+ // Data for compression type 0x02
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x27, 0x00, 0x00, 0x23, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x06, 0x0E, 0x10, 0x04,
+ 0x06, 0x08, 0x05, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x01, 0x01, 0x02, 0x01, 0x01,
+ 0x01, 0x04, 0x02, 0x04, 0x02, 0x02, 0x02, 0x01, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x03, 0x02,
+ 0x03, 0x01, 0x03, 0x06, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01,
+ 0x01, 0x29, 0x07, 0x16, 0x12, 0x40, 0x0A, 0x0A, 0x11, 0x25, 0x01, 0x03, 0x17, 0x10, 0x26, 0x2A,
+ 0x10, 0x01, 0x23, 0x23, 0x2F, 0x10, 0x06, 0x07, 0x02, 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+
+ // Data for compression type 0x03
+ 0xFF, 0x0B, 0x07, 0x05, 0x0B, 0x02, 0x02, 0x02, 0x06, 0x02, 0x02, 0x01, 0x04, 0x02, 0x01, 0x03,
+ 0x09, 0x01, 0x01, 0x01, 0x03, 0x04, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
+ 0x05, 0x01, 0x01, 0x01, 0x0D, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
+ 0x0A, 0x04, 0x02, 0x01, 0x06, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01,
+ 0x05, 0x02, 0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x03, 0x03,
+ 0x01, 0x03, 0x01, 0x01, 0x02, 0x05, 0x01, 0x01, 0x04, 0x03, 0x05, 0x01, 0x03, 0x01, 0x03, 0x03,
+ 0x02, 0x01, 0x04, 0x03, 0x0A, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x02, 0x01, 0x0A, 0x02, 0x05, 0x01, 0x01, 0x02, 0x07, 0x02, 0x17, 0x01, 0x05, 0x01, 0x01,
+ 0x0E, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x06, 0x02, 0x01, 0x04, 0x05, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11,
+ 0x00, 0x00,
+
+ // Data for compression type 0x04
+ 0xFF, 0xFB, 0x98, 0x9A, 0x84, 0x85, 0x63, 0x64, 0x3E, 0x3E, 0x22, 0x22, 0x13, 0x13, 0x18, 0x17,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+
+ // Data for compression type 0x05
+ 0xFF, 0xF1, 0x9D, 0x9E, 0x9A, 0x9B, 0x9A, 0x97, 0x93, 0x93, 0x8C, 0x8E, 0x86, 0x88, 0x80, 0x82,
+ 0x7C, 0x7C, 0x72, 0x73, 0x69, 0x6B, 0x5F, 0x60, 0x55, 0x56, 0x4A, 0x4B, 0x40, 0x41, 0x37, 0x37,
+ 0x2F, 0x2F, 0x27, 0x27, 0x21, 0x21, 0x1B, 0x1C, 0x17, 0x17, 0x13, 0x13, 0x10, 0x10, 0x0D, 0x0D,
+ 0x0B, 0x0B, 0x09, 0x09, 0x08, 0x08, 0x07, 0x07, 0x06, 0x05, 0x05, 0x04, 0x04, 0x04, 0x19, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+
+ // Data for compression type 0x06
+ 0xC3, 0xCB, 0xF5, 0x41, 0xFF, 0x7B, 0xF7, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xBF, 0xCC, 0xF2, 0x40, 0xFD, 0x7C, 0xF7, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7A, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+
+ // Data for compression type 0x07
+ 0xC3, 0xD9, 0xEF, 0x3D, 0xF9, 0x7C, 0xE9, 0x1E, 0xFD, 0xAB, 0xF1, 0x2C, 0xFC, 0x5B, 0xFE, 0x17,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xBD, 0xD9, 0xEC, 0x3D, 0xF5, 0x7D, 0xE8, 0x1D, 0xFB, 0xAE, 0xF0, 0x2C, 0xFB, 0x5C, 0xFF, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+
+ // Data for compression type 0x08
+ 0xBA, 0xC5, 0xDA, 0x33, 0xE3, 0x6D, 0xD8, 0x18, 0xE5, 0x94, 0xDA, 0x23, 0xDF, 0x4A, 0xD1, 0x10,
+ 0xEE, 0xAF, 0xE4, 0x2C, 0xEA, 0x5A, 0xDE, 0x15, 0xF4, 0x87, 0xE9, 0x21, 0xF6, 0x43, 0xFC, 0x12,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xB0, 0xC7, 0xD8, 0x33, 0xE3, 0x6B, 0xD6, 0x18, 0xE7, 0x95, 0xD8, 0x23, 0xDB, 0x49, 0xD0, 0x11,
+ 0xE9, 0xB2, 0xE2, 0x2B, 0xE8, 0x5C, 0xDD, 0x15, 0xF1, 0x87, 0xE7, 0x20, 0xF7, 0x44, 0xFF, 0x13,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5F, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00
+};
diff --git a/dep/StormLib/src/huffman/huff.h b/dep/StormLib/src/huffman/huff.h
new file mode 100644
index 00000000000..83e9b2cdad0
--- /dev/null
+++ b/dep/StormLib/src/huffman/huff.h
@@ -0,0 +1,142 @@
+/*****************************************************************************/
+/* huffman.h Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Description : */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* xx.xx.xx 1.00 Lad The first version of huffman.h */
+/* 03.05.03 2.00 Lad Added compression */
+/* 08.12.03 2.01 Dan High-memory handling (> 0x80000000) */
+/*****************************************************************************/
+
+#ifndef __HUFFMAN_H__
+#define __HUFFMAN_H__
+
+#include "../StormPort.h"
+
+//-----------------------------------------------------------------------------
+// Defines
+
+#define INSERT_ITEM 1
+#define SWITCH_ITEMS 2 // Switch the item1 and item2
+
+#define PTR_NOT(ptr) (THTreeItem *)(~(DWORD_PTR)(ptr))
+#define PTR_PTR(ptr) ((THTreeItem *)(ptr))
+#define PTR_INT(ptr) (INT_PTR)(ptr)
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+//-----------------------------------------------------------------------------
+// Structures and classes
+
+// Input stream for Huffmann decompression
+class TInputStream
+{
+ public:
+
+ unsigned long GetBit();
+ unsigned long Get7Bits();
+ unsigned long Get8Bits();
+ void SkipBits(unsigned int BitCount);
+
+ unsigned char * pbInBuffer; // Input data
+ unsigned char * pbInBufferEnd; // End of the input buffer
+ unsigned long BitBuffer; // Input bit buffer
+ unsigned int BitCount; // Number of bits remaining in 'dwBitBuff'
+};
+
+// Output stream for Huffmann compression
+class TOutputStream
+{
+ public:
+
+ void PutBits(unsigned long dwBuff, unsigned int nPutBits);
+
+ unsigned char * pbOutBuffer; // 00 : Output buffer
+ unsigned long cbOutSize; // 04 : Size of output buffer
+ unsigned char * pbOutPos; // 08 : Current output position
+ unsigned long dwBitBuff; // 0C : Bit buffer
+ unsigned long nBits; // 10 : Number of bits in the bit buffer
+};
+
+// Huffmann tree item (?)
+struct THTreeItem
+{
+ THTreeItem * Call1501DB70(THTreeItem * pLast);
+ THTreeItem * GetPrevItem(LONG_PTR value);
+ void ClearItemLinks();
+ void RemoveItem();
+
+ THTreeItem * next; // 00 - Pointer to next THTreeItem
+ THTreeItem * prev; // 04 - Pointer to prev THTreeItem (< 0 if none)
+ unsigned long dcmpByte; // 08 - Index of this item in item pointer array, decompressed byte value
+ unsigned long byteValue; // 0C - Some byte value
+ THTreeItem * parent; // 10 - Pointer to parent THTreeItem (NULL if none)
+ THTreeItem * child; // 14 - Pointer to child THTreeItem
+ int addressMultiplier; // -1 if object on negative address (>0x80000000), +1 if positive
+};
+
+// Structure used for quick decompress. The 'bitCount' contains number of bits
+// and byte value contains result decompressed byte value.
+// After each walk through Huffman tree are filled all entries which are
+// multiplies of number of bits loaded from input stream. These entries
+// contain number of bits and result value. At the next 7 bits is tested this
+// structure first. If corresponding entry found, decompression routine will
+// not walk through Huffman tree and directly stores output byte to output stream.
+struct TQDecompress
+{
+ unsigned long offs00; // 00 - 1 if resolved
+ unsigned long nBits; // 04 - Bit count
+ union
+ {
+ unsigned long dcmpByte; // 08 - Byte value for decompress (if bitCount <= 7)
+ THTreeItem * pItem; // 08 - THTreeItem (if number of bits is greater than 7
+ };
+};
+
+// Structure for Huffman tree (Size 0x3674 bytes). Because I'm not expert
+// for the decompression, I do not know actually if the class is really a Hufmann
+// tree. If someone knows the decompression details, please let me know
+class THuffmannTree
+{
+ public:
+
+ THuffmannTree();
+ void InitTree(bool bCompression);
+ void BuildTree(unsigned int nCmpType);
+// void ModifyTree(unsigned long dwIndex);
+// void UninitTree();
+
+// void Call15007010(Bit32 dwInLength, THTreeItem * item);
+ THTreeItem * Call1500E740(unsigned int nValue);
+ void Call1500E820(THTreeItem * pItem);
+ unsigned int DoCompression(TOutputStream * os, unsigned char * pbInBuffer, int nInLength, int nCmpType);
+ unsigned int DoDecompression(unsigned char * pbOutBuffer, unsigned int dwOutLength, TInputStream * is);
+
+ unsigned long bIsCmp0; // 0000 - 1 if compression type 0
+ unsigned long offs0004; // 0004 - Some flag
+ THTreeItem items0008[0x203]; // 0008 - HTree items
+
+ //- Sometimes used as HTree item -----------
+ THTreeItem * pItem3050; // 3050 - Always NULL (?)
+ THTreeItem * pItem3054; // 3054 - Pointer to Huffman tree item
+ THTreeItem * pItem3058; // 3058 - Pointer to Huffman tree item (< 0 if invalid)
+
+ //- Sometimes used as HTree item -----------
+ THTreeItem * pItem305C; // 305C - Usually NULL
+ THTreeItem * pFirst; // 3060 - Pointer to top (first) Huffman tree item
+ THTreeItem * pLast; // 3064 - Pointer to bottom (last) Huffman tree item (< 0 if invalid)
+ unsigned long nItems; // 3068 - Number of used HTree items
+
+ //-------------------------------------------
+ THTreeItem * items306C[0x102]; // 306C - THTreeItem pointer array
+ TQDecompress qd3474[0x80]; // 3474 - Array for quick decompression
+ int addressMultiplier; // -1 if object on negative address (>0x80000000), +1 if positive
+
+ static unsigned char Table1502A630[];// Some table
+};
+
+#endif // __HUFFMAN_H__
diff --git a/dep/StormLib/src/huffman/huff_patch.cpp b/dep/StormLib/src/huffman/huff_patch.cpp
new file mode 100644
index 00000000000..6176a9b1f77
--- /dev/null
+++ b/dep/StormLib/src/huffman/huff_patch.cpp
@@ -0,0 +1,1120 @@
+/*****************************************************************************/
+/* huffman.cpp Copyright (c) Ladislav Zezula 1998-2003 */
+/*---------------------------------------------------------------------------*/
+/* This module contains Huffmann (de)compression methods */
+/* */
+/* Authors : Ladislav Zezula (ladik@zezula.net) */
+/* ShadowFlare (BlakFlare@hotmail.com) */
+/* */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* xx.xx.xx 1.00 Lad The first version of dcmp.cpp */
+/* 03.05.03 1.00 Lad Added compression methods */
+/* 19.11.03 1.01 Dan Big endian handling */
+/* 08.12.03 2.01 Dan High-memory handling (> 0x80000000) */
+/*****************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+
+#include "huff.h"
+
+THTreeItem * gcpFirst, * gpFirst, * gcpItem3054, * gpItem3054;
+
+#define PTR_VALID(ptr) ((ptr) != gcpFirst && (ptr) != gcpItem3054)
+#define PTR_INVALID(ptr) (!PTR_VALID(ptr))
+#define PTR_INVALID_OR_NULL(ptr) (0 == (ptr) || PTR_INVALID(ptr))
+
+//-----------------------------------------------------------------------------
+// Methods of the THTreeItem struct
+
+// 1501DB70
+THTreeItem * THTreeItem::Call1501DB70(THTreeItem * pLast)
+{
+ if(pLast == NULL)
+ pLast = this + 1;
+ return pLast;
+}
+
+// Gets previous Huffman tree item (?)
+THTreeItem * THTreeItem::GetPrevItem(SIntPtr value)
+{
+ if(PTR_INVALID(prev))
+ return PTR_NOT(prev);
+
+ if(value == -1 || PTR_INVALID((THTreeItem *) value))
+ value = (SIntPtr)(this - next->prev);
+ return prev + value;
+}
+
+// 1500F5E0
+void THTreeItem::ClearItemLinks()
+{
+ next = prev = NULL;
+}
+
+// 1500BC90
+void THTreeItem::RemoveItem()
+{
+ THTreeItem * pTemp; // EDX
+
+ if(next != NULL)
+ {
+ pTemp = prev;
+
+ if(PTR_INVALID(pTemp))
+ pTemp = PTR_NOT(pTemp);
+ else
+ pTemp += (this - next->prev);
+
+ pTemp->next = next;
+ next->prev = prev;
+ next = prev = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// TOutputStream functions
+
+void TOutputStream::PutBits(unsigned long dwBuff, unsigned int nPutBits)
+{
+ dwBitBuff |= (dwBuff << nBits);
+ nBits += nPutBits;
+
+ // Flush completed bytes
+ while(nBits >= 8)
+ {
+ if(cbOutSize != 0)
+ {
+ *pbOutPos++ = (unsigned char)dwBitBuff;
+ cbOutSize--;
+ }
+
+ dwBitBuff >>= 8;
+ nBits -= 8;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// TInputStream functions
+
+// Gets one bit from input stream
+unsigned long TInputStream::GetBit()
+{
+ unsigned long dwOneBit = 0;
+
+ // Ensure that the input stream is reloaded, if there are no bits left
+ if(BitCount == 0)
+ {
+ // Refill the bit buffer
+ BitBuffer = *pbInBuffer++;
+ BitCount = 8;
+ }
+
+ // Copy the bit from bit buffer to the variable
+ dwOneBit = (BitBuffer & 0x01);
+ BitBuffer >>= 1;
+ BitCount--;
+
+ return dwOneBit;
+}
+
+// Gets 7 bits from the stream. DOES NOT remove the bits from input stream
+unsigned long TInputStream::Get7Bits()
+{
+ unsigned long dwReloadByte = 0;
+
+ // If there is not enough bits to get the value,
+ // we have to add 8 more bits from the input buffer
+ if(BitCount < 7)
+ {
+ dwReloadByte = *pbInBuffer++;
+ BitBuffer |= dwReloadByte << BitCount;
+ BitCount += 8;
+ }
+
+ // Return the first available 7 bits. DO NOT remove them from the input stream
+ return (BitBuffer & 0x7F);
+}
+
+// Gets the whole byte from the input stream.
+unsigned long TInputStream::Get8Bits()
+{
+ unsigned long dwReloadByte = 0;
+ unsigned long dwOneByte = 0;
+
+ // If there is not enough bits to get the value,
+ // we have to add 8 more bits from the input buffer
+ if(BitCount < 8)
+ {
+ dwReloadByte = *pbInBuffer++;
+ BitBuffer |= dwReloadByte << BitCount;
+ BitCount += 8;
+ }
+
+ // Return the lowest 8 its
+ dwOneByte = (BitBuffer & 0xFF);
+ BitBuffer >>= 8;
+ BitCount -= 8;
+ return dwOneByte;
+}
+
+void TInputStream::SkipBits(unsigned int dwBitsToSkip)
+{
+ unsigned long dwReloadByte = 0;
+
+ // If there is not enough bits in the buffer,
+ // we have to add 8 more bits from the input buffer
+ if(BitCount < dwBitsToSkip)
+ {
+ dwReloadByte = *pbInBuffer++;
+ BitBuffer |= dwReloadByte << BitCount;
+ BitCount += 8;
+ }
+
+ // Skip the remaining bits
+ BitBuffer >>= dwBitsToSkip;
+ BitCount -= dwBitsToSkip;
+}
+
+//-----------------------------------------------------------------------------
+// Functions for huffmann tree items
+
+// Inserts item into the tree (?)
+static void InsertItem(THTreeItem ** itemPtr, THTreeItem * item, unsigned long where, THTreeItem * item2)
+{
+ THTreeItem * next = item->next; // EDI - next to the first item
+ THTreeItem * prev = item->prev; // ESI - prev to the first item
+ THTreeItem * prev2; // Pointer to previous item
+ THTreeItem * next2; // Pointer to the next item
+
+ // The same code like in RemoveItem(item);
+ if(next != 0) // If the first item already has next one
+ {
+ if(PTR_INVALID(prev))
+ prev = PTR_NOT(prev);
+ else
+ prev += (item - next->prev);
+
+ // 150083C1
+ // Remove the item from the tree
+ prev->next = next;
+ next->prev = prev;
+
+ // Invalidate 'prev' and 'next' pointer
+ item->next = 0;
+ item->prev = 0;
+ }
+
+ if(item2 == NULL) // EDX - If the second item is not entered,
+ item2 = PTR_PTR(&itemPtr[1]); // take the first tree item
+
+ switch(where)
+ {
+ case SWITCH_ITEMS : // Switch the two items
+ item->next = item2->next; // item2->next (Pointer to pointer to first)
+ item->prev = item2->next->prev;
+ item2->next->prev = item;
+ item2->next = item; // Set the first item
+ return;
+
+ case INSERT_ITEM: // Insert as the last item
+ item->next = item2; // Set next item (or pointer to pointer to first item)
+ item->prev = item2->prev; // Set prev item (or last item in the tree)
+
+ next2 = itemPtr[0];// Usually NULL
+ prev2 = item2->prev; // Prev item to the second (or last tree item)
+
+ if(PTR_INVALID(prev2))
+ {
+ prev2 = PTR_NOT(prev);
+
+ prev2->next = item;
+ item2->prev = item; // Next after last item
+ return;
+ }
+
+ if(PTR_INVALID(next2))
+ next2 = (THTreeItem *)(item2 - item2->next->prev);
+
+ prev2 += (long) next2;
+ prev2->next = item;
+ item2->prev = item; // Set the next/last item
+ return;
+
+ default:
+ return;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// THuffmannTree class functions
+
+THuffmannTree::THuffmannTree()
+{
+}
+
+void THuffmannTree::InitTree(bool bCompression)
+{
+ THTreeItem * pItem;
+ unsigned int nCount;
+
+ // Clear links for all the items in the tree
+ for(pItem = items0008, nCount = 0x203; nCount != 0; pItem++, nCount--)
+ pItem->ClearItemLinks();
+
+ gcpItem3054 = (THTreeItem *) &gcpItem3054;
+ pItem3050 = NULL;
+ pItem3054 = PTR_PTR(&pItem3054);
+ pItem3058 = gcpItem3054;
+ gpItem3054 = pItem3054;
+
+ gcpFirst = (THTreeItem *) &gcpFirst;
+ pItem305C = NULL;
+ pFirst = PTR_PTR(&pFirst);
+ pLast = gcpFirst;
+ gpFirst = pFirst;
+
+ offs0004 = 1;
+ nItems = 0;
+
+ // Clear all TQDecompress items. Do this only if preparing for decompression
+ if(bCompression == false)
+ {
+ for(nCount = 0; nCount < sizeof(qd3474) / sizeof(TQDecompress); nCount++)
+ qd3474[nCount].offs00 = 0;
+ }
+}
+
+// Builds Huffman tree. Called with the first 8 bits loaded from input stream
+void THuffmannTree::BuildTree(unsigned int nCmpType)
+{
+ unsigned long maxByte; // [ESP+10] - The greatest character found in table
+ THTreeItem ** itemPtr; // [ESP+14] - Pointer to Huffman tree item pointer array
+ unsigned char * byteArray; // [ESP+1C] - Pointer to unsigned char in Table1502A630
+ THTreeItem * child1;
+ unsigned long i; // egcs in linux doesn't like multiple for loops without an explicit i
+
+ // Loop while pointer has a valid value
+ while(PTR_VALID(pLast)) // ESI - Last entry
+ {
+ THTreeItem * temp; // EAX
+
+ if(pLast->next != NULL) // ESI->next
+ pLast->RemoveItem();
+ // EDI = &offs3054
+ pItem3058 = PTR_PTR(&pItem3054); // [EDI+4]
+ pLast->prev = pItem3058; // EAX
+
+ temp = PTR_PTR(&pItem3054)->GetPrevItem((SIntPtr)(&pItem3050));
+
+ temp->next = pLast;
+ pItem3054 = pLast;
+ }
+
+ // Clear all pointers in HTree item array
+ memset(items306C, 0, sizeof(items306C));
+
+ maxByte = 0; // Greatest character found init to zero.
+ itemPtr = (THTreeItem **)&items306C; // Pointer to current entry in HTree item pointer array
+
+ // Ensure we have low 8 bits only
+ nCmpType &= 0xFF;
+ byteArray = Table1502A630 + nCmpType * 258; // EDI also
+
+ for(i = 0; i < 0x100; i++, itemPtr++)
+ {
+ THTreeItem * item = pItem3058; // Item to be created
+ THTreeItem * pItem3 = pItem3058;
+ unsigned char oneByte = byteArray[i];
+
+ // Skip all the bytes which are zero.
+ if(byteArray[i] == 0)
+ continue;
+
+ // If not valid pointer, take the first available item in the array
+ if(PTR_INVALID_OR_NULL(item))
+ item = &items0008[nItems++];
+
+ // Insert this item as the top of the tree
+ InsertItem(&pItem305C, item, SWITCH_ITEMS, NULL);
+
+ item->parent = NULL; // Invalidate child and parent
+ item->child = NULL;
+ *itemPtr = item; // Store pointer into pointer array
+
+ item->dcmpByte = i; // Store counter
+ item->byteValue = oneByte; // Store byte value
+ if(oneByte >= maxByte)
+ {
+ maxByte = oneByte;
+ continue;
+ }
+
+ // Find the first item which has byte value greater than current one byte
+ if(PTR_VALID(pItem3 = pLast)) // EDI - Pointer to the last item
+ {
+ // 15006AF7
+ if(pItem3 != NULL)
+ {
+ do // 15006AFB
+ {
+ if(pItem3->byteValue >= oneByte)
+ goto _15006B09;
+ pItem3 = pItem3->prev;
+ }
+ while(PTR_VALID(pItem3));
+ }
+ }
+ pItem3 = NULL;
+
+ // 15006B09
+ _15006B09:
+ if(item->next != NULL)
+ item->RemoveItem();
+
+ // 15006B15
+ if(pItem3 == NULL)
+ pItem3 = PTR_PTR(&pFirst);
+
+ // 15006B1F
+ item->next = pItem3->next;
+ item->prev = pItem3->next->prev;
+ pItem3->next->prev = item;
+ pItem3->next = item;
+ }
+
+ // 15006B4A
+ for(; i < 0x102; i++)
+ {
+ THTreeItem ** itemPtr = &items306C[i]; // EDI
+
+ // 15006B59
+ THTreeItem * item = pItem3058; // ESI
+ if(PTR_INVALID_OR_NULL(item))
+ item = &items0008[nItems++];
+
+ InsertItem(&pItem305C, item, INSERT_ITEM, NULL);
+
+ // 15006B89
+ item->dcmpByte = i;
+ item->byteValue = 1;
+ item->parent = NULL;
+ item->child = NULL;
+ *itemPtr++ = item;
+ }
+
+ // 15006BAA
+ if(PTR_VALID(child1 = pLast)) // EDI - last item (first child to item
+ {
+ THTreeItem * child2; // EBP
+ THTreeItem * item; // ESI
+
+ // 15006BB8
+ while(PTR_VALID(child2 = child1->prev))
+ {
+ if(PTR_INVALID_OR_NULL(item = pItem3058))
+ item = &items0008[nItems++];
+
+ // 15006BE3
+ InsertItem(&pItem305C, item, SWITCH_ITEMS, NULL);
+
+ // 15006BF3
+ item->parent = NULL;
+ item->child = NULL;
+
+ //EDX = child2->byteValue + child1->byteValue;
+ //EAX = child1->byteValue;
+ //ECX = maxByte; // The greatest character (0xFF usually)
+
+ item->byteValue = child1->byteValue + child2->byteValue; // 0x02
+ item->child = child1; // Prev item in the
+ child1->parent = item;
+ child2->parent = item;
+
+ // EAX = item->byteValue;
+ if(item->byteValue >= maxByte)
+ maxByte = item->byteValue;
+ else
+ {
+ THTreeItem * pItem2 = child2->prev; // EDI
+
+ // 15006C2D
+ while(PTR_VALID(pItem2))
+ {
+ if(pItem2->byteValue >= item->byteValue)
+ goto _15006C3B;
+ pItem2 = pItem2->prev;
+ }
+ pItem2 = NULL;
+
+ _15006C3B:
+ if(item->next != 0)
+ {
+ THTreeItem * temp4 = item->GetPrevItem(-1);
+
+ temp4->next = item->next; // The first item changed
+ item->next->prev = item->prev; // First->prev changed to negative value
+ item->next = NULL;
+ item->prev = NULL;
+ }
+
+ // 15006C62
+ if(pItem2 == NULL)
+ pItem2 = PTR_PTR(&pFirst);
+
+ item->next = pItem2->next; // Set item with 0x100 byte value
+ item->prev = pItem2->next->prev; // Set item with 0x17 byte value
+ pItem2->next->prev = item; // Changed prev of item with
+ pItem2->next = item;
+ }
+
+ // 15006C7B
+ if(PTR_INVALID_OR_NULL(child1 = child2->prev))
+ break;
+ }
+ }
+ // 15006C88
+ offs0004 = 1;
+}
+
+THTreeItem * THuffmannTree::Call1500E740(unsigned int nValue)
+{
+ THTreeItem * pItem1 = pItem3058; // EDX
+ THTreeItem * pItem2; // EAX
+ THTreeItem * pNext;
+ THTreeItem * pPrev;
+ THTreeItem ** ppItem;
+
+ if(PTR_INVALID_OR_NULL(pItem1) || (pItem2 = pItem1) == NULL)
+ {
+ if((pItem2 = &items0008[nItems++]) != NULL)
+ pItem1 = pItem2;
+ else
+ pItem1 = pFirst;
+ }
+ else
+ pItem1 = pItem2;
+
+ pNext = pItem1->next;
+ if(pNext != NULL)
+ {
+ pPrev = pItem1->prev;
+ if(PTR_INVALID(pPrev))
+ pPrev = PTR_NOT(pPrev);
+ else
+ pPrev += (pItem1 - pItem1->next->prev);
+
+ pPrev->next = pNext;
+ pNext->prev = pPrev;
+ pItem1->next = NULL;
+ pItem1->prev = NULL;
+ }
+
+ ppItem = &pFirst; // esi
+ if(nValue > 1)
+ {
+ // ecx = pFirst->next;
+ pItem1->next = *ppItem;
+ pItem1->prev = (*ppItem)->prev;
+
+ (*ppItem)->prev = pItem2;
+ *ppItem = pItem1;
+
+ pItem2->parent = NULL;
+ pItem2->child = NULL;
+ }
+ else
+ {
+ pItem1->next = (THTreeItem *)ppItem;
+ pItem1->prev = ppItem[1];
+ // edi = pItem305C;
+ pPrev = ppItem[1]; // ecx
+ if(PTR_INVALID(pPrev))
+ {
+ pPrev = PTR_NOT(pPrev);
+ pPrev->next = pItem1;
+ pPrev->prev = pItem2;
+
+ pItem2->parent = NULL;
+ pItem2->child = NULL;
+ }
+ else
+ {
+ if(PTR_INVALID(pItem305C))
+ pPrev += (THTreeItem *)ppItem - (*ppItem)->prev;
+ else
+ pPrev += (long)pItem305C;
+
+ pPrev->next = pItem1;
+ ppItem[1] = pItem2;
+ pItem2->parent = NULL;
+ pItem2->child = NULL;
+ }
+ }
+ return pItem2;
+}
+
+void THuffmannTree::Call1500E820(THTreeItem * pItem)
+{
+ THTreeItem * pItem1; // edi
+ THTreeItem * pItem2 = NULL; // eax
+ THTreeItem * pItem3; // edx
+ THTreeItem * pPrev; // ebx
+
+ for(; pItem != NULL; pItem = pItem->parent)
+ {
+ pItem->byteValue++;
+
+ for(pItem1 = pItem; ; pItem1 = pPrev)
+ {
+ pPrev = pItem1->prev;
+ if(PTR_INVALID_OR_NULL(pPrev))
+ {
+ pPrev = NULL;
+ break;
+ }
+
+ if(pPrev->byteValue >= pItem->byteValue)
+ break;
+ }
+
+ if(pItem1 == pItem)
+ continue;
+
+ if(pItem1->next != NULL)
+ {
+ pItem2 = pItem1->GetPrevItem(-1);
+ pItem2->next = pItem1->next;
+ pItem1->next->prev = pItem1->prev;
+ pItem1->next = NULL;
+ pItem1->prev = NULL;
+ }
+
+ pItem2 = pItem->next;
+ pItem1->next = pItem2;
+ pItem1->prev = pItem2->prev;
+ pItem2->prev = pItem1;
+ pItem->next = pItem1;
+ if((pItem2 = pItem1) != NULL)
+ {
+ pItem2 = pItem->GetPrevItem(-1);
+ pItem2->next = pItem->next;
+ pItem->next->prev = pItem->prev;
+ pItem->next = NULL;
+ pItem->prev = NULL;
+ }
+
+ if(pPrev == NULL)
+ pPrev = PTR_PTR(&pFirst);
+
+ pItem2 = pPrev->next;
+ pItem->next = pItem2;
+ pItem->prev = pItem2->prev;
+ pItem2->prev = pItem;
+ pPrev->next = pItem;
+
+ pItem3 = pItem1->parent->child;
+ pItem2 = pItem->parent;
+ if(pItem2->child == pItem)
+ pItem2->child = pItem1;
+ if(pItem3 == pItem1)
+ pItem1->parent->child = pItem;
+
+ pItem2 = pItem->parent;
+ pItem->parent = pItem1->parent;
+ pItem1->parent = pItem2;
+ offs0004++;
+ }
+}
+
+// 1500E920
+unsigned int THuffmannTree::DoCompression(TOutputStream * os, unsigned char * pbInBuffer, int nInLength, int nCmpType)
+{
+ THTreeItem * pItem1;
+ THTreeItem * pItem2;
+ THTreeItem * pItem3;
+ THTreeItem * pTemp;
+ unsigned long dwBitBuff;
+ unsigned int nBits;
+ unsigned int nBit;
+
+ BuildTree(nCmpType);
+ bIsCmp0 = (nCmpType == 0);
+
+ // Store the compression type into output buffer
+ os->dwBitBuff |= (nCmpType << os->nBits);
+ os->nBits += 8;
+
+ // Flush completed bytes
+ while(os->nBits >= 8)
+ {
+ if(os->cbOutSize != 0)
+ {
+ *os->pbOutPos++ = (unsigned char)os->dwBitBuff;
+ os->cbOutSize--;
+ }
+
+ os->dwBitBuff >>= 8;
+ os->nBits -= 8;
+ }
+
+ for(; nInLength != 0; nInLength--)
+ {
+ unsigned char bOneByte = *pbInBuffer++;
+
+ if((pItem1 = items306C[bOneByte]) == NULL)
+ {
+ pItem2 = items306C[0x101]; // ecx
+ pItem3 = pItem2->parent; // eax
+ dwBitBuff = 0;
+ nBits = 0;
+
+ for(; pItem3 != NULL; pItem3 = pItem3->parent)
+ {
+ nBit = (pItem3->child != pItem2) ? 1 : 0;
+ dwBitBuff = (dwBitBuff << 1) | nBit;
+ nBits++;
+ pItem2 = pItem3;
+ }
+ os->PutBits(dwBitBuff, nBits);
+
+ // Store the loaded byte into output stream
+ os->dwBitBuff |= (bOneByte << os->nBits);
+ os->nBits += 8;
+
+ // Flush the whole byte(s)
+ while(os->nBits >= 8)
+ {
+ if(os->cbOutSize != 0)
+ {
+ *os->pbOutPos++ = (unsigned char)os->dwBitBuff;
+ os->cbOutSize--;
+ }
+ os->dwBitBuff >>= 8;
+ os->nBits -= 8;
+ }
+
+ pItem1 = (PTR_INVALID_OR_NULL(pLast)) ? NULL : pLast;
+ pItem2 = Call1500E740(1);
+ pItem2->dcmpByte = pItem1->dcmpByte;
+ pItem2->byteValue = pItem1->byteValue;
+ pItem2->parent = pItem1;
+ items306C[pItem2->dcmpByte] = pItem2;
+
+ pItem2 = Call1500E740(1);
+ pItem2->dcmpByte = bOneByte;
+ pItem2->byteValue = 0;
+ pItem2->parent = pItem1;
+ items306C[pItem2->dcmpByte] = pItem2;
+ pItem1->child = pItem2;
+
+ Call1500E820(pItem2);
+
+ if(bIsCmp0 != 0)
+ {
+ Call1500E820(items306C[bOneByte]);
+ continue;
+ }
+
+ for(pItem1 = items306C[bOneByte]; pItem1 != NULL; pItem1 = pItem1->parent)
+ {
+ pItem1->byteValue++;
+ pItem2 = pItem1;
+
+ for(;;)
+ {
+ pItem3 = pItem2->prev;
+ if(PTR_INVALID_OR_NULL(pItem3))
+ {
+ pItem3 = NULL;
+ break;
+ }
+ if(pItem3->byteValue >= pItem1->byteValue)
+ break;
+ pItem2 = pItem3;
+ }
+
+ if(pItem2 != pItem1)
+ {
+ InsertItem(&pItem305C, pItem2, SWITCH_ITEMS, pItem1);
+ InsertItem(&pItem305C, pItem1, SWITCH_ITEMS, pItem3);
+
+ pItem3 = pItem2->parent->child;
+ if(pItem1->parent->child == pItem1)
+ pItem1->parent->child = pItem2;
+
+ if(pItem3 == pItem2)
+ pItem2->parent->child = pItem1;
+
+ pTemp = pItem1->parent;
+ pItem1->parent = pItem2->parent;
+ pItem2->parent = pTemp;
+ offs0004++;
+ }
+ }
+ }
+// 1500EB62
+ else
+ {
+ dwBitBuff = 0;
+ nBits = 0;
+ for(pItem2 = pItem1->parent; pItem2 != NULL; pItem2 = pItem2->parent)
+ {
+ nBit = (pItem2->child != pItem1) ? 1 : 0;
+ dwBitBuff = (dwBitBuff << 1) | nBit;
+ nBits++;
+ pItem1 = pItem2;
+ }
+ os->PutBits(dwBitBuff, nBits);
+ }
+
+// 1500EB98
+ if(bIsCmp0 != 0)
+ Call1500E820(items306C[bOneByte]); // 1500EB9D
+// 1500EBAF
+ } // for(; nInLength != 0; nInLength--)
+
+// 1500EBB8
+ pItem1 = items306C[0x100];
+ dwBitBuff = 0;
+ nBits = 0;
+ for(pItem2 = pItem1->parent; pItem2 != NULL; pItem2 = pItem2->parent)
+ {
+ nBit = (pItem2->child != pItem1) ? 1 : 0;
+ dwBitBuff = (dwBitBuff << 1) | nBit;
+ nBits++;
+ pItem1 = pItem2;
+ }
+
+// 1500EBE6
+ os->PutBits(dwBitBuff, nBits);
+
+// 1500EBEF
+ // Flush the remaining bits
+ while(os->nBits != 0)
+ {
+ if(os->cbOutSize != 0)
+ {
+ *os->pbOutPos++ = (unsigned char)os->dwBitBuff;
+ os->cbOutSize--;
+ }
+ os->dwBitBuff >>= 8;
+ os->nBits -= ((os->nBits > 8) ? 8 : os->nBits);
+ }
+
+ return (unsigned int)(os->pbOutPos - os->pbOutBuffer);
+}
+
+// Decompression using Huffman tree (1500E450)
+unsigned int THuffmannTree::DoDecompression(unsigned char * pbOutBuffer, unsigned int dwOutLength, TInputStream * is)
+{
+ TQDecompress * qd;
+ THTreeItem * pItem1;
+ THTreeItem * pItem2;
+ unsigned char * pbOutPos = pbOutBuffer;
+ unsigned long nBitCount;
+ unsigned int nDcmpByte = 0;
+ unsigned int n8Bits; // 8 bits loaded from input stream
+ unsigned int n7Bits; // 7 bits loaded from input stream
+ bool bHasQdEntry;
+
+ // Test the output length. Must not be NULL.
+ if(dwOutLength == 0)
+ return 0;
+
+ // Get the compression type from the input stream
+ n8Bits = is->Get8Bits();
+
+ // Build the Huffman tree
+ BuildTree(n8Bits);
+ bIsCmp0 = (n8Bits == 0) ? 1 : 0;
+
+ for(;;)
+ {
+ // Security check: If we are at the end of the input buffer,
+ // it means that the data are corrupt.
+ if(is->pbInBuffer > is->pbInBufferEnd)
+ return 0;
+
+ // Get 7 bits from input stream
+ n7Bits = is->Get7Bits();
+
+ // Try to use quick decompression. Check TQDecompress array for corresponding item.
+ // If found, ise the result byte instead.
+ qd = &qd3474[n7Bits];
+
+ // If there is a quick-pass possible (ebx)
+ bHasQdEntry = (qd->offs00 >= offs0004) ? true : false;
+
+ // If we can use quick decompress, use it.
+ if(bHasQdEntry)
+ {
+ if(qd->nBits > 7)
+ {
+ is->SkipBits(7);
+ pItem1 = qd->pItem;
+ goto _1500E549;
+ }
+ is->SkipBits(qd->nBits);
+ nDcmpByte = qd->dcmpByte;
+ }
+ else
+ {
+ pItem1 = pFirst->next->prev;
+ if(PTR_INVALID_OR_NULL(pItem1))
+ pItem1 = NULL;
+_1500E549:
+ nBitCount = 0;
+ pItem2 = NULL;
+
+ do
+ {
+ pItem1 = pItem1->child; // Move down by one level
+ if(is->GetBit()) // If current bit is set, move to previous
+ pItem1 = pItem1->prev;
+
+ if(++nBitCount == 7) // If we are at 7th bit, save current HTree item.
+ pItem2 = pItem1;
+ }
+ while(pItem1->child != NULL); // Walk until tree has no deeper level
+
+ if(bHasQdEntry == false)
+ {
+ if(nBitCount > 7)
+ {
+ qd->offs00 = offs0004;
+ qd->nBits = nBitCount;
+ qd->pItem = pItem2;
+ }
+ else
+ {
+ unsigned long nIndex = n7Bits & (0xFFFFFFFF >> (32 - nBitCount));
+ unsigned long nAdd = (1 << nBitCount);
+
+ for(qd = &qd3474[nIndex]; nIndex <= 0x7F; nIndex += nAdd, qd += nAdd)
+ {
+ qd->offs00 = offs0004;
+ qd->nBits = nBitCount;
+ qd->dcmpByte = pItem1->dcmpByte;
+ }
+ }
+ }
+ nDcmpByte = pItem1->dcmpByte;
+ }
+
+ if(nDcmpByte == 0x101) // Huffman tree needs to be modified
+ {
+ n8Bits = is->Get8Bits();
+ pItem1 = (PTR_INVALID_OR_NULL(pLast)) ? NULL : pLast;
+
+ pItem2 = Call1500E740(1);
+ pItem2->parent = pItem1;
+ pItem2->dcmpByte = pItem1->dcmpByte;
+ pItem2->byteValue = pItem1->byteValue;
+ items306C[pItem2->dcmpByte] = pItem2;
+
+ pItem2 = Call1500E740(1);
+ pItem2->parent = pItem1;
+ pItem2->dcmpByte = n8Bits;
+ pItem2->byteValue = 0;
+ items306C[pItem2->dcmpByte] = pItem2;
+
+ pItem1->child = pItem2;
+ Call1500E820(pItem2);
+ if(bIsCmp0 == 0)
+ Call1500E820(items306C[n8Bits]);
+
+ nDcmpByte = n8Bits;
+ }
+
+ if(nDcmpByte == 0x100)
+ break;
+
+ *pbOutPos++ = (unsigned char)nDcmpByte;
+ if(--dwOutLength == 0)
+ break;
+
+ if(bIsCmp0)
+ Call1500E820(items306C[nDcmpByte]);
+ }
+
+ return (unsigned int)(pbOutPos - pbOutBuffer);
+}
+
+
+// Table for (de)compression. Every compression type has 258 entries
+unsigned char THuffmannTree::Table1502A630[] =
+{
+ // Data for compression type 0x00
+ 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00,
+
+ // Data for compression type 0x01
+ 0x54, 0x16, 0x16, 0x0D, 0x0C, 0x08, 0x06, 0x05, 0x06, 0x05, 0x06, 0x03, 0x04, 0x04, 0x03, 0x05,
+ 0x0E, 0x0B, 0x14, 0x13, 0x13, 0x09, 0x0B, 0x06, 0x05, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02,
+ 0x0D, 0x07, 0x09, 0x06, 0x06, 0x04, 0x03, 0x02, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02,
+ 0x09, 0x06, 0x04, 0x04, 0x04, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x04,
+ 0x08, 0x03, 0x04, 0x07, 0x09, 0x05, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02,
+ 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02,
+ 0x06, 0x0A, 0x08, 0x08, 0x06, 0x07, 0x04, 0x03, 0x04, 0x04, 0x02, 0x02, 0x04, 0x02, 0x03, 0x03,
+ 0x04, 0x03, 0x07, 0x07, 0x09, 0x06, 0x04, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x0A, 0x02, 0x02, 0x03, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x03, 0x05, 0x02, 0x03,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x04, 0x04, 0x07, 0x09, 0x08, 0x0C, 0x02,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03,
+ 0x04, 0x01, 0x02, 0x04, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x4B,
+ 0x00, 0x00,
+
+ // Data for compression type 0x02
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x27, 0x00, 0x00, 0x23, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x06, 0x0E, 0x10, 0x04,
+ 0x06, 0x08, 0x05, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x01, 0x01, 0x02, 0x01, 0x01,
+ 0x01, 0x04, 0x02, 0x04, 0x02, 0x02, 0x02, 0x01, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x03, 0x02,
+ 0x03, 0x01, 0x03, 0x06, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01,
+ 0x01, 0x29, 0x07, 0x16, 0x12, 0x40, 0x0A, 0x0A, 0x11, 0x25, 0x01, 0x03, 0x17, 0x10, 0x26, 0x2A,
+ 0x10, 0x01, 0x23, 0x23, 0x2F, 0x10, 0x06, 0x07, 0x02, 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+
+ // Data for compression type 0x03
+ 0xFF, 0x0B, 0x07, 0x05, 0x0B, 0x02, 0x02, 0x02, 0x06, 0x02, 0x02, 0x01, 0x04, 0x02, 0x01, 0x03,
+ 0x09, 0x01, 0x01, 0x01, 0x03, 0x04, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
+ 0x05, 0x01, 0x01, 0x01, 0x0D, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
+ 0x0A, 0x04, 0x02, 0x01, 0x06, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01,
+ 0x05, 0x02, 0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x03, 0x03,
+ 0x01, 0x03, 0x01, 0x01, 0x02, 0x05, 0x01, 0x01, 0x04, 0x03, 0x05, 0x01, 0x03, 0x01, 0x03, 0x03,
+ 0x02, 0x01, 0x04, 0x03, 0x0A, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x02, 0x01, 0x0A, 0x02, 0x05, 0x01, 0x01, 0x02, 0x07, 0x02, 0x17, 0x01, 0x05, 0x01, 0x01,
+ 0x0E, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x06, 0x02, 0x01, 0x04, 0x05, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11,
+ 0x00, 0x00,
+
+ // Data for compression type 0x04
+ 0xFF, 0xFB, 0x98, 0x9A, 0x84, 0x85, 0x63, 0x64, 0x3E, 0x3E, 0x22, 0x22, 0x13, 0x13, 0x18, 0x17,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+
+ // Data for compression type 0x05
+ 0xFF, 0xF1, 0x9D, 0x9E, 0x9A, 0x9B, 0x9A, 0x97, 0x93, 0x93, 0x8C, 0x8E, 0x86, 0x88, 0x80, 0x82,
+ 0x7C, 0x7C, 0x72, 0x73, 0x69, 0x6B, 0x5F, 0x60, 0x55, 0x56, 0x4A, 0x4B, 0x40, 0x41, 0x37, 0x37,
+ 0x2F, 0x2F, 0x27, 0x27, 0x21, 0x21, 0x1B, 0x1C, 0x17, 0x17, 0x13, 0x13, 0x10, 0x10, 0x0D, 0x0D,
+ 0x0B, 0x0B, 0x09, 0x09, 0x08, 0x08, 0x07, 0x07, 0x06, 0x05, 0x05, 0x04, 0x04, 0x04, 0x19, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+
+ // Data for compression type 0x06
+ 0xC3, 0xCB, 0xF5, 0x41, 0xFF, 0x7B, 0xF7, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xBF, 0xCC, 0xF2, 0x40, 0xFD, 0x7C, 0xF7, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7A, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+
+ // Data for compression type 0x07
+ 0xC3, 0xD9, 0xEF, 0x3D, 0xF9, 0x7C, 0xE9, 0x1E, 0xFD, 0xAB, 0xF1, 0x2C, 0xFC, 0x5B, 0xFE, 0x17,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xBD, 0xD9, 0xEC, 0x3D, 0xF5, 0x7D, 0xE8, 0x1D, 0xFB, 0xAE, 0xF0, 0x2C, 0xFB, 0x5C, 0xFF, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+
+ // Data for compression type 0x08
+ 0xBA, 0xC5, 0xDA, 0x33, 0xE3, 0x6D, 0xD8, 0x18, 0xE5, 0x94, 0xDA, 0x23, 0xDF, 0x4A, 0xD1, 0x10,
+ 0xEE, 0xAF, 0xE4, 0x2C, 0xEA, 0x5A, 0xDE, 0x15, 0xF4, 0x87, 0xE9, 0x21, 0xF6, 0x43, 0xFC, 0x12,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xB0, 0xC7, 0xD8, 0x33, 0xE3, 0x6B, 0xD6, 0x18, 0xE7, 0x95, 0xD8, 0x23, 0xDB, 0x49, 0xD0, 0x11,
+ 0xE9, 0xB2, 0xE2, 0x2B, 0xE8, 0x5C, 0xDD, 0x15, 0xF1, 0x87, 0xE7, 0x20, 0xF7, 0x44, 0xFF, 0x13,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5F, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00
+};
diff --git a/dep/StormLib/src/huffman/huff_patch.h b/dep/StormLib/src/huffman/huff_patch.h
new file mode 100644
index 00000000000..c1c03e67860
--- /dev/null
+++ b/dep/StormLib/src/huffman/huff_patch.h
@@ -0,0 +1,145 @@
+/*****************************************************************************/
+/* huffman.h Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Description : */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* xx.xx.xx 1.00 Lad The first version of huffman.h */
+/* 03.05.03 2.00 Lad Added compression */
+/* 08.12.03 2.01 Dan High-memory handling (> 0x80000000) */
+/*****************************************************************************/
+
+#ifndef __HUFFMAN_H__
+#define __HUFFMAN_H__
+
+#include <stdint.h>
+
+#define SIntPtr intptr_t
+
+//-----------------------------------------------------------------------------
+// Defines
+
+#define INSERT_ITEM 1
+#define SWITCH_ITEMS 2 // Switch the item1 and item2
+
+#define PTR_NOT(ptr) ((ptr) == gcpFirst ? gpFirst : gpItem3054)
+#define PTR_PTR(ptr) ((THTreeItem *)(ptr))
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+//-----------------------------------------------------------------------------
+// Structures and classes
+
+// Input stream for Huffmann decompression
+class TInputStream
+{
+ public:
+
+ unsigned long GetBit();
+ unsigned long Get7Bits();
+ unsigned long Get8Bits();
+ void SkipBits(unsigned int BitCount);
+
+ unsigned char * pbInBuffer; // Input data
+ unsigned char * pbInBufferEnd; // End of the input buffer
+ unsigned long BitBuffer; // Input bit buffer
+ unsigned int BitCount; // Number of bits remaining in 'dwBitBuff'
+};
+
+// Output stream for Huffmann compression
+class TOutputStream
+{
+ public:
+
+ void PutBits(unsigned long dwBuff, unsigned int nPutBits);
+
+ unsigned char * pbOutBuffer; // 00 : Output buffer
+ unsigned long cbOutSize; // 04 : Size of output buffer
+ unsigned char * pbOutPos; // 08 : Current output position
+ unsigned long dwBitBuff; // 0C : Bit buffer
+ unsigned long nBits; // 10 : Number of bits in the bit buffer
+};
+
+// Huffmann tree item (?)
+struct THTreeItem
+{
+ public:
+
+ THTreeItem * Call1501DB70(THTreeItem * pLast);
+ THTreeItem * GetPrevItem(SIntPtr value);
+ void ClearItemLinks();
+ void RemoveItem();
+
+ THTreeItem * next; // 00 - Pointer to next THTreeItem
+ THTreeItem * prev; // 04 - Pointer to prev THTreeItem (< 0 if none)
+ unsigned long dcmpByte; // 08 - Index of this item in item pointer array, decompressed byte value
+ unsigned long byteValue; // 0C - Some byte value
+ THTreeItem * parent; // 10 - Pointer to parent THTreeItem (NULL if none)
+ THTreeItem * child; // 14 - Pointer to child THTreeItem
+ int addressMultiplier; // -1 if object on negative address (>0x80000000), +1 if positive
+};
+
+// Structure used for quick decompress. The 'bitCount' contains number of bits
+// and byte value contains result decompressed byte value.
+// After each walk through Huffman tree are filled all entries which are
+// multiplies of number of bits loaded from input stream. These entries
+// contain number of bits and result value. At the next 7 bits is tested this
+// structure first. If corresponding entry found, decompression routine will
+// not walk through Huffman tree and directly stores output byte to output stream.
+struct TQDecompress
+{
+ unsigned long offs00; // 00 - 1 if resolved
+ unsigned long nBits; // 04 - Bit count
+ union
+ {
+ unsigned long dcmpByte; // 08 - Byte value for decompress (if bitCount <= 7)
+ THTreeItem * pItem; // 08 - THTreeItem (if number of bits is greater than 7
+ };
+};
+
+// Structure for Huffman tree (Size 0x3674 bytes). Because I'm not expert
+// for the decompression, I do not know actually if the class is really a Hufmann
+// tree. If someone knows the decompression details, please let me know
+class THuffmannTree
+{
+ public:
+
+ THuffmannTree();
+ void InitTree(bool bCompression);
+ void BuildTree(unsigned int nCmpType);
+// void ModifyTree(unsigned long dwIndex);
+// void UninitTree();
+
+// void Call15007010(Bit32 dwInLength, THTreeItem * item);
+ THTreeItem * Call1500E740(unsigned int nValue);
+ void Call1500E820(THTreeItem * pItem);
+ unsigned int DoCompression(TOutputStream * os, unsigned char * pbInBuffer, int nInLength, int nCmpType);
+ unsigned int DoDecompression(unsigned char * pbOutBuffer, unsigned int dwOutLength, TInputStream * is);
+
+ unsigned long bIsCmp0; // 0000 - 1 if compression type 0
+ unsigned long offs0004; // 0004 - Some flag
+ THTreeItem items0008[0x203]; // 0008 - HTree items
+
+ //- Sometimes used as HTree item -----------
+ THTreeItem * pItem3050; // 3050 - Always NULL (?)
+ THTreeItem * pItem3054; // 3054 - Pointer to Huffman tree item
+ THTreeItem * pItem3058; // 3058 - Pointer to Huffman tree item (< 0 if invalid)
+
+ //- Sometimes used as HTree item -----------
+ THTreeItem * pItem305C; // 305C - Usually NULL
+ THTreeItem * pFirst; // 3060 - Pointer to top (first) Huffman tree item
+ THTreeItem * pLast; // 3064 - Pointer to bottom (last) Huffman tree item (< 0 if invalid)
+ unsigned long nItems; // 3068 - Number of used HTree items
+
+ //-------------------------------------------
+ THTreeItem * items306C[0x102]; // 306C - THTreeItem pointer array
+ TQDecompress qd3474[0x80]; // 3474 - Array for quick decompression
+ int addressMultiplier; // -1 if object on negative address (>0x80000000), +1 if positive
+
+ static unsigned char Table1502A630[];// Some table
+};
+
+#endif // __HUFFMAN_H__
diff --git a/dep/StormLib/src/jenkins/lookup.h b/dep/StormLib/src/jenkins/lookup.h
new file mode 100644
index 00000000000..54ccc979ca6
--- /dev/null
+++ b/dep/StormLib/src/jenkins/lookup.h
@@ -0,0 +1,24 @@
+#ifndef __LOOKUP3_H__
+#define __LOOKUP3_H__
+
+#ifdef WIN32
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+#else
+#include <stdint.h> /* defines uint32_t etc */
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+uint32_t hashlittle(const void *key, size_t length, uint32_t initval);
+void hashlittle2(const void *key, size_t length, uint32_t *pc, uint32_t *pb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LOOKUP3_H__
diff --git a/dep/StormLib/src/jenkins/lookup3.c b/dep/StormLib/src/jenkins/lookup3.c
new file mode 100644
index 00000000000..6af56b481ad
--- /dev/null
+++ b/dep/StormLib/src/jenkins/lookup3.c
@@ -0,0 +1,1003 @@
+/*
+-------------------------------------------------------------------------------
+lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+
+These are functions for producing 32-bit hashes for hash table lookup.
+hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
+are externally useful functions. Routines to test the hash are included
+if SELF_TEST is defined. You can use this free for any purpose. It's in
+the public domain. It has no warranty.
+
+You probably want to use hashlittle(). hashlittle() and hashbig()
+hash byte arrays. hashlittle() is is faster than hashbig() on
+little-endian machines. Intel and AMD are little-endian machines.
+On second thought, you probably want hashlittle2(), which is identical to
+hashlittle() except it returns two 32-bit hashes for the price of one.
+You could implement hashbig2() if you wanted but I haven't bothered here.
+
+If you want to find a hash of, say, exactly 7 integers, do
+ a = i1; b = i2; c = i3;
+ mix(a,b,c);
+ a += i4; b += i5; c += i6;
+ mix(a,b,c);
+ a += i7;
+ final(a,b,c);
+then use c as the hash value. If you have a variable length array of
+4-byte integers to hash, use hashword(). If you have a byte array (like
+a character string), use hashlittle(). If you have several byte arrays, or
+a mix of things, see the comments above hashlittle().
+
+Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
+then mix those integers. This is fast (you can do a lot more thorough
+mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+-------------------------------------------------------------------------------
+*/
+//#define SELF_TEST 1
+
+#include <stdio.h> /* defines printf for tests */
+#include <time.h> /* defines time_t for timings in the test */
+
+#ifdef linux
+#include <sys/param.h> /* attempt to define endianness */
+#include <endian.h> /* attempt to define endianness */
+#endif
+
+#include "lookup.h"
+
+/*
+ * My best guess at if you are big-endian or little-endian. This may
+ * need adjustment.
+ */
+#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
+ __BYTE_ORDER == __LITTLE_ENDIAN) || \
+ (defined(i386) || defined(__i386__) || defined(__i486__) || \
+ defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL))
+# define HASH_LITTLE_ENDIAN 1
+# define HASH_BIG_ENDIAN 0
+#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
+ __BYTE_ORDER == __BIG_ENDIAN) || \
+ (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 1
+#else
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 0
+#endif
+
+#define hashsize(n) ((uint32_t)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/*
+-------------------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+
+This is reversible, so any information in (a,b,c) before mix() is
+still in (a,b,c) after mix().
+
+If four pairs of (a,b,c) inputs are run through mix(), or through
+mix() in reverse, there are at least 32 bits of the output that
+are sometimes the same for one pair and different for another pair.
+This was tested for:
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
+satisfy this are
+ 4 6 8 16 19 4
+ 9 15 3 18 27 15
+ 14 9 3 7 17 3
+Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+for "differ" defined as + with a one-bit base and a two-bit delta. I
+used http://burtleburtle.net/bob/hash/avalanche.html to choose
+the operations, constants, and arrangements of the variables.
+
+This does not achieve avalanche. There are input bits of (a,b,c)
+that fail to affect some output bits of (a,b,c), especially of a. The
+most thoroughly mixed value is c, but it doesn't really even achieve
+avalanche in c.
+
+This allows some parallelism. Read-after-writes are good at doubling
+the number of bits affected, so the goal of mixing pulls in the opposite
+direction as the goal of parallelism. I did what I could. Rotates
+seem to cost as much as shifts on every machine I could lay my hands
+on, and rotates are much kinder to the top and bottom bits, so I used
+rotates.
+-------------------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+}
+
+/*
+-------------------------------------------------------------------------------
+final -- final mixing of 3 32-bit values (a,b,c) into c
+
+Pairs of (a,b,c) values differing in only a few bits will usually
+produce values of c that look totally different. This was tested for
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+These constants passed:
+ 14 11 25 16 4 14 24
+ 12 14 25 16 4 14 24
+and these came close:
+ 4 8 15 26 3 22 24
+ 10 8 15 26 3 22 24
+ 11 8 15 26 3 22 24
+-------------------------------------------------------------------------------
+*/
+#define final(a,b,c) \
+{ \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+
+/*
+--------------------------------------------------------------------
+ This works on all machines. To be useful, it requires
+ -- that the key be an array of uint32_t's, and
+ -- that the length be the number of uint32_t's in the key
+
+ The function hashword() is identical to hashlittle() on little-endian
+ machines, and identical to hashbig() on big-endian machines,
+ except that the length has to be measured in uint32_ts rather than in
+ bytes. hashlittle() is more complicated than hashword() only because
+ hashlittle() has to dance around fitting the key bytes into registers.
+--------------------------------------------------------------------
+*/
+uint32_t hashword(
+const uint32_t *k, /* the key, an array of uint32_t values */
+size_t length, /* the length of the key, in uint32_ts */
+uint32_t initval) /* the previous hash, or an arbitrary value */
+{
+ uint32_t a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval;
+
+ /*------------------------------------------------- handle most of the key */
+ while (length > 3)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 3;
+ k += 3;
+ }
+
+ /*------------------------------------------- handle the last 3 uint32_t's */
+ switch(length) /* all the case statements fall through */
+ {
+ case 3 : c+=k[2];
+ case 2 : b+=k[1];
+ case 1 : a+=k[0];
+ final(a,b,c);
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
+ /*------------------------------------------------------ report the result */
+ return c;
+}
+
+
+/*
+--------------------------------------------------------------------
+hashword2() -- same as hashword(), but take two seeds and return two
+32-bit values. pc and pb must both be nonnull, and *pc and *pb must
+both be initialized with seeds. If you pass in (*pb)==0, the output
+(*pc) will be the same as the return value from hashword().
+--------------------------------------------------------------------
+*/
+void hashword2 (
+const uint32_t *k, /* the key, an array of uint32_t values */
+size_t length, /* the length of the key, in uint32_ts */
+uint32_t *pc, /* IN: seed OUT: primary hash value */
+uint32_t *pb) /* IN: more seed OUT: secondary hash value */
+{
+ uint32_t a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)(length<<2)) + *pc;
+ c += *pb;
+
+ /*------------------------------------------------- handle most of the key */
+ while (length > 3)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 3;
+ k += 3;
+ }
+
+ /*------------------------------------------- handle the last 3 uint32_t's */
+ switch(length) /* all the case statements fall through */
+ {
+ case 3 : c+=k[2];
+ case 2 : b+=k[1];
+ case 1 : a+=k[0];
+ final(a,b,c);
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
+ /*------------------------------------------------------ report the result */
+ *pc=c; *pb=b;
+}
+
+
+/*
+-------------------------------------------------------------------------------
+hashlittle() -- hash a variable-length key into a 32-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ length : the length of the key, counting by bytes
+ initval : can be any 4-byte value
+Returns a 32-bit value. Every bit of the key affects every bit of
+the return value. Two keys differing by one or two bits will have
+totally different hash values.
+
+The best hash table sizes are powers of 2. There is no need to do
+mod a prime (mod is sooo slow!). If you need less than 32 bits,
+use a bitmask. For example, if you need only 10 bits, do
+ h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (uint8_t **)k, do it like this:
+ for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
+
+By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
+code any way you wish, private, educational, or commercial. It's free.
+
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable. Do NOT use for cryptographic purposes.
+-------------------------------------------------------------------------------
+*/
+
+uint32_t hashlittle( const void *key, size_t length, uint32_t initval)
+{
+ uint32_t a,b,c; /* internal state */
+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+ const uint8_t *k8;
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
+ case 1 : a+=k8[0]; break;
+ case 0 : return c;
+ }
+
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
+ const uint8_t *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((uint32_t)k[1])<<16);
+ b += k[2] + (((uint32_t)k[3])<<16);
+ c += k[4] + (((uint32_t)k[5])<<16);
+ mix(a,b,c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=k[4];
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=k[2];
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : return c; /* zero length requires no mixing */
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((uint32_t)k[1])<<8;
+ a += ((uint32_t)k[2])<<16;
+ a += ((uint32_t)k[3])<<24;
+ b += k[4];
+ b += ((uint32_t)k[5])<<8;
+ b += ((uint32_t)k[6])<<16;
+ b += ((uint32_t)k[7])<<24;
+ c += k[8];
+ c += ((uint32_t)k[9])<<8;
+ c += ((uint32_t)k[10])<<16;
+ c += ((uint32_t)k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=((uint32_t)k[11])<<24;
+ case 11: c+=((uint32_t)k[10])<<16;
+ case 10: c+=((uint32_t)k[9])<<8;
+ case 9 : c+=k[8];
+ case 8 : b+=((uint32_t)k[7])<<24;
+ case 7 : b+=((uint32_t)k[6])<<16;
+ case 6 : b+=((uint32_t)k[5])<<8;
+ case 5 : b+=k[4];
+ case 4 : a+=((uint32_t)k[3])<<24;
+ case 3 : a+=((uint32_t)k[2])<<16;
+ case 2 : a+=((uint32_t)k[1])<<8;
+ case 1 : a+=k[0];
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a,b,c);
+ return c;
+}
+
+
+/*
+ * hashlittle2: return 2 32-bit hash values
+ *
+ * This is identical to hashlittle(), except it returns two 32-bit hash
+ * values instead of just one. This is good enough for hash table
+ * lookup with 2^^64 buckets, or if you want a second hash if you're not
+ * happy with the first, or if you want a probably-unique 64-bit ID for
+ * the key. *pc is better mixed than *pb, so use *pc first. If you want
+ * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)".
+ */
+void hashlittle2(
+ const void *key, /* the key to hash */
+ size_t length, /* length of the key */
+ uint32_t *pc, /* IN: primary initval, OUT: primary hash */
+ uint32_t *pb) /* IN: secondary initval, OUT: secondary hash */
+{
+ uint32_t a,b,c; /* internal state */
+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)length) + *pc;
+ c += *pb;
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+ const uint8_t *k8;
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
+ case 1 : a+=k8[0]; break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
+ const uint8_t *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((uint32_t)k[1])<<16);
+ b += k[2] + (((uint32_t)k[3])<<16);
+ c += k[4] + (((uint32_t)k[5])<<16);
+ mix(a,b,c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=k[4];
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=k[2];
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((uint32_t)k[1])<<8;
+ a += ((uint32_t)k[2])<<16;
+ a += ((uint32_t)k[3])<<24;
+ b += k[4];
+ b += ((uint32_t)k[5])<<8;
+ b += ((uint32_t)k[6])<<16;
+ b += ((uint32_t)k[7])<<24;
+ c += k[8];
+ c += ((uint32_t)k[9])<<8;
+ c += ((uint32_t)k[10])<<16;
+ c += ((uint32_t)k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=((uint32_t)k[11])<<24;
+ case 11: c+=((uint32_t)k[10])<<16;
+ case 10: c+=((uint32_t)k[9])<<8;
+ case 9 : c+=k[8];
+ case 8 : b+=((uint32_t)k[7])<<24;
+ case 7 : b+=((uint32_t)k[6])<<16;
+ case 6 : b+=((uint32_t)k[5])<<8;
+ case 5 : b+=k[4];
+ case 4 : a+=((uint32_t)k[3])<<24;
+ case 3 : a+=((uint32_t)k[2])<<16;
+ case 2 : a+=((uint32_t)k[1])<<8;
+ case 1 : a+=k[0];
+ break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+ }
+
+ final(a,b,c);
+ *pc=c; *pb=b;
+}
+
+
+
+/*
+ * hashbig():
+ * This is the same as hashword() on big-endian machines. It is different
+ * from hashlittle() on all machines. hashbig() takes advantage of
+ * big-endian byte ordering.
+ */
+uint32_t hashbig( const void *key, size_t length, uint32_t initval)
+{
+ uint32_t a,b,c;
+ union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
+
+ u.ptr = key;
+ if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+ const uint8_t *k8;
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]<<8" actually reads beyond the end of the string, but
+ * then shifts out the part it's not allowed to read. Because the
+ * string is aligned, the illegal read is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff00; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff0000; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff000000; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff00; break;
+ case 2 : a+=k[0]&0xffff0000; break;
+ case 1 : a+=k[0]&0xff000000; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((uint32_t)k8[10])<<8; /* fall through */
+ case 10: c+=((uint32_t)k8[9])<<16; /* fall through */
+ case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */
+ case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */
+ case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */
+ case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */
+ case 1 : a+=((uint32_t)k8[0])<<24; break;
+ case 0 : return c;
+ }
+
+#endif /* !VALGRIND */
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += ((uint32_t)k[0])<<24;
+ a += ((uint32_t)k[1])<<16;
+ a += ((uint32_t)k[2])<<8;
+ a += ((uint32_t)k[3]);
+ b += ((uint32_t)k[4])<<24;
+ b += ((uint32_t)k[5])<<16;
+ b += ((uint32_t)k[6])<<8;
+ b += ((uint32_t)k[7]);
+ c += ((uint32_t)k[8])<<24;
+ c += ((uint32_t)k[9])<<16;
+ c += ((uint32_t)k[10])<<8;
+ c += ((uint32_t)k[11]);
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=k[11];
+ case 11: c+=((uint32_t)k[10])<<8;
+ case 10: c+=((uint32_t)k[9])<<16;
+ case 9 : c+=((uint32_t)k[8])<<24;
+ case 8 : b+=k[7];
+ case 7 : b+=((uint32_t)k[6])<<8;
+ case 6 : b+=((uint32_t)k[5])<<16;
+ case 5 : b+=((uint32_t)k[4])<<24;
+ case 4 : a+=k[3];
+ case 3 : a+=((uint32_t)k[2])<<8;
+ case 2 : a+=((uint32_t)k[1])<<16;
+ case 1 : a+=((uint32_t)k[0])<<24;
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a,b,c);
+ return c;
+}
+
+
+#ifdef SELF_TEST
+
+/* used for timings */
+void driver1()
+{
+ uint8_t buf[256];
+ uint32_t i;
+ uint32_t h=0;
+ time_t a,z;
+
+ time(&a);
+ for (i=0; i<256; ++i) buf[i] = 'x';
+ for (i=0; i<1; ++i)
+ {
+ h = hashlittle(&buf[0],1,h);
+ }
+ time(&z);
+ if (z-a > 0) printf("time %d %.8x\n", z-a, h);
+}
+
+/* check that every input bit changes every output bit half the time */
+#define HASHSTATE 1
+#define HASHLEN 1
+#define MAXPAIR 60
+#define MAXLEN 70
+void driver2()
+{
+ uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1];
+ uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z;
+ uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE];
+ uint32_t x[HASHSTATE],y[HASHSTATE];
+ uint32_t hlen;
+
+ printf("No more than %d trials should ever be needed \n",MAXPAIR/2);
+ for (hlen=0; hlen < MAXLEN; ++hlen)
+ {
+ z=0;
+ for (i=0; i<hlen; ++i) /*----------------------- for each input byte, */
+ {
+ for (j=0; j<8; ++j) /*------------------------ for each input bit, */
+ {
+ for (m=1; m<8; ++m) /*------------ for serveral possible initvals, */
+ {
+ for (l=0; l<HASHSTATE; ++l)
+ e[l]=f[l]=g[l]=h[l]=x[l]=y[l]=~((uint32_t)0);
+
+ /*---- check that every output bit is affected by that input bit */
+ for (k=0; k<MAXPAIR; k+=2)
+ {
+ uint32_t finished=1;
+ /* keys have one bit different */
+ for (l=0; l<hlen+1; ++l) {a[l] = b[l] = (uint8_t)0;}
+ /* have a and b be two keys differing in only one bit */
+ a[i] ^= (k<<j);
+ a[i] ^= (k>>(8-j));
+ c[0] = hashlittle(a, hlen, m);
+ b[i] ^= ((k+1)<<j);
+ b[i] ^= ((k+1)>>(8-j));
+ d[0] = hashlittle(b, hlen, m);
+ /* check every bit is 1, 0, set, and not set at least once */
+ for (l=0; l<HASHSTATE; ++l)
+ {
+ e[l] &= (c[l]^d[l]);
+ f[l] &= ~(c[l]^d[l]);
+ g[l] &= c[l];
+ h[l] &= ~c[l];
+ x[l] &= d[l];
+ y[l] &= ~d[l];
+ if (e[l]|f[l]|g[l]|h[l]|x[l]|y[l]) finished=0;
+ }
+ if (finished) break;
+ }
+ if (k>z) z=k;
+ if (k==MAXPAIR)
+ {
+ printf("Some bit didn't change: ");
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x ",
+ e[0],f[0],g[0],h[0],x[0],y[0]);
+ printf("i %d j %d m %d len %d\n", i, j, m, hlen);
+ }
+ if (z==MAXPAIR) goto done;
+ }
+ }
+ }
+ done:
+ if (z < MAXPAIR)
+ {
+ printf("Mix success %2d bytes %2d initvals ",i,m);
+ printf("required %d trials\n", z/2);
+ }
+ }
+ printf("\n");
+}
+
+/* Check for reading beyond the end of the buffer and alignment problems */
+void driver3()
+{
+ uint8_t buf[MAXLEN+20], *b;
+ uint32_t len;
+ uint8_t q[] = "This is the time for all good men to come to the aid of their country...";
+ uint32_t h;
+ uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country...";
+ uint32_t i;
+ uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country...";
+ uint32_t j;
+ uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country...";
+ uint32_t ref,x,y;
+ uint8_t *p;
+
+ printf("Endianness. These lines should all be the same (for values filled in):\n");
+ printf("%.8x %.8x %.8x\n",
+ hashword((const uint32_t *)q, (sizeof(q)-1)/4, 13),
+ hashword((const uint32_t *)q, (sizeof(q)-5)/4, 13),
+ hashword((const uint32_t *)q, (sizeof(q)-9)/4, 13));
+ p = q;
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ p = &qq[1];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ p = &qqq[2];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ p = &qqqq[3];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ printf("\n");
+
+ /* check that hashlittle2 and hashlittle produce the same results */
+ i=47; j=0;
+ hashlittle2(q, sizeof(q), &i, &j);
+ if (hashlittle(q, sizeof(q), 47) != i)
+ printf("hashlittle2 and hashlittle mismatch\n");
+
+ /* check that hashword2 and hashword produce the same results */
+ len = 0xdeadbeef;
+ i=47, j=0;
+ hashword2(&len, 1, &i, &j);
+ if (hashword(&len, 1, 47) != i)
+ printf("hashword2 and hashword mismatch %x %x\n",
+ i, hashword(&len, 1, 47));
+
+ /* check hashlittle doesn't read before or after the ends of the string */
+ for (h=0, b=buf+1; h<8; ++h, ++b)
+ {
+ for (i=0; i<MAXLEN; ++i)
+ {
+ len = i;
+ for (j=0; j<i; ++j) *(b+j)=0;
+
+ /* these should all be equal */
+ ref = hashlittle(b, len, (uint32_t)1);
+ *(b+i)=(uint8_t)~0;
+ *(b-1)=(uint8_t)~0;
+ x = hashlittle(b, len, (uint32_t)1);
+ y = hashlittle(b, len, (uint32_t)1);
+ if ((ref != x) || (ref != y))
+ {
+ printf("alignment error: %.8x %.8x %.8x %d %d\n",ref,x,y,
+ h, i);
+ }
+ }
+ }
+}
+
+/* check for problems with nulls */
+ void driver4()
+{
+ uint8_t buf[1];
+ uint32_t h,i,state[HASHSTATE];
+
+
+ buf[0] = ~0;
+ for (i=0; i<HASHSTATE; ++i) state[i] = 1;
+ printf("These should all be different\n");
+ for (i=0, h=0; i<8; ++i)
+ {
+ h = hashlittle(buf, 0, h);
+ printf("%2ld 0-byte strings, hash is %.8x\n", i, h);
+ }
+}
+
+void driver5()
+{
+ uint32_t b,c;
+ b=0, c=0, hashlittle2("", 0, &c, &b);
+ printf("hash is %.8lx %.8lx\n", c, b); /* deadbeef deadbeef */
+ b=0xdeadbeef, c=0, hashlittle2("", 0, &c, &b);
+ printf("hash is %.8lx %.8lx\n", c, b); /* bd5b7dde deadbeef */
+ b=0xdeadbeef, c=0xdeadbeef, hashlittle2("", 0, &c, &b);
+ printf("hash is %.8lx %.8lx\n", c, b); /* 9c093ccd bd5b7dde */
+ b=0, c=0, hashlittle2("Four score and seven years ago", 30, &c, &b);
+ printf("hash is %.8lx %.8lx\n", c, b); /* 17770551 ce7226e6 */
+ b=1, c=0, hashlittle2("Four score and seven years ago", 30, &c, &b);
+ printf("hash is %.8lx %.8lx\n", c, b); /* e3607cae bd371de4 */
+ b=0, c=1, hashlittle2("Four score and seven years ago", 30, &c, &b);
+ printf("hash is %.8lx %.8lx\n", c, b); /* cd628161 6cbea4b3 */
+ c = hashlittle("Four score and seven years ago", 30, 0);
+ printf("hash is %.8lx\n", c); /* 17770551 */
+ c = hashlittle("Four score and seven years ago", 30, 1);
+ printf("hash is %.8lx\n", c); /* cd628161 */
+}
+
+
+int main()
+{
+ driver1(); /* test that the key is hashed: used for timings */
+ driver2(); /* test that whole key is hashed thoroughly */
+ driver3(); /* test that nothing but the key is hashed */
+ driver4(); /* test hashing multiple buffers (all buffers are null) */
+ driver5(); /* test the hash against known vectors */
+ return 1;
+}
+
+#endif /* SELF_TEST */
diff --git a/dep/StormLib/src/libtomcrypt/src/hashes/hash_memory.c b/dep/StormLib/src/libtomcrypt/src/hashes/hash_memory.c
new file mode 100644
index 00000000000..1daf0bffa1b
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/hashes/hash_memory.c
@@ -0,0 +1,69 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+/**
+ @file hash_memory.c
+ Hash memory helper, Tom St Denis
+*/
+
+/**
+ Hash a block of memory and store the digest.
+ @param hash The index of the hash you wish to use
+ @param in The data you wish to hash
+ @param inlen The length of the data to hash (octets)
+ @param out [out] Where to store the digest
+ @param outlen [in/out] Max size and resulting size of the digest
+ @return CRYPT_OK if successful
+*/
+int hash_memory(int hash, const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen)
+{
+ hash_state *md;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+ return err;
+ }
+
+ if (*outlen < hash_descriptor[hash].hashsize) {
+ *outlen = hash_descriptor[hash].hashsize;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ md = XMALLOC(sizeof(hash_state));
+ if (md == NULL) {
+ return CRYPT_MEM;
+ }
+
+ if ((err = hash_descriptor[hash].init(md)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ if ((err = hash_descriptor[hash].process(md, in, inlen)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ err = hash_descriptor[hash].done(md, out);
+ *outlen = hash_descriptor[hash].hashsize;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+ zeromem(md, sizeof(hash_state));
+#endif
+ XFREE(md);
+
+ return err;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/hashes/helper/hash_memory.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:27:23 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/hashes/md5.c b/dep/StormLib/src/libtomcrypt/src/hashes/md5.c
new file mode 100644
index 00000000000..4cbd000c0d4
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/hashes/md5.c
@@ -0,0 +1,368 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+
+/**
+ @file md5.c
+ LTC_MD5 hash function by Tom St Denis
+*/
+
+#ifdef LTC_MD5
+
+const struct ltc_hash_descriptor md5_desc =
+{
+ "md5",
+ 3,
+ 16,
+ 64,
+
+ /* OID */
+ { 1, 2, 840, 113549, 2, 5, },
+ 6,
+
+ &md5_init,
+ &md5_process,
+ &md5_done,
+ &md5_test,
+ NULL
+};
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define G(x,y,z) (y ^ (z & (y ^ x)))
+#define H(x,y,z) (x^y^z)
+#define I(x,y,z) (y^(x|(~z)))
+
+#ifdef LTC_SMALL_CODE
+
+#define FF(a,b,c,d,M,s,t) \
+ a = (a + F(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define GG(a,b,c,d,M,s,t) \
+ a = (a + G(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define HH(a,b,c,d,M,s,t) \
+ a = (a + H(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define II(a,b,c,d,M,s,t) \
+ a = (a + I(b,c,d) + M + t); a = ROL(a, s) + b;
+
+static const unsigned char Worder[64] = {
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12,
+ 5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2,
+ 0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9
+};
+
+static const unsigned char Rorder[64] = {
+ 7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
+ 5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
+ 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
+ 6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
+};
+
+static const ulong32 Korder[64] = {
+0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL, 0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL,
+0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL, 0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL,
+0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL, 0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL,
+0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL, 0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL,
+0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL, 0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL,
+0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL, 0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL,
+0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL, 0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL,
+0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL, 0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL
+};
+
+#else
+
+#define FF(a,b,c,d,M,s,t) \
+ a = (a + F(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+#define GG(a,b,c,d,M,s,t) \
+ a = (a + G(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+#define HH(a,b,c,d,M,s,t) \
+ a = (a + H(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+#define II(a,b,c,d,M,s,t) \
+ a = (a + I(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+
+#endif
+
+#ifdef LTC_CLEAN_STACK
+static int _md5_compress(hash_state *md, unsigned char *buf)
+#else
+static int md5_compress(hash_state *md, unsigned char *buf)
+#endif
+{
+ ulong32 i, W[16], a, b, c, d;
+#ifdef LTC_SMALL_CODE
+ ulong32 t;
+#endif
+
+ /* copy the state into 512-bits into W[0..15] */
+ for (i = 0; i < 16; i++) {
+ LOAD32L(W[i], buf + (4*i));
+ }
+
+ /* copy state */
+ a = md->md5.state[0];
+ b = md->md5.state[1];
+ c = md->md5.state[2];
+ d = md->md5.state[3];
+
+#ifdef LTC_SMALL_CODE
+ for (i = 0; i < 16; ++i) {
+ FF(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+ t = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 32; ++i) {
+ GG(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+ t = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 48; ++i) {
+ HH(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+ t = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 64; ++i) {
+ II(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+ t = d; d = c; c = b; b = a; a = t;
+ }
+
+#else
+ FF(a,b,c,d,W[0],7,0xd76aa478UL)
+ FF(d,a,b,c,W[1],12,0xe8c7b756UL)
+ FF(c,d,a,b,W[2],17,0x242070dbUL)
+ FF(b,c,d,a,W[3],22,0xc1bdceeeUL)
+ FF(a,b,c,d,W[4],7,0xf57c0fafUL)
+ FF(d,a,b,c,W[5],12,0x4787c62aUL)
+ FF(c,d,a,b,W[6],17,0xa8304613UL)
+ FF(b,c,d,a,W[7],22,0xfd469501UL)
+ FF(a,b,c,d,W[8],7,0x698098d8UL)
+ FF(d,a,b,c,W[9],12,0x8b44f7afUL)
+ FF(c,d,a,b,W[10],17,0xffff5bb1UL)
+ FF(b,c,d,a,W[11],22,0x895cd7beUL)
+ FF(a,b,c,d,W[12],7,0x6b901122UL)
+ FF(d,a,b,c,W[13],12,0xfd987193UL)
+ FF(c,d,a,b,W[14],17,0xa679438eUL)
+ FF(b,c,d,a,W[15],22,0x49b40821UL)
+ GG(a,b,c,d,W[1],5,0xf61e2562UL)
+ GG(d,a,b,c,W[6],9,0xc040b340UL)
+ GG(c,d,a,b,W[11],14,0x265e5a51UL)
+ GG(b,c,d,a,W[0],20,0xe9b6c7aaUL)
+ GG(a,b,c,d,W[5],5,0xd62f105dUL)
+ GG(d,a,b,c,W[10],9,0x02441453UL)
+ GG(c,d,a,b,W[15],14,0xd8a1e681UL)
+ GG(b,c,d,a,W[4],20,0xe7d3fbc8UL)
+ GG(a,b,c,d,W[9],5,0x21e1cde6UL)
+ GG(d,a,b,c,W[14],9,0xc33707d6UL)
+ GG(c,d,a,b,W[3],14,0xf4d50d87UL)
+ GG(b,c,d,a,W[8],20,0x455a14edUL)
+ GG(a,b,c,d,W[13],5,0xa9e3e905UL)
+ GG(d,a,b,c,W[2],9,0xfcefa3f8UL)
+ GG(c,d,a,b,W[7],14,0x676f02d9UL)
+ GG(b,c,d,a,W[12],20,0x8d2a4c8aUL)
+ HH(a,b,c,d,W[5],4,0xfffa3942UL)
+ HH(d,a,b,c,W[8],11,0x8771f681UL)
+ HH(c,d,a,b,W[11],16,0x6d9d6122UL)
+ HH(b,c,d,a,W[14],23,0xfde5380cUL)
+ HH(a,b,c,d,W[1],4,0xa4beea44UL)
+ HH(d,a,b,c,W[4],11,0x4bdecfa9UL)
+ HH(c,d,a,b,W[7],16,0xf6bb4b60UL)
+ HH(b,c,d,a,W[10],23,0xbebfbc70UL)
+ HH(a,b,c,d,W[13],4,0x289b7ec6UL)
+ HH(d,a,b,c,W[0],11,0xeaa127faUL)
+ HH(c,d,a,b,W[3],16,0xd4ef3085UL)
+ HH(b,c,d,a,W[6],23,0x04881d05UL)
+ HH(a,b,c,d,W[9],4,0xd9d4d039UL)
+ HH(d,a,b,c,W[12],11,0xe6db99e5UL)
+ HH(c,d,a,b,W[15],16,0x1fa27cf8UL)
+ HH(b,c,d,a,W[2],23,0xc4ac5665UL)
+ II(a,b,c,d,W[0],6,0xf4292244UL)
+ II(d,a,b,c,W[7],10,0x432aff97UL)
+ II(c,d,a,b,W[14],15,0xab9423a7UL)
+ II(b,c,d,a,W[5],21,0xfc93a039UL)
+ II(a,b,c,d,W[12],6,0x655b59c3UL)
+ II(d,a,b,c,W[3],10,0x8f0ccc92UL)
+ II(c,d,a,b,W[10],15,0xffeff47dUL)
+ II(b,c,d,a,W[1],21,0x85845dd1UL)
+ II(a,b,c,d,W[8],6,0x6fa87e4fUL)
+ II(d,a,b,c,W[15],10,0xfe2ce6e0UL)
+ II(c,d,a,b,W[6],15,0xa3014314UL)
+ II(b,c,d,a,W[13],21,0x4e0811a1UL)
+ II(a,b,c,d,W[4],6,0xf7537e82UL)
+ II(d,a,b,c,W[11],10,0xbd3af235UL)
+ II(c,d,a,b,W[2],15,0x2ad7d2bbUL)
+ II(b,c,d,a,W[9],21,0xeb86d391UL)
+#endif
+
+ md->md5.state[0] = md->md5.state[0] + a;
+ md->md5.state[1] = md->md5.state[1] + b;
+ md->md5.state[2] = md->md5.state[2] + c;
+ md->md5.state[3] = md->md5.state[3] + d;
+
+ return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+static int md5_compress(hash_state *md, unsigned char *buf)
+{
+ int err;
+ err = _md5_compress(md, buf);
+ burn_stack(sizeof(ulong32) * 21);
+ return err;
+}
+#endif
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return CRYPT_OK if successful
+*/
+int md5_init(hash_state * md)
+{
+ LTC_ARGCHK(md != NULL);
+ md->md5.state[0] = 0x67452301UL;
+ md->md5.state[1] = 0xefcdab89UL;
+ md->md5.state[2] = 0x98badcfeUL;
+ md->md5.state[3] = 0x10325476UL;
+ md->md5.curlen = 0;
+ md->md5.length = 0;
+ return CRYPT_OK;
+}
+
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param in The data to hash
+ @param inlen The length of the data (octets)
+ @return CRYPT_OK if successful
+*/
+HASH_PROCESS(md5_process, md5_compress, md5, 64)
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (16 bytes)
+ @return CRYPT_OK if successful
+*/
+int md5_done(hash_state * md, unsigned char *out)
+{
+ int i;
+
+ LTC_ARGCHK(md != NULL);
+ LTC_ARGCHK(out != NULL);
+
+ if (md->md5.curlen >= sizeof(md->md5.buf)) {
+ return CRYPT_INVALID_ARG;
+ }
+
+
+ /* increase the length of the message */
+ md->md5.length += md->md5.curlen * 8;
+
+ /* append the '1' bit */
+ md->md5.buf[md->md5.curlen++] = (unsigned char)0x80;
+
+ /* if the length is currently above 56 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if (md->md5.curlen > 56) {
+ while (md->md5.curlen < 64) {
+ md->md5.buf[md->md5.curlen++] = (unsigned char)0;
+ }
+ md5_compress(md, md->md5.buf);
+ md->md5.curlen = 0;
+ }
+
+ /* pad upto 56 bytes of zeroes */
+ while (md->md5.curlen < 56) {
+ md->md5.buf[md->md5.curlen++] = (unsigned char)0;
+ }
+
+ /* store length */
+ STORE64L(md->md5.length, md->md5.buf+56);
+ md5_compress(md, md->md5.buf);
+
+ /* copy output */
+ for (i = 0; i < 4; i++) {
+ STORE32L(md->md5.state[i], out+(4*i));
+ }
+#ifdef LTC_CLEAN_STACK
+ zeromem(md, sizeof(hash_state));
+#endif
+ return CRYPT_OK;
+}
+
+/**
+ Self-test the hash
+ @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int md5_test(void)
+{
+ #ifndef LTC_TEST
+ return CRYPT_NOP;
+ #else
+ static const struct {
+ char *msg;
+ unsigned char hash[16];
+ } tests[] = {
+ { "",
+ { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
+ 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } },
+ { "a",
+ {0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8,
+ 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } },
+ { "abc",
+ { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0,
+ 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } },
+ { "message digest",
+ { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d,
+ 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } },
+ { "abcdefghijklmnopqrstuvwxyz",
+ { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00,
+ 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } },
+ { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5,
+ 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } },
+ { "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55,
+ 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } },
+ { NULL, { 0 } }
+ };
+
+ int i;
+ unsigned char tmp[16];
+ hash_state md;
+
+ for (i = 0; tests[i].msg != NULL; i++) {
+ md5_init(&md);
+ md5_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+ md5_done(&md, tmp);
+ if (XMEMCMP(tmp, tests[i].hash, 16) != 0) {
+ return CRYPT_FAIL_TESTVECTOR;
+ }
+ }
+ return CRYPT_OK;
+ #endif
+}
+
+#endif
+
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/hashes/md5.c,v $ */
+/* $Revision: 1.10 $ */
+/* $Date: 2007/05/12 14:25:28 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/hashes/sha1.c b/dep/StormLib/src/libtomcrypt/src/hashes/sha1.c
new file mode 100644
index 00000000000..409d0954241
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/hashes/sha1.c
@@ -0,0 +1,288 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+/**
+ @file sha1.c
+ LTC_SHA1 code by Tom St Denis
+*/
+
+
+#ifdef LTC_SHA1
+
+const struct ltc_hash_descriptor sha1_desc =
+{
+ "sha1",
+ 2,
+ 20,
+ 64,
+
+ /* OID */
+ { 1, 3, 14, 3, 2, 26, },
+ 6,
+
+ &sha1_init,
+ &sha1_process,
+ &sha1_done,
+ &sha1_test,
+ NULL
+};
+
+#define F0(x,y,z) (z ^ (x & (y ^ z)))
+#define F1(x,y,z) (x ^ y ^ z)
+#define F2(x,y,z) ((x & y) | (z & (x | y)))
+#define F3(x,y,z) (x ^ y ^ z)
+
+#ifdef LTC_CLEAN_STACK
+static int _sha1_compress(hash_state *md, unsigned char *buf)
+#else
+static int sha1_compress(hash_state *md, unsigned char *buf)
+#endif
+{
+ ulong32 a,b,c,d,e,W[80],i;
+#ifdef LTC_SMALL_CODE
+ ulong32 t;
+#endif
+
+ /* copy the state into 512-bits into W[0..15] */
+ for (i = 0; i < 16; i++) {
+ LOAD32H(W[i], buf + (4*i));
+ }
+
+ /* copy state */
+ a = md->sha1.state[0];
+ b = md->sha1.state[1];
+ c = md->sha1.state[2];
+ d = md->sha1.state[3];
+ e = md->sha1.state[4];
+
+ /* expand it */
+ for (i = 16; i < 80; i++) {
+ W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
+ }
+
+ /* compress */
+ /* round one */
+ #define FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30);
+ #define FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30);
+ #define FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30);
+ #define FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30);
+
+#ifdef LTC_SMALL_CODE
+
+ for (i = 0; i < 20; ) {
+ FF0(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 40; ) {
+ FF1(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 60; ) {
+ FF2(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 80; ) {
+ FF3(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+ }
+
+#else
+
+ for (i = 0; i < 20; ) {
+ FF0(a,b,c,d,e,i++);
+ FF0(e,a,b,c,d,i++);
+ FF0(d,e,a,b,c,i++);
+ FF0(c,d,e,a,b,i++);
+ FF0(b,c,d,e,a,i++);
+ }
+
+ /* round two */
+ for (; i < 40; ) {
+ FF1(a,b,c,d,e,i++);
+ FF1(e,a,b,c,d,i++);
+ FF1(d,e,a,b,c,i++);
+ FF1(c,d,e,a,b,i++);
+ FF1(b,c,d,e,a,i++);
+ }
+
+ /* round three */
+ for (; i < 60; ) {
+ FF2(a,b,c,d,e,i++);
+ FF2(e,a,b,c,d,i++);
+ FF2(d,e,a,b,c,i++);
+ FF2(c,d,e,a,b,i++);
+ FF2(b,c,d,e,a,i++);
+ }
+
+ /* round four */
+ for (; i < 80; ) {
+ FF3(a,b,c,d,e,i++);
+ FF3(e,a,b,c,d,i++);
+ FF3(d,e,a,b,c,i++);
+ FF3(c,d,e,a,b,i++);
+ FF3(b,c,d,e,a,i++);
+ }
+#endif
+
+ #undef FF0
+ #undef FF1
+ #undef FF2
+ #undef FF3
+
+ /* store */
+ md->sha1.state[0] = md->sha1.state[0] + a;
+ md->sha1.state[1] = md->sha1.state[1] + b;
+ md->sha1.state[2] = md->sha1.state[2] + c;
+ md->sha1.state[3] = md->sha1.state[3] + d;
+ md->sha1.state[4] = md->sha1.state[4] + e;
+
+ return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+static int sha1_compress(hash_state *md, unsigned char *buf)
+{
+ int err;
+ err = _sha1_compress(md, buf);
+ burn_stack(sizeof(ulong32) * 87);
+ return err;
+}
+#endif
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return CRYPT_OK if successful
+*/
+int sha1_init(hash_state * md)
+{
+ LTC_ARGCHK(md != NULL);
+ md->sha1.state[0] = 0x67452301UL;
+ md->sha1.state[1] = 0xefcdab89UL;
+ md->sha1.state[2] = 0x98badcfeUL;
+ md->sha1.state[3] = 0x10325476UL;
+ md->sha1.state[4] = 0xc3d2e1f0UL;
+ md->sha1.curlen = 0;
+ md->sha1.length = 0;
+ return CRYPT_OK;
+}
+
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param in The data to hash
+ @param inlen The length of the data (octets)
+ @return CRYPT_OK if successful
+*/
+HASH_PROCESS(sha1_process, sha1_compress, sha1, 64)
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (20 bytes)
+ @return CRYPT_OK if successful
+*/
+int sha1_done(hash_state * md, unsigned char *out)
+{
+ int i;
+
+ LTC_ARGCHK(md != NULL);
+ LTC_ARGCHK(out != NULL);
+
+ if (md->sha1.curlen >= sizeof(md->sha1.buf)) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* increase the length of the message */
+ md->sha1.length += md->sha1.curlen * 8;
+
+ /* append the '1' bit */
+ md->sha1.buf[md->sha1.curlen++] = (unsigned char)0x80;
+
+ /* if the length is currently above 56 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if (md->sha1.curlen > 56) {
+ while (md->sha1.curlen < 64) {
+ md->sha1.buf[md->sha1.curlen++] = (unsigned char)0;
+ }
+ sha1_compress(md, md->sha1.buf);
+ md->sha1.curlen = 0;
+ }
+
+ /* pad upto 56 bytes of zeroes */
+ while (md->sha1.curlen < 56) {
+ md->sha1.buf[md->sha1.curlen++] = (unsigned char)0;
+ }
+
+ /* store length */
+ STORE64H(md->sha1.length, md->sha1.buf+56);
+ sha1_compress(md, md->sha1.buf);
+
+ /* copy output */
+ for (i = 0; i < 5; i++) {
+ STORE32H(md->sha1.state[i], out+(4*i));
+ }
+#ifdef LTC_CLEAN_STACK
+ zeromem(md, sizeof(hash_state));
+#endif
+ return CRYPT_OK;
+}
+
+/**
+ Self-test the hash
+ @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int sha1_test(void)
+{
+ #ifndef LTC_TEST
+ return CRYPT_NOP;
+ #else
+ static const struct {
+ char *msg;
+ unsigned char hash[20];
+ } tests[] = {
+ { "abc",
+ { 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a,
+ 0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c,
+ 0x9c, 0xd0, 0xd8, 0x9d }
+ },
+ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E,
+ 0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5,
+ 0xE5, 0x46, 0x70, 0xF1 }
+ }
+ };
+
+ int i;
+ unsigned char tmp[20];
+ hash_state md;
+
+ for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+ sha1_init(&md);
+ sha1_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+ sha1_done(&md, tmp);
+ if (XMEMCMP(tmp, tests[i].hash, 20) != 0) {
+ return CRYPT_FAIL_TESTVECTOR;
+ }
+ }
+ return CRYPT_OK;
+ #endif
+}
+
+#endif
+
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/hashes/sha1.c,v $ */
+/* $Revision: 1.10 $ */
+/* $Date: 2007/05/12 14:25:28 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt.h b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt.h
new file mode 100644
index 00000000000..74cdff47549
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt.h
@@ -0,0 +1,87 @@
+#ifndef TOMCRYPT_H_
+#define TOMCRYPT_H_
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include <limits.h>
+
+/* use configuration data */
+#include "tomcrypt_custom.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* version */
+#define CRYPT 0x0117
+#define SCRYPT "1.17"
+
+/* max size of either a cipher/hash block or symmetric key [largest of the two] */
+#define MAXBLOCKSIZE 128
+
+/* descriptor table size */
+#define TAB_SIZE 32
+
+/* error codes [will be expanded in future releases] */
+enum {
+ CRYPT_OK=0, /* Result OK */
+ CRYPT_ERROR, /* Generic Error */
+ CRYPT_NOP, /* Not a failure but no operation was performed */
+
+ CRYPT_INVALID_KEYSIZE, /* Invalid key size given */
+ CRYPT_INVALID_ROUNDS, /* Invalid number of rounds */
+ CRYPT_FAIL_TESTVECTOR, /* Algorithm failed test vectors */
+
+ CRYPT_BUFFER_OVERFLOW, /* Not enough space for output */
+ CRYPT_INVALID_PACKET, /* Invalid input packet given */
+
+ CRYPT_INVALID_PRNGSIZE, /* Invalid number of bits for a PRNG */
+ CRYPT_ERROR_READPRNG, /* Could not read enough from PRNG */
+
+ CRYPT_INVALID_CIPHER, /* Invalid cipher specified */
+ CRYPT_INVALID_HASH, /* Invalid hash specified */
+ CRYPT_INVALID_PRNG, /* Invalid PRNG specified */
+
+ CRYPT_MEM, /* Out of memory */
+
+ CRYPT_PK_TYPE_MISMATCH, /* Not equivalent types of PK keys */
+ CRYPT_PK_NOT_PRIVATE, /* Requires a private PK key */
+
+ CRYPT_INVALID_ARG, /* Generic invalid argument */
+ CRYPT_FILE_NOTFOUND, /* File Not Found */
+
+ CRYPT_PK_INVALID_TYPE, /* Invalid type of PK key */
+ CRYPT_PK_INVALID_SYSTEM,/* Invalid PK system specified */
+ CRYPT_PK_DUP, /* Duplicate key already in key ring */
+ CRYPT_PK_NOT_FOUND, /* Key not found in keyring */
+ CRYPT_PK_INVALID_SIZE, /* Invalid size input for PK parameters */
+
+ CRYPT_INVALID_PRIME_SIZE,/* Invalid size of prime requested */
+ CRYPT_PK_INVALID_PADDING /* Invalid padding on input */
+};
+
+#include "tomcrypt_cfg.h"
+#include "tomcrypt_macros.h"
+#include "tomcrypt_cipher.h"
+#include "tomcrypt_hash.h"
+#include "tomcrypt_mac.h"
+#include "tomcrypt_prng.h"
+#include "tomcrypt_pk.h"
+#include "tomcrypt_math.h"
+#include "tomcrypt_misc.h"
+#include "tomcrypt_argchk.h"
+#include "tomcrypt_pkcs.h"
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* TOMCRYPT_H_ */
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt.h,v $ */
+/* $Revision: 1.21 $ */
+/* $Date: 2006/12/16 19:34:05 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_argchk.h b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_argchk.h
new file mode 100644
index 00000000000..cfc93ad7ea6
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_argchk.h
@@ -0,0 +1,38 @@
+/* Defines the LTC_ARGCHK macro used within the library */
+/* ARGTYPE is defined in mycrypt_cfg.h */
+#if ARGTYPE == 0
+
+#include <signal.h>
+
+/* this is the default LibTomCrypt macro */
+void crypt_argchk(char *v, char *s, int d);
+#define LTC_ARGCHK(x) if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); }
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 1
+
+/* fatal type of error */
+#define LTC_ARGCHK(x) assert((x))
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 2
+
+#define LTC_ARGCHK(x) if (!(x)) { fprintf(stderr, "\nwarning: ARGCHK failed at %s:%d\n", __FILE__, __LINE__); }
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 3
+
+#define LTC_ARGCHK(x)
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 4
+
+#define LTC_ARGCHK(x) if (!(x)) return CRYPT_INVALID_ARG;
+#define LTC_ARGCHKVD(x) if (!(x)) return;
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_argchk.h,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/08/27 20:50:21 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_cfg.h b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_cfg.h
new file mode 100644
index 00000000000..7feae6e8bdc
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_cfg.h
@@ -0,0 +1,136 @@
+/* This is the build config file.
+ *
+ * With this you can setup what to inlcude/exclude automatically during any build. Just comment
+ * out the line that #define's the word for the thing you want to remove. phew!
+ */
+
+#ifndef TOMCRYPT_CFG_H
+#define TOMCRYPT_CFG_H
+
+#if defined(_WIN32) || defined(_MSC_VER)
+#define LTC_CALL __cdecl
+#else
+#ifndef LTC_CALL
+ #define LTC_CALL
+#endif
+#endif
+
+#ifndef LTC_EXPORT
+#define LTC_EXPORT
+#endif
+
+/* certain platforms use macros for these, making the prototypes broken */
+#ifndef LTC_NO_PROTOTYPES
+
+/* you can change how memory allocation works ... */
+LTC_EXPORT void * LTC_CALL XMALLOC(size_t n);
+LTC_EXPORT void * LTC_CALL XREALLOC(void *p, size_t n);
+LTC_EXPORT void * LTC_CALL XCALLOC(size_t n, size_t s);
+LTC_EXPORT void LTC_CALL XFREE(void *p);
+
+LTC_EXPORT void LTC_CALL XQSORT(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));
+
+
+/* change the clock function too */
+LTC_EXPORT clock_t LTC_CALL XCLOCK(void);
+
+/* various other functions */
+LTC_EXPORT void * LTC_CALL XMEMCPY(void *dest, const void *src, size_t n);
+LTC_EXPORT int LTC_CALL XMEMCMP(const void *s1, const void *s2, size_t n);
+LTC_EXPORT void * LTC_CALL XMEMSET(void *s, int c, size_t n);
+
+LTC_EXPORT int LTC_CALL XSTRCMP(const char *s1, const char *s2);
+
+#endif
+
+/* type of argument checking, 0=default, 1=fatal and 2=error+continue, 3=nothing */
+#ifndef ARGTYPE
+ #define ARGTYPE 0
+#endif
+
+/* Controls endianess and size of registers. Leave uncommented to get platform neutral [slower] code
+ *
+ * Note: in order to use the optimized macros your platform must support unaligned 32 and 64 bit read/writes.
+ * The x86 platforms allow this but some others [ARM for instance] do not. On those platforms you **MUST**
+ * use the portable [slower] macros.
+ */
+
+/* detect x86-32 machines somewhat */
+#if !defined(__STRICT_ANSI__) && (defined(INTEL_CC) || (defined(_MSC_VER) && defined(WIN32)) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__))))
+ #define ENDIAN_LITTLE
+ #define ENDIAN_32BITWORD
+ #define LTC_FAST
+ #define LTC_FAST_TYPE unsigned long
+#endif
+
+/* detects MIPS R5900 processors (PS2) */
+#if (defined(__R5900) || defined(R5900) || defined(__R5900__)) && (defined(_mips) || defined(__mips__) || defined(mips))
+ #define ENDIAN_LITTLE
+ #define ENDIAN_64BITWORD
+#endif
+
+/* detect amd64 */
+#if !defined(__STRICT_ANSI__) && defined(__x86_64__)
+ #define ENDIAN_LITTLE
+ #define ENDIAN_64BITWORD
+ #define LTC_FAST
+ #define LTC_FAST_TYPE unsigned long
+#endif
+
+/* detect PPC32 */
+#if !defined(__STRICT_ANSI__) && defined(LTC_PPC32)
+ #define ENDIAN_BIG
+ #define ENDIAN_32BITWORD
+ #define LTC_FAST
+ #define LTC_FAST_TYPE unsigned long
+#endif
+
+/* detect sparc and sparc64 */
+#if defined(__sparc__)
+ #define ENDIAN_BIG
+ #if defined(__arch64__)
+ #define ENDIAN_64BITWORD
+ #else
+ #define ENDIAN_32BITWORD
+ #endif
+#endif
+
+
+#ifdef LTC_NO_FAST
+ #ifdef LTC_FAST
+ #undef LTC_FAST
+ #endif
+#endif
+
+/* No asm is a quick way to disable anything "not portable" */
+#ifdef LTC_NO_ASM
+ #undef ENDIAN_LITTLE
+ #undef ENDIAN_BIG
+ #undef ENDIAN_32BITWORD
+ #undef ENDIAN_64BITWORD
+ #undef LTC_FAST
+ #undef LTC_FAST_TYPE
+ #define LTC_NO_ROLC
+ #define LTC_NO_BSWAP
+#endif
+
+/* #define ENDIAN_LITTLE */
+/* #define ENDIAN_BIG */
+
+/* #define ENDIAN_32BITWORD */
+/* #define ENDIAN_64BITWORD */
+
+#if (defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) && !(defined(ENDIAN_32BITWORD) || defined(ENDIAN_64BITWORD))
+ #error You must specify a word size as well as endianess in tomcrypt_cfg.h
+#endif
+
+#if !(defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE))
+ #define ENDIAN_NEUTRAL
+#endif
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_cfg.h,v $ */
+/* $Revision: 1.19 $ */
+/* $Date: 2006/12/04 02:19:48 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_cipher.h b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_cipher.h
new file mode 100644
index 00000000000..bd740bf4a0c
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_cipher.h
@@ -0,0 +1,891 @@
+/* ---- SYMMETRIC KEY STUFF -----
+ *
+ * We put each of the ciphers scheduled keys in their own structs then we put all of
+ * the key formats in one union. This makes the function prototypes easier to use.
+ */
+#ifdef LTC_BLOWFISH
+struct blowfish_key {
+ ulong32 S[4][256];
+ ulong32 K[18];
+};
+#endif
+
+#ifdef LTC_RC5
+struct rc5_key {
+ int rounds;
+ ulong32 K[50];
+};
+#endif
+
+#ifdef LTC_RC6
+struct rc6_key {
+ ulong32 K[44];
+};
+#endif
+
+#ifdef LTC_SAFERP
+struct saferp_key {
+ unsigned char K[33][16];
+ long rounds;
+};
+#endif
+
+#ifdef LTC_RIJNDAEL
+struct rijndael_key {
+ ulong32 eK[60], dK[60];
+ int Nr;
+};
+#endif
+
+#ifdef LTC_KSEED
+struct kseed_key {
+ ulong32 K[32], dK[32];
+};
+#endif
+
+#ifdef LTC_KASUMI
+struct kasumi_key {
+ ulong32 KLi1[8], KLi2[8],
+ KOi1[8], KOi2[8], KOi3[8],
+ KIi1[8], KIi2[8], KIi3[8];
+};
+#endif
+
+#ifdef LTC_XTEA
+struct xtea_key {
+ unsigned long A[32], B[32];
+};
+#endif
+
+#ifdef LTC_TWOFISH
+#ifndef LTC_TWOFISH_SMALL
+ struct twofish_key {
+ ulong32 S[4][256], K[40];
+ };
+#else
+ struct twofish_key {
+ ulong32 K[40];
+ unsigned char S[32], start;
+ };
+#endif
+#endif
+
+#ifdef LTC_SAFER
+#define LTC_SAFER_K64_DEFAULT_NOF_ROUNDS 6
+#define LTC_SAFER_K128_DEFAULT_NOF_ROUNDS 10
+#define LTC_SAFER_SK64_DEFAULT_NOF_ROUNDS 8
+#define LTC_SAFER_SK128_DEFAULT_NOF_ROUNDS 10
+#define LTC_SAFER_MAX_NOF_ROUNDS 13
+#define LTC_SAFER_BLOCK_LEN 8
+#define LTC_SAFER_KEY_LEN (1 + LTC_SAFER_BLOCK_LEN * (1 + 2 * LTC_SAFER_MAX_NOF_ROUNDS))
+typedef unsigned char safer_block_t[LTC_SAFER_BLOCK_LEN];
+typedef unsigned char safer_key_t[LTC_SAFER_KEY_LEN];
+struct safer_key { safer_key_t key; };
+#endif
+
+#ifdef LTC_RC2
+struct rc2_key { unsigned xkey[64]; };
+#endif
+
+#ifdef LTC_DES
+struct des_key {
+ ulong32 ek[32], dk[32];
+};
+
+struct des3_key {
+ ulong32 ek[3][32], dk[3][32];
+};
+#endif
+
+#ifdef LTC_CAST5
+struct cast5_key {
+ ulong32 K[32], keylen;
+};
+#endif
+
+#ifdef LTC_NOEKEON
+struct noekeon_key {
+ ulong32 K[4], dK[4];
+};
+#endif
+
+#ifdef LTC_SKIPJACK
+struct skipjack_key {
+ unsigned char key[10];
+};
+#endif
+
+#ifdef LTC_KHAZAD
+struct khazad_key {
+ ulong64 roundKeyEnc[8 + 1];
+ ulong64 roundKeyDec[8 + 1];
+};
+#endif
+
+#ifdef LTC_ANUBIS
+struct anubis_key {
+ int keyBits;
+ int R;
+ ulong32 roundKeyEnc[18 + 1][4];
+ ulong32 roundKeyDec[18 + 1][4];
+};
+#endif
+
+#ifdef LTC_MULTI2
+struct multi2_key {
+ int N;
+ ulong32 uk[8];
+};
+#endif
+
+typedef union Symmetric_key {
+#ifdef LTC_DES
+ struct des_key des;
+ struct des3_key des3;
+#endif
+#ifdef LTC_RC2
+ struct rc2_key rc2;
+#endif
+#ifdef LTC_SAFER
+ struct safer_key safer;
+#endif
+#ifdef LTC_TWOFISH
+ struct twofish_key twofish;
+#endif
+#ifdef LTC_BLOWFISH
+ struct blowfish_key blowfish;
+#endif
+#ifdef LTC_RC5
+ struct rc5_key rc5;
+#endif
+#ifdef LTC_RC6
+ struct rc6_key rc6;
+#endif
+#ifdef LTC_SAFERP
+ struct saferp_key saferp;
+#endif
+#ifdef LTC_RIJNDAEL
+ struct rijndael_key rijndael;
+#endif
+#ifdef LTC_XTEA
+ struct xtea_key xtea;
+#endif
+#ifdef LTC_CAST5
+ struct cast5_key cast5;
+#endif
+#ifdef LTC_NOEKEON
+ struct noekeon_key noekeon;
+#endif
+#ifdef LTC_SKIPJACK
+ struct skipjack_key skipjack;
+#endif
+#ifdef LTC_KHAZAD
+ struct khazad_key khazad;
+#endif
+#ifdef LTC_ANUBIS
+ struct anubis_key anubis;
+#endif
+#ifdef LTC_KSEED
+ struct kseed_key kseed;
+#endif
+#ifdef LTC_KASUMI
+ struct kasumi_key kasumi;
+#endif
+#ifdef LTC_MULTI2
+ struct multi2_key multi2;
+#endif
+ void *data;
+} symmetric_key;
+
+#ifdef LTC_ECB_MODE
+/** A block cipher ECB structure */
+typedef struct {
+ /** The index of the cipher chosen */
+ int cipher,
+ /** The block size of the given cipher */
+ blocklen;
+ /** The scheduled key */
+ symmetric_key key;
+} symmetric_ECB;
+#endif
+
+#ifdef LTC_CFB_MODE
+/** A block cipher CFB structure */
+typedef struct {
+ /** The index of the cipher chosen */
+ int cipher,
+ /** The block size of the given cipher */
+ blocklen,
+ /** The padding offset */
+ padlen;
+ /** The current IV */
+ unsigned char IV[MAXBLOCKSIZE],
+ /** The pad used to encrypt/decrypt */
+ pad[MAXBLOCKSIZE];
+ /** The scheduled key */
+ symmetric_key key;
+} symmetric_CFB;
+#endif
+
+#ifdef LTC_OFB_MODE
+/** A block cipher OFB structure */
+typedef struct {
+ /** The index of the cipher chosen */
+ int cipher,
+ /** The block size of the given cipher */
+ blocklen,
+ /** The padding offset */
+ padlen;
+ /** The current IV */
+ unsigned char IV[MAXBLOCKSIZE];
+ /** The scheduled key */
+ symmetric_key key;
+} symmetric_OFB;
+#endif
+
+#ifdef LTC_CBC_MODE
+/** A block cipher CBC structure */
+typedef struct {
+ /** The index of the cipher chosen */
+ int cipher,
+ /** The block size of the given cipher */
+ blocklen;
+ /** The current IV */
+ unsigned char IV[MAXBLOCKSIZE];
+ /** The scheduled key */
+ symmetric_key key;
+} symmetric_CBC;
+#endif
+
+
+#ifdef LTC_CTR_MODE
+/** A block cipher CTR structure */
+typedef struct {
+ /** The index of the cipher chosen */
+ int cipher,
+ /** The block size of the given cipher */
+ blocklen,
+ /** The padding offset */
+ padlen,
+ /** The mode (endianess) of the CTR, 0==little, 1==big */
+ mode,
+ /** counter width */
+ ctrlen;
+
+ /** The counter */
+ unsigned char ctr[MAXBLOCKSIZE],
+ /** The pad used to encrypt/decrypt */
+ pad[MAXBLOCKSIZE];
+ /** The scheduled key */
+ symmetric_key key;
+} symmetric_CTR;
+#endif
+
+
+#ifdef LTC_LRW_MODE
+/** A LRW structure */
+typedef struct {
+ /** The index of the cipher chosen (must be a 128-bit block cipher) */
+ int cipher;
+
+ /** The current IV */
+ unsigned char IV[16],
+
+ /** the tweak key */
+ tweak[16],
+
+ /** The current pad, it's the product of the first 15 bytes against the tweak key */
+ pad[16];
+
+ /** The scheduled symmetric key */
+ symmetric_key key;
+
+#ifdef LRW_TABLES
+ /** The pre-computed multiplication table */
+ unsigned char PC[16][256][16];
+#endif
+} symmetric_LRW;
+#endif
+
+#ifdef LTC_F8_MODE
+/** A block cipher F8 structure */
+typedef struct {
+ /** The index of the cipher chosen */
+ int cipher,
+ /** The block size of the given cipher */
+ blocklen,
+ /** The padding offset */
+ padlen;
+ /** The current IV */
+ unsigned char IV[MAXBLOCKSIZE],
+ MIV[MAXBLOCKSIZE];
+ /** Current block count */
+ ulong32 blockcnt;
+ /** The scheduled key */
+ symmetric_key key;
+} symmetric_F8;
+#endif
+
+
+/** cipher descriptor table, last entry has "name == NULL" to mark the end of table */
+extern struct ltc_cipher_descriptor {
+ /** name of cipher */
+ char *name;
+ /** internal ID */
+ unsigned char ID;
+ /** min keysize (octets) */
+ int min_key_length,
+ /** max keysize (octets) */
+ max_key_length,
+ /** block size (octets) */
+ block_length,
+ /** default number of rounds */
+ default_rounds;
+ /** Setup the cipher
+ @param key The input symmetric key
+ @param keylen The length of the input key (octets)
+ @param num_rounds The requested number of rounds (0==default)
+ @param skey [out] The destination of the scheduled key
+ @return CRYPT_OK if successful
+ */
+ int (*setup)(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+ /** Encrypt a block
+ @param pt The plaintext
+ @param ct [out] The ciphertext
+ @param skey The scheduled key
+ @return CRYPT_OK if successful
+ */
+ int (*ecb_encrypt)(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+ /** Decrypt a block
+ @param ct The ciphertext
+ @param pt [out] The plaintext
+ @param skey The scheduled key
+ @return CRYPT_OK if successful
+ */
+ int (*ecb_decrypt)(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+ /** Test the block cipher
+ @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+ */
+ int (*test)(void);
+
+ /** Terminate the context
+ @param skey The scheduled key
+ */
+ void (*done)(symmetric_key *skey);
+
+ /** Determine a key size
+ @param keysize [in/out] The size of the key desired and the suggested size
+ @return CRYPT_OK if successful
+ */
+ int (*keysize)(int *keysize);
+
+/** Accelerators **/
+ /** Accelerated ECB encryption
+ @param pt Plaintext
+ @param ct Ciphertext
+ @param blocks The number of complete blocks to process
+ @param skey The scheduled key context
+ @return CRYPT_OK if successful
+ */
+ int (*accel_ecb_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, symmetric_key *skey);
+
+ /** Accelerated ECB decryption
+ @param pt Plaintext
+ @param ct Ciphertext
+ @param blocks The number of complete blocks to process
+ @param skey The scheduled key context
+ @return CRYPT_OK if successful
+ */
+ int (*accel_ecb_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, symmetric_key *skey);
+
+ /** Accelerated CBC encryption
+ @param pt Plaintext
+ @param ct Ciphertext
+ @param blocks The number of complete blocks to process
+ @param IV The initial value (input/output)
+ @param skey The scheduled key context
+ @return CRYPT_OK if successful
+ */
+ int (*accel_cbc_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, symmetric_key *skey);
+
+ /** Accelerated CBC decryption
+ @param pt Plaintext
+ @param ct Ciphertext
+ @param blocks The number of complete blocks to process
+ @param IV The initial value (input/output)
+ @param skey The scheduled key context
+ @return CRYPT_OK if successful
+ */
+ int (*accel_cbc_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, unsigned char *IV, symmetric_key *skey);
+
+ /** Accelerated CTR encryption
+ @param pt Plaintext
+ @param ct Ciphertext
+ @param blocks The number of complete blocks to process
+ @param IV The initial value (input/output)
+ @param mode little or big endian counter (mode=0 or mode=1)
+ @param skey The scheduled key context
+ @return CRYPT_OK if successful
+ */
+ int (*accel_ctr_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, int mode, symmetric_key *skey);
+
+ /** Accelerated LRW
+ @param pt Plaintext
+ @param ct Ciphertext
+ @param blocks The number of complete blocks to process
+ @param IV The initial value (input/output)
+ @param tweak The LRW tweak
+ @param skey The scheduled key context
+ @return CRYPT_OK if successful
+ */
+ int (*accel_lrw_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, const unsigned char *tweak, symmetric_key *skey);
+
+ /** Accelerated LRW
+ @param ct Ciphertext
+ @param pt Plaintext
+ @param blocks The number of complete blocks to process
+ @param IV The initial value (input/output)
+ @param tweak The LRW tweak
+ @param skey The scheduled key context
+ @return CRYPT_OK if successful
+ */
+ int (*accel_lrw_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, unsigned char *IV, const unsigned char *tweak, symmetric_key *skey);
+
+ /** Accelerated CCM packet (one-shot)
+ @param key The secret key to use
+ @param keylen The length of the secret key (octets)
+ @param uskey A previously scheduled key [optional can be NULL]
+ @param nonce The session nonce [use once]
+ @param noncelen The length of the nonce
+ @param header The header for the session
+ @param headerlen The length of the header (octets)
+ @param pt [out] The plaintext
+ @param ptlen The length of the plaintext (octets)
+ @param ct [out] The ciphertext
+ @param tag [out] The destination tag
+ @param taglen [in/out] The max size and resulting size of the authentication tag
+ @param direction Encrypt or Decrypt direction (0 or 1)
+ @return CRYPT_OK if successful
+ */
+ int (*accel_ccm_memory)(
+ const unsigned char *key, unsigned long keylen,
+ symmetric_key *uskey,
+ const unsigned char *nonce, unsigned long noncelen,
+ const unsigned char *header, unsigned long headerlen,
+ unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ unsigned char *tag, unsigned long *taglen,
+ int direction);
+
+ /** Accelerated GCM packet (one shot)
+ @param key The secret key
+ @param keylen The length of the secret key
+ @param IV The initial vector
+ @param IVlen The length of the initial vector
+ @param adata The additional authentication data (header)
+ @param adatalen The length of the adata
+ @param pt The plaintext
+ @param ptlen The length of the plaintext (ciphertext length is the same)
+ @param ct The ciphertext
+ @param tag [out] The MAC tag
+ @param taglen [in/out] The MAC tag length
+ @param direction Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT)
+ @return CRYPT_OK on success
+ */
+ int (*accel_gcm_memory)(
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *IV, unsigned long IVlen,
+ const unsigned char *adata, unsigned long adatalen,
+ unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ unsigned char *tag, unsigned long *taglen,
+ int direction);
+
+ /** Accelerated one shot LTC_OMAC
+ @param key The secret key
+ @param keylen The key length (octets)
+ @param in The message
+ @param inlen Length of message (octets)
+ @param out [out] Destination for tag
+ @param outlen [in/out] Initial and final size of out
+ @return CRYPT_OK on success
+ */
+ int (*omac_memory)(
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+ /** Accelerated one shot XCBC
+ @param key The secret key
+ @param keylen The key length (octets)
+ @param in The message
+ @param inlen Length of message (octets)
+ @param out [out] Destination for tag
+ @param outlen [in/out] Initial and final size of out
+ @return CRYPT_OK on success
+ */
+ int (*xcbc_memory)(
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+ /** Accelerated one shot F9
+ @param key The secret key
+ @param keylen The key length (octets)
+ @param in The message
+ @param inlen Length of message (octets)
+ @param out [out] Destination for tag
+ @param outlen [in/out] Initial and final size of out
+ @return CRYPT_OK on success
+ @remark Requires manual padding
+ */
+ int (*f9_memory)(
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+} cipher_descriptor[];
+
+#ifdef LTC_BLOWFISH
+int blowfish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int blowfish_test(void);
+void blowfish_done(symmetric_key *skey);
+int blowfish_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor blowfish_desc;
+#endif
+
+#ifdef LTC_RC5
+int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int rc5_test(void);
+void rc5_done(symmetric_key *skey);
+int rc5_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor rc5_desc;
+#endif
+
+#ifdef LTC_RC6
+int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int rc6_test(void);
+void rc6_done(symmetric_key *skey);
+int rc6_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor rc6_desc;
+#endif
+
+#ifdef LTC_RC2
+int rc2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rc2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int rc2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int rc2_test(void);
+void rc2_done(symmetric_key *skey);
+int rc2_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor rc2_desc;
+#endif
+
+#ifdef LTC_SAFERP
+int saferp_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int saferp_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int saferp_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int saferp_test(void);
+void saferp_done(symmetric_key *skey);
+int saferp_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor saferp_desc;
+#endif
+
+#ifdef LTC_SAFER
+int safer_k64_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int safer_sk64_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int safer_k128_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int safer_sk128_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int safer_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+int safer_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+int safer_k64_test(void);
+int safer_sk64_test(void);
+int safer_sk128_test(void);
+void safer_done(symmetric_key *skey);
+int safer_64_keysize(int *keysize);
+int safer_128_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor safer_k64_desc, safer_k128_desc, safer_sk64_desc, safer_sk128_desc;
+#endif
+
+#ifdef LTC_RIJNDAEL
+
+/* make aes an alias */
+#define aes_setup rijndael_setup
+#define aes_ecb_encrypt rijndael_ecb_encrypt
+#define aes_ecb_decrypt rijndael_ecb_decrypt
+#define aes_test rijndael_test
+#define aes_done rijndael_done
+#define aes_keysize rijndael_keysize
+
+#define aes_enc_setup rijndael_enc_setup
+#define aes_enc_ecb_encrypt rijndael_enc_ecb_encrypt
+#define aes_enc_keysize rijndael_enc_keysize
+
+int rijndael_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int rijndael_test(void);
+void rijndael_done(symmetric_key *skey);
+int rijndael_keysize(int *keysize);
+int rijndael_enc_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rijndael_enc_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+void rijndael_enc_done(symmetric_key *skey);
+int rijndael_enc_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor rijndael_desc, aes_desc;
+extern const struct ltc_cipher_descriptor rijndael_enc_desc, aes_enc_desc;
+#endif
+
+#ifdef LTC_XTEA
+int xtea_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int xtea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int xtea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int xtea_test(void);
+void xtea_done(symmetric_key *skey);
+int xtea_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor xtea_desc;
+#endif
+
+#ifdef LTC_TWOFISH
+int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int twofish_test(void);
+void twofish_done(symmetric_key *skey);
+int twofish_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor twofish_desc;
+#endif
+
+#ifdef LTC_DES
+int des_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int des_test(void);
+void des_done(symmetric_key *skey);
+int des_keysize(int *keysize);
+int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int des3_test(void);
+void des3_done(symmetric_key *skey);
+int des3_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor des_desc, des3_desc;
+#endif
+
+#ifdef LTC_CAST5
+int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int cast5_test(void);
+void cast5_done(symmetric_key *skey);
+int cast5_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor cast5_desc;
+#endif
+
+#ifdef LTC_NOEKEON
+int noekeon_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int noekeon_test(void);
+void noekeon_done(symmetric_key *skey);
+int noekeon_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor noekeon_desc;
+#endif
+
+#ifdef LTC_SKIPJACK
+int skipjack_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int skipjack_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int skipjack_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int skipjack_test(void);
+void skipjack_done(symmetric_key *skey);
+int skipjack_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor skipjack_desc;
+#endif
+
+#ifdef LTC_KHAZAD
+int khazad_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int khazad_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int khazad_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int khazad_test(void);
+void khazad_done(symmetric_key *skey);
+int khazad_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor khazad_desc;
+#endif
+
+#ifdef LTC_ANUBIS
+int anubis_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int anubis_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int anubis_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int anubis_test(void);
+void anubis_done(symmetric_key *skey);
+int anubis_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor anubis_desc;
+#endif
+
+#ifdef LTC_KSEED
+int kseed_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int kseed_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int kseed_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int kseed_test(void);
+void kseed_done(symmetric_key *skey);
+int kseed_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor kseed_desc;
+#endif
+
+#ifdef LTC_KASUMI
+int kasumi_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int kasumi_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int kasumi_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int kasumi_test(void);
+void kasumi_done(symmetric_key *skey);
+int kasumi_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor kasumi_desc;
+#endif
+
+
+#ifdef LTC_MULTI2
+int multi2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int multi2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int multi2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int multi2_test(void);
+void multi2_done(symmetric_key *skey);
+int multi2_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor multi2_desc;
+#endif
+
+#ifdef LTC_ECB_MODE
+int ecb_start(int cipher, const unsigned char *key,
+ int keylen, int num_rounds, symmetric_ECB *ecb);
+int ecb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_ECB *ecb);
+int ecb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_ECB *ecb);
+int ecb_done(symmetric_ECB *ecb);
+#endif
+
+#ifdef LTC_CFB_MODE
+int cfb_start(int cipher, const unsigned char *IV, const unsigned char *key,
+ int keylen, int num_rounds, symmetric_CFB *cfb);
+int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CFB *cfb);
+int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CFB *cfb);
+int cfb_getiv(unsigned char *IV, unsigned long *len, symmetric_CFB *cfb);
+int cfb_setiv(const unsigned char *IV, unsigned long len, symmetric_CFB *cfb);
+int cfb_done(symmetric_CFB *cfb);
+#endif
+
+#ifdef LTC_OFB_MODE
+int ofb_start(int cipher, const unsigned char *IV, const unsigned char *key,
+ int keylen, int num_rounds, symmetric_OFB *ofb);
+int ofb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_OFB *ofb);
+int ofb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_OFB *ofb);
+int ofb_getiv(unsigned char *IV, unsigned long *len, symmetric_OFB *ofb);
+int ofb_setiv(const unsigned char *IV, unsigned long len, symmetric_OFB *ofb);
+int ofb_done(symmetric_OFB *ofb);
+#endif
+
+#ifdef LTC_CBC_MODE
+int cbc_start(int cipher, const unsigned char *IV, const unsigned char *key,
+ int keylen, int num_rounds, symmetric_CBC *cbc);
+int cbc_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CBC *cbc);
+int cbc_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CBC *cbc);
+int cbc_getiv(unsigned char *IV, unsigned long *len, symmetric_CBC *cbc);
+int cbc_setiv(const unsigned char *IV, unsigned long len, symmetric_CBC *cbc);
+int cbc_done(symmetric_CBC *cbc);
+#endif
+
+#ifdef LTC_CTR_MODE
+
+#define CTR_COUNTER_LITTLE_ENDIAN 0x0000
+#define CTR_COUNTER_BIG_ENDIAN 0x1000
+#define LTC_CTR_RFC3686 0x2000
+
+int ctr_start( int cipher,
+ const unsigned char *IV,
+ const unsigned char *key, int keylen,
+ int num_rounds, int ctr_mode,
+ symmetric_CTR *ctr);
+int ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CTR *ctr);
+int ctr_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CTR *ctr);
+int ctr_getiv(unsigned char *IV, unsigned long *len, symmetric_CTR *ctr);
+int ctr_setiv(const unsigned char *IV, unsigned long len, symmetric_CTR *ctr);
+int ctr_done(symmetric_CTR *ctr);
+int ctr_test(void);
+#endif
+
+#ifdef LTC_LRW_MODE
+
+#define LRW_ENCRYPT 0
+#define LRW_DECRYPT 1
+
+int lrw_start( int cipher,
+ const unsigned char *IV,
+ const unsigned char *key, int keylen,
+ const unsigned char *tweak,
+ int num_rounds,
+ symmetric_LRW *lrw);
+int lrw_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_LRW *lrw);
+int lrw_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_LRW *lrw);
+int lrw_getiv(unsigned char *IV, unsigned long *len, symmetric_LRW *lrw);
+int lrw_setiv(const unsigned char *IV, unsigned long len, symmetric_LRW *lrw);
+int lrw_done(symmetric_LRW *lrw);
+int lrw_test(void);
+
+/* don't call */
+int lrw_process(const unsigned char *pt, unsigned char *ct, unsigned long len, int mode, symmetric_LRW *lrw);
+#endif
+
+#ifdef LTC_F8_MODE
+int f8_start( int cipher, const unsigned char *IV,
+ const unsigned char *key, int keylen,
+ const unsigned char *salt_key, int skeylen,
+ int num_rounds, symmetric_F8 *f8);
+int f8_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_F8 *f8);
+int f8_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_F8 *f8);
+int f8_getiv(unsigned char *IV, unsigned long *len, symmetric_F8 *f8);
+int f8_setiv(const unsigned char *IV, unsigned long len, symmetric_F8 *f8);
+int f8_done(symmetric_F8 *f8);
+int f8_test_mode(void);
+#endif
+
+#ifdef LTC_XTS_MODE
+typedef struct {
+ symmetric_key key1, key2;
+ int cipher;
+} symmetric_xts;
+
+int xts_start( int cipher,
+ const unsigned char *key1,
+ const unsigned char *key2,
+ unsigned long keylen,
+ int num_rounds,
+ symmetric_xts *xts);
+
+int xts_encrypt(
+ const unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ const unsigned char *tweak,
+ symmetric_xts *xts);
+int xts_decrypt(
+ const unsigned char *ct, unsigned long ptlen,
+ unsigned char *pt,
+ const unsigned char *tweak,
+ symmetric_xts *xts);
+
+void xts_done(symmetric_xts *xts);
+int xts_test(void);
+void xts_mult_x(unsigned char *I);
+#endif
+
+int find_cipher(const char *name);
+int find_cipher_any(const char *name, int blocklen, int keylen);
+int find_cipher_id(unsigned char ID);
+int register_cipher(const struct ltc_cipher_descriptor *cipher);
+int unregister_cipher(const struct ltc_cipher_descriptor *cipher);
+int cipher_is_valid(int idx);
+
+LTC_MUTEX_PROTO(ltc_cipher_mutex)
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_cipher.h,v $ */
+/* $Revision: 1.54 $ */
+/* $Date: 2007/05/12 14:37:41 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_custom.h b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_custom.h
new file mode 100644
index 00000000000..88ec8f984ab
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_custom.h
@@ -0,0 +1,424 @@
+#ifndef TOMCRYPT_CUSTOM_H_
+#define TOMCRYPT_CUSTOM_H_
+
+#define LTC_NO_CIPHERS
+#define LTC_NO_HASHES
+#define LTC_NO_MACS
+#define LTC_NO_PRNGS
+#define LTC_NO_CURVES
+#define LTC_NO_MODES
+#define LTC_NO_PKCS
+#define LTC_NO_ROLC
+
+#define LTC_SOURCE
+#define LTC_SHA1
+#define LTC_MD5
+#define LTC_DER
+#define LTC_RC4
+
+#define USE_LTM
+#define LTM_DESC
+
+/* macros for various libc functions you can change for embedded targets */
+#ifndef XMALLOC
+ #ifdef malloc
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XMALLOC LibTomMalloc
+#endif
+#ifndef XREALLOC
+ #ifdef realloc
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XREALLOC LibTomRealloc
+#endif
+#ifndef XCALLOC
+ #ifdef calloc
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XCALLOC LibTomCalloc
+#endif
+#ifndef XFREE
+ #ifdef free
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XFREE LibTomFree
+#endif
+
+#ifndef XMEMSET
+ #ifdef memset
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XMEMSET memset
+#endif
+#ifndef XMEMCPY
+ #ifdef memcpy
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XMEMCPY memcpy
+#endif
+#ifndef XMEMCMP
+ #ifdef memcmp
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XMEMCMP memcmp
+#endif
+#ifndef XSTRCMP
+ #ifdef strcmp
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XSTRCMP strcmp
+#endif
+
+#ifndef XCLOCK
+#define XCLOCK LibTomClock
+#endif
+#ifndef XCLOCKS_PER_SEC
+#define XCLOCKS_PER_SEC CLOCKS_PER_SEC
+#endif
+
+#ifndef XQSORT
+ #ifdef qsort
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XQSORT LibTomQsort
+#endif
+
+/* Easy button? */
+#ifdef LTC_EASY
+ #define LTC_NO_CIPHERS
+ #define LTC_RIJNDAEL
+ #define LTC_BLOWFISH
+ #define LTC_DES
+ #define LTC_CAST5
+
+ #define LTC_NO_MODES
+ #define LTC_ECB_MODE
+ #define LTC_CBC_MODE
+ #define LTC_CTR_MODE
+
+ #define LTC_NO_HASHES
+ #define LTC_SHA1
+ #define LTC_SHA512
+ #define LTC_SHA384
+ #define LTC_SHA256
+ #define LTC_SHA224
+
+ #define LTC_NO_MACS
+ #define LTC_HMAC
+ #define LTC_OMAC
+ #define LTC_CCM_MODE
+
+ #define LTC_NO_PRNGS
+ #define LTC_SPRNG
+ #define LTC_YARROW
+ #define LTC_DEVRANDOM
+ #define TRY_URANDOM_FIRST
+
+ #define LTC_NO_PK
+ #define LTC_MRSA
+ #define LTC_MECC
+#endif
+
+/* Use small code where possible */
+/* #define LTC_SMALL_CODE */
+
+/* Enable self-test test vector checking */
+#ifndef LTC_NO_TEST
+ #define LTC_TEST
+#endif
+
+/* clean the stack of functions which put private information on stack */
+/* #define LTC_CLEAN_STACK */
+
+/* disable all file related functions */
+/* #define LTC_NO_FILE */
+
+/* disable all forms of ASM */
+/* #define LTC_NO_ASM */
+
+/* disable FAST mode */
+/* #define LTC_NO_FAST */
+
+/* disable BSWAP on x86 */
+/* #define LTC_NO_BSWAP */
+
+/* ---> Symmetric Block Ciphers <--- */
+#ifndef LTC_NO_CIPHERS
+
+#define LTC_BLOWFISH
+#define LTC_RC2
+#define LTC_RC5
+#define LTC_RC6
+#define LTC_SAFERP
+#define LTC_RIJNDAEL
+#define LTC_XTEA
+/* _TABLES tells it to use tables during setup, _SMALL means to use the smaller scheduled key format
+ * (saves 4KB of ram), _ALL_TABLES enables all tables during setup */
+#define LTC_TWOFISH
+#ifndef LTC_NO_TABLES
+ #define LTC_TWOFISH_TABLES
+ /* #define LTC_TWOFISH_ALL_TABLES */
+#else
+ #define LTC_TWOFISH_SMALL
+#endif
+/* #define LTC_TWOFISH_SMALL */
+/* LTC_DES includes EDE triple-LTC_DES */
+#define LTC_DES
+#define LTC_CAST5
+#define LTC_NOEKEON
+#define LTC_SKIPJACK
+#define LTC_SAFER
+#define LTC_KHAZAD
+#define LTC_ANUBIS
+#define LTC_ANUBIS_TWEAK
+#define LTC_KSEED
+#define LTC_KASUMI
+
+#endif /* LTC_NO_CIPHERS */
+
+
+/* ---> Block Cipher Modes of Operation <--- */
+#ifndef LTC_NO_MODES
+
+#define LTC_CFB_MODE
+#define LTC_OFB_MODE
+#define LTC_ECB_MODE
+#define LTC_CBC_MODE
+#define LTC_CTR_MODE
+
+/* F8 chaining mode */
+#define LTC_F8_MODE
+
+/* LRW mode */
+#define LTC_LRW_MODE
+#ifndef LTC_NO_TABLES
+ /* like GCM mode this will enable 16 8x128 tables [64KB] that make
+ * seeking very fast.
+ */
+ #define LRW_TABLES
+#endif
+
+/* XTS mode */
+#define LTC_XTS_MODE
+
+#endif /* LTC_NO_MODES */
+
+/* ---> One-Way Hash Functions <--- */
+#ifndef LTC_NO_HASHES
+
+#define LTC_CHC_HASH
+#define LTC_WHIRLPOOL
+#define LTC_SHA512
+#define LTC_SHA384
+#define LTC_SHA256
+#define LTC_SHA224
+#define LTC_TIGER
+#define LTC_SHA1
+#define LTC_MD5
+#define LTC_MD4
+#define LTC_MD2
+#define LTC_RIPEMD128
+#define LTC_RIPEMD160
+#define LTC_RIPEMD256
+#define LTC_RIPEMD320
+
+#endif /* LTC_NO_HASHES */
+
+/* ---> MAC functions <--- */
+#ifndef LTC_NO_MACS
+
+#define LTC_HMAC
+#define LTC_OMAC
+#define LTC_PMAC
+#define LTC_XCBC
+#define LTC_F9_MODE
+#define LTC_PELICAN
+
+#if defined(LTC_PELICAN) && !defined(LTC_RIJNDAEL)
+ #error Pelican-MAC requires LTC_RIJNDAEL
+#endif
+
+/* ---> Encrypt + Authenticate Modes <--- */
+
+#define LTC_EAX_MODE
+#if defined(LTC_EAX_MODE) && !(defined(LTC_CTR_MODE) && defined(LTC_OMAC))
+ #error LTC_EAX_MODE requires CTR and LTC_OMAC mode
+#endif
+
+#define LTC_OCB_MODE
+#define LTC_CCM_MODE
+#define LTC_GCM_MODE
+
+/* Use 64KiB tables */
+#ifndef LTC_NO_TABLES
+ #define LTC_GCM_TABLES
+#endif
+
+/* USE SSE2? requires GCC works on x86_32 and x86_64*/
+#ifdef LTC_GCM_TABLES
+/* #define LTC_GCM_TABLES_SSE2 */
+#endif
+
+#endif /* LTC_NO_MACS */
+
+/* Various tidbits of modern neatoness */
+#define LTC_BASE64
+
+/* --> Pseudo Random Number Generators <--- */
+#ifndef LTC_NO_PRNGS
+
+/* Yarrow */
+#define LTC_YARROW
+/* which descriptor of AES to use? */
+/* 0 = rijndael_enc 1 = aes_enc, 2 = rijndael [full], 3 = aes [full] */
+#define LTC_YARROW_AES 0
+
+#if defined(LTC_YARROW) && !defined(LTC_CTR_MODE)
+ #error LTC_YARROW requires LTC_CTR_MODE chaining mode to be defined!
+#endif
+
+/* a PRNG that simply reads from an available system source */
+#define LTC_SPRNG
+
+/* The LTC_RC4 stream cipher */
+#define LTC_RC4
+
+/* Fortuna PRNG */
+#define LTC_FORTUNA
+/* reseed every N calls to the read function */
+#define LTC_FORTUNA_WD 10
+/* number of pools (4..32) can save a bit of ram by lowering the count */
+#define LTC_FORTUNA_POOLS 32
+
+/* Greg's LTC_SOBER128 PRNG ;-0 */
+#define LTC_SOBER128
+
+/* the *nix style /dev/random device */
+#define LTC_DEVRANDOM
+/* try /dev/urandom before trying /dev/random */
+#define TRY_URANDOM_FIRST
+
+#endif /* LTC_NO_PRNGS */
+
+/* ---> math provider? <--- */
+#ifndef LTC_NO_MATH
+
+/* LibTomMath */
+#define LTM_LTC_DESC
+
+/* TomsFastMath */
+//#define TFM_LTC_DESC
+
+#endif /* LTC_NO_MATH */
+
+/* ---> Public Key Crypto <--- */
+#ifndef LTC_NO_PK
+
+/* Include RSA support */
+#define LTC_MRSA
+
+/* Include Katja (a Rabin variant like RSA) */
+/* #define MKAT */
+
+/* Digital Signature Algorithm */
+#define LTC_MDSA
+
+/* ECC */
+#define LTC_MECC
+
+/* use Shamir's trick for point mul (speeds up signature verification) */
+#define LTC_ECC_SHAMIR
+
+#if defined(TFM_LTC_DESC) && defined(LTC_MECC)
+ #define LTC_MECC_ACCEL
+#endif
+
+/* do we want fixed point ECC */
+/* #define LTC_MECC_FP */
+
+/* Timing Resistant? */
+/* #define LTC_ECC_TIMING_RESISTANT */
+
+#endif /* LTC_NO_PK */
+
+/* LTC_PKCS #1 (RSA) and #5 (Password Handling) stuff */
+#ifndef LTC_NO_PKCS
+
+#define LTC_PKCS_1
+#define LTC_PKCS_5
+
+/* Include ASN.1 DER (required by DSA/RSA) */
+#define LTC_DER
+
+#endif /* LTC_NO_PKCS */
+
+/* cleanup */
+
+#ifdef LTC_MECC
+/* Supported ECC Key Sizes */
+#ifndef LTC_NO_CURVES
+ #define ECC112
+ #define ECC128
+ #define ECC160
+ #define ECC192
+ #define ECC224
+ #define ECC256
+ #define ECC384
+ #define ECC521
+#endif
+#endif
+
+#if defined(LTC_MECC) || defined(LTC_MRSA) || defined(LTC_MDSA) || defined(MKATJA)
+ /* Include the MPI functionality? (required by the PK algorithms) */
+ #define MPI
+#endif
+
+#ifdef LTC_MRSA
+ #define LTC_PKCS_1
+#endif
+
+#if defined(LTC_DER) && !defined(MPI)
+ #error ASN.1 DER requires MPI functionality
+#endif
+
+#if (defined(LTC_MDSA) || defined(LTC_MRSA) || defined(LTC_MECC) || defined(MKATJA)) && !defined(LTC_DER)
+ #error PK requires ASN.1 DER functionality, make sure LTC_DER is enabled
+#endif
+
+/* THREAD management */
+#ifdef LTC_PTHREAD
+
+#include <pthread.h>
+
+#define LTC_MUTEX_GLOBAL(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER;
+#define LTC_MUTEX_PROTO(x) extern pthread_mutex_t x;
+#define LTC_MUTEX_TYPE(x) pthread_mutex_t x;
+#define LTC_MUTEX_INIT(x) pthread_mutex_init(x, NULL);
+#define LTC_MUTEX_LOCK(x) pthread_mutex_lock(x);
+#define LTC_MUTEX_UNLOCK(x) pthread_mutex_unlock(x);
+
+#else
+
+/* default no functions */
+#define LTC_MUTEX_GLOBAL(x)
+#define LTC_MUTEX_PROTO(x)
+#define LTC_MUTEX_TYPE(x)
+#define LTC_MUTEX_INIT(x)
+#define LTC_MUTEX_LOCK(x)
+#define LTC_MUTEX_UNLOCK(x)
+
+#endif
+
+/* Debuggers */
+
+/* define this if you use Valgrind, note: it CHANGES the way SOBER-128 and LTC_RC4 work (see the code) */
+/* #define LTC_VALGRIND */
+
+#endif
+
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_custom.h,v $ */
+/* $Revision: 1.73 $ */
+/* $Date: 2007/05/12 14:37:41 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_hash.h b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_hash.h
new file mode 100644
index 00000000000..18553ebf9da
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_hash.h
@@ -0,0 +1,378 @@
+/* ---- HASH FUNCTIONS ---- */
+#ifdef LTC_SHA512
+struct sha512_state {
+ ulong64 length, state[8];
+ unsigned long curlen;
+ unsigned char buf[128];
+};
+#endif
+
+#ifdef LTC_SHA256
+struct sha256_state {
+ ulong64 length;
+ ulong32 state[8], curlen;
+ unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_SHA1
+struct sha1_state {
+ ulong64 length;
+ ulong32 state[5], curlen;
+ unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_MD5
+struct md5_state {
+ ulong64 length;
+ ulong32 state[4], curlen;
+ unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_MD4
+struct md4_state {
+ ulong64 length;
+ ulong32 state[4], curlen;
+ unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_TIGER
+struct tiger_state {
+ ulong64 state[3], length;
+ unsigned long curlen;
+ unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_MD2
+struct md2_state {
+ unsigned char chksum[16], X[48], buf[16];
+ unsigned long curlen;
+};
+#endif
+
+#ifdef LTC_RIPEMD128
+struct rmd128_state {
+ ulong64 length;
+ unsigned char buf[64];
+ ulong32 curlen, state[4];
+};
+#endif
+
+#ifdef LTC_RIPEMD160
+struct rmd160_state {
+ ulong64 length;
+ unsigned char buf[64];
+ ulong32 curlen, state[5];
+};
+#endif
+
+#ifdef LTC_RIPEMD256
+struct rmd256_state {
+ ulong64 length;
+ unsigned char buf[64];
+ ulong32 curlen, state[8];
+};
+#endif
+
+#ifdef LTC_RIPEMD320
+struct rmd320_state {
+ ulong64 length;
+ unsigned char buf[64];
+ ulong32 curlen, state[10];
+};
+#endif
+
+#ifdef LTC_WHIRLPOOL
+struct whirlpool_state {
+ ulong64 length, state[8];
+ unsigned char buf[64];
+ ulong32 curlen;
+};
+#endif
+
+#ifdef LTC_CHC_HASH
+struct chc_state {
+ ulong64 length;
+ unsigned char state[MAXBLOCKSIZE], buf[MAXBLOCKSIZE];
+ ulong32 curlen;
+};
+#endif
+
+typedef union Hash_state {
+#ifdef LTC_CHC_HASH
+ struct chc_state chc;
+#endif
+#ifdef LTC_WHIRLPOOL
+ struct whirlpool_state whirlpool;
+#endif
+#ifdef LTC_SHA512
+ struct sha512_state sha512;
+#endif
+#ifdef LTC_SHA256
+ struct sha256_state sha256;
+#endif
+#ifdef LTC_SHA1
+ struct sha1_state sha1;
+#endif
+#ifdef LTC_MD5
+ struct md5_state md5;
+#endif
+#ifdef LTC_MD4
+ struct md4_state md4;
+#endif
+#ifdef LTC_MD2
+ struct md2_state md2;
+#endif
+#ifdef LTC_TIGER
+ struct tiger_state tiger;
+#endif
+#ifdef LTC_RIPEMD128
+ struct rmd128_state rmd128;
+#endif
+#ifdef LTC_RIPEMD160
+ struct rmd160_state rmd160;
+#endif
+#ifdef LTC_RIPEMD256
+ struct rmd256_state rmd256;
+#endif
+#ifdef LTC_RIPEMD320
+ struct rmd320_state rmd320;
+#endif
+ void *data;
+} hash_state;
+
+/** hash descriptor */
+extern struct ltc_hash_descriptor {
+ /** name of hash */
+ char *name;
+ /** internal ID */
+ unsigned char ID;
+ /** Size of digest in octets */
+ unsigned long hashsize;
+ /** Input block size in octets */
+ unsigned long blocksize;
+ /** ASN.1 OID */
+ unsigned long OID[16];
+ /** Length of DER encoding */
+ unsigned long OIDlen;
+
+ /** Init a hash state
+ @param hash The hash to initialize
+ @return CRYPT_OK if successful
+ */
+ int (*init)(hash_state *hash);
+ /** Process a block of data
+ @param hash The hash state
+ @param in The data to hash
+ @param inlen The length of the data (octets)
+ @return CRYPT_OK if successful
+ */
+ int (*process)(hash_state *hash, const unsigned char *in, unsigned long inlen);
+ /** Produce the digest and store it
+ @param hash The hash state
+ @param out [out] The destination of the digest
+ @return CRYPT_OK if successful
+ */
+ int (*done)(hash_state *hash, unsigned char *out);
+ /** Self-test
+ @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+ */
+ int (*test)(void);
+
+ /* accelerated hmac callback: if you need to-do multiple packets just use the generic hmac_memory and provide a hash callback */
+ int (*hmac_block)(const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+} hash_descriptor[];
+
+#ifdef LTC_CHC_HASH
+int chc_register(int cipher);
+int chc_init(hash_state * md);
+int chc_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int chc_done(hash_state * md, unsigned char *hash);
+int chc_test(void);
+extern const struct ltc_hash_descriptor chc_desc;
+#endif
+
+#ifdef LTC_WHIRLPOOL
+int whirlpool_init(hash_state * md);
+int whirlpool_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int whirlpool_done(hash_state * md, unsigned char *hash);
+int whirlpool_test(void);
+extern const struct ltc_hash_descriptor whirlpool_desc;
+#endif
+
+#ifdef LTC_SHA512
+int sha512_init(hash_state * md);
+int sha512_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int sha512_done(hash_state * md, unsigned char *hash);
+int sha512_test(void);
+extern const struct ltc_hash_descriptor sha512_desc;
+#endif
+
+#ifdef LTC_SHA384
+#ifndef LTC_SHA512
+ #error LTC_SHA512 is required for LTC_SHA384
+#endif
+int sha384_init(hash_state * md);
+#define sha384_process sha512_process
+int sha384_done(hash_state * md, unsigned char *hash);
+int sha384_test(void);
+extern const struct ltc_hash_descriptor sha384_desc;
+#endif
+
+#ifdef LTC_SHA256
+int sha256_init(hash_state * md);
+int sha256_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int sha256_done(hash_state * md, unsigned char *hash);
+int sha256_test(void);
+extern const struct ltc_hash_descriptor sha256_desc;
+
+#ifdef LTC_SHA224
+#ifndef LTC_SHA256
+ #error LTC_SHA256 is required for LTC_SHA224
+#endif
+int sha224_init(hash_state * md);
+#define sha224_process sha256_process
+int sha224_done(hash_state * md, unsigned char *hash);
+int sha224_test(void);
+extern const struct ltc_hash_descriptor sha224_desc;
+#endif
+#endif
+
+#ifdef LTC_SHA1
+int sha1_init(hash_state * md);
+int sha1_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int sha1_done(hash_state * md, unsigned char *hash);
+int sha1_test(void);
+extern const struct ltc_hash_descriptor sha1_desc;
+#endif
+
+#ifdef LTC_MD5
+int md5_init(hash_state * md);
+int md5_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int md5_done(hash_state * md, unsigned char *hash);
+int md5_test(void);
+extern const struct ltc_hash_descriptor md5_desc;
+#endif
+
+#ifdef LTC_MD4
+int md4_init(hash_state * md);
+int md4_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int md4_done(hash_state * md, unsigned char *hash);
+int md4_test(void);
+extern const struct ltc_hash_descriptor md4_desc;
+#endif
+
+#ifdef LTC_MD2
+int md2_init(hash_state * md);
+int md2_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int md2_done(hash_state * md, unsigned char *hash);
+int md2_test(void);
+extern const struct ltc_hash_descriptor md2_desc;
+#endif
+
+#ifdef LTC_TIGER
+int tiger_init(hash_state * md);
+int tiger_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int tiger_done(hash_state * md, unsigned char *hash);
+int tiger_test(void);
+extern const struct ltc_hash_descriptor tiger_desc;
+#endif
+
+#ifdef LTC_RIPEMD128
+int rmd128_init(hash_state * md);
+int rmd128_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int rmd128_done(hash_state * md, unsigned char *hash);
+int rmd128_test(void);
+extern const struct ltc_hash_descriptor rmd128_desc;
+#endif
+
+#ifdef LTC_RIPEMD160
+int rmd160_init(hash_state * md);
+int rmd160_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int rmd160_done(hash_state * md, unsigned char *hash);
+int rmd160_test(void);
+extern const struct ltc_hash_descriptor rmd160_desc;
+#endif
+
+#ifdef LTC_RIPEMD256
+int rmd256_init(hash_state * md);
+int rmd256_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int rmd256_done(hash_state * md, unsigned char *hash);
+int rmd256_test(void);
+extern const struct ltc_hash_descriptor rmd256_desc;
+#endif
+
+#ifdef LTC_RIPEMD320
+int rmd320_init(hash_state * md);
+int rmd320_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int rmd320_done(hash_state * md, unsigned char *hash);
+int rmd320_test(void);
+extern const struct ltc_hash_descriptor rmd320_desc;
+#endif
+
+
+int find_hash(const char *name);
+int find_hash_id(unsigned char ID);
+int find_hash_oid(const unsigned long *ID, unsigned long IDlen);
+int find_hash_any(const char *name, int digestlen);
+int register_hash(const struct ltc_hash_descriptor *hash);
+int unregister_hash(const struct ltc_hash_descriptor *hash);
+int hash_is_valid(int idx);
+
+LTC_MUTEX_PROTO(ltc_hash_mutex)
+
+int hash_memory(int hash,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int hash_memory_multi(int hash, unsigned char *out, unsigned long *outlen,
+ const unsigned char *in, unsigned long inlen, ...);
+int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outlen);
+int hash_file(int hash, const char *fname, unsigned char *out, unsigned long *outlen);
+
+/* a simple macro for making hash "process" functions */
+#define HASH_PROCESS(func_name, compress_name, state_var, block_size) \
+int func_name (hash_state * md, const unsigned char *in, unsigned long inlen) \
+{ \
+ unsigned long n; \
+ int err; \
+ LTC_ARGCHK(md != NULL); \
+ LTC_ARGCHK(in != NULL); \
+ if (md-> state_var .curlen > sizeof(md-> state_var .buf)) { \
+ return CRYPT_INVALID_ARG; \
+ } \
+ while (inlen > 0) { \
+ if (md-> state_var .curlen == 0 && inlen >= block_size) { \
+ if ((err = compress_name (md, (unsigned char *)in)) != CRYPT_OK) { \
+ return err; \
+ } \
+ md-> state_var .length += block_size * 8; \
+ in += block_size; \
+ inlen -= block_size; \
+ } else { \
+ n = MIN(inlen, (block_size - md-> state_var .curlen)); \
+ memcpy(md-> state_var .buf + md-> state_var.curlen, in, (size_t)n); \
+ md-> state_var .curlen += n; \
+ in += n; \
+ inlen -= n; \
+ if (md-> state_var .curlen == block_size) { \
+ if ((err = compress_name (md, md-> state_var .buf)) != CRYPT_OK) { \
+ return err; \
+ } \
+ md-> state_var .length += 8*block_size; \
+ md-> state_var .curlen = 0; \
+ } \
+ } \
+ } \
+ return CRYPT_OK; \
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_hash.h,v $ */
+/* $Revision: 1.22 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_mac.h b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_mac.h
new file mode 100644
index 00000000000..7ad9516bd29
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_mac.h
@@ -0,0 +1,384 @@
+#ifdef LTC_HMAC
+typedef struct Hmac_state {
+ hash_state md;
+ int hash;
+ hash_state hashstate;
+ unsigned char *key;
+} hmac_state;
+
+int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen);
+int hmac_process(hmac_state *hmac, const unsigned char *in, unsigned long inlen);
+int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen);
+int hmac_test(void);
+int hmac_memory(int hash,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int hmac_memory_multi(int hash,
+ const unsigned char *key, unsigned long keylen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *in, unsigned long inlen, ...);
+int hmac_file(int hash, const char *fname, const unsigned char *key,
+ unsigned long keylen,
+ unsigned char *dst, unsigned long *dstlen);
+#endif
+
+#ifdef LTC_OMAC
+
+typedef struct {
+ int cipher_idx,
+ buflen,
+ blklen;
+ unsigned char block[MAXBLOCKSIZE],
+ prev[MAXBLOCKSIZE],
+ Lu[2][MAXBLOCKSIZE];
+ symmetric_key key;
+} omac_state;
+
+int omac_init(omac_state *omac, int cipher, const unsigned char *key, unsigned long keylen);
+int omac_process(omac_state *omac, const unsigned char *in, unsigned long inlen);
+int omac_done(omac_state *omac, unsigned char *out, unsigned long *outlen);
+int omac_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int omac_memory_multi(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *in, unsigned long inlen, ...);
+int omac_file(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const char *filename,
+ unsigned char *out, unsigned long *outlen);
+int omac_test(void);
+#endif /* LTC_OMAC */
+
+#ifdef LTC_PMAC
+
+typedef struct {
+ unsigned char Ls[32][MAXBLOCKSIZE], /* L shifted by i bits to the left */
+ Li[MAXBLOCKSIZE], /* value of Li [current value, we calc from previous recall] */
+ Lr[MAXBLOCKSIZE], /* L * x^-1 */
+ block[MAXBLOCKSIZE], /* currently accumulated block */
+ checksum[MAXBLOCKSIZE]; /* current checksum */
+
+ symmetric_key key; /* scheduled key for cipher */
+ unsigned long block_index; /* index # for current block */
+ int cipher_idx, /* cipher idx */
+ block_len, /* length of block */
+ buflen; /* number of bytes in the buffer */
+} pmac_state;
+
+int pmac_init(pmac_state *pmac, int cipher, const unsigned char *key, unsigned long keylen);
+int pmac_process(pmac_state *pmac, const unsigned char *in, unsigned long inlen);
+int pmac_done(pmac_state *pmac, unsigned char *out, unsigned long *outlen);
+
+int pmac_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *msg, unsigned long msglen,
+ unsigned char *out, unsigned long *outlen);
+
+int pmac_memory_multi(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *in, unsigned long inlen, ...);
+
+int pmac_file(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const char *filename,
+ unsigned char *out, unsigned long *outlen);
+
+int pmac_test(void);
+
+/* internal functions */
+int pmac_ntz(unsigned long x);
+void pmac_shift_xor(pmac_state *pmac);
+
+#endif /* PMAC */
+
+#ifdef LTC_EAX_MODE
+
+#if !(defined(LTC_OMAC) && defined(LTC_CTR_MODE))
+ #error LTC_EAX_MODE requires LTC_OMAC and CTR
+#endif
+
+typedef struct {
+ unsigned char N[MAXBLOCKSIZE];
+ symmetric_CTR ctr;
+ omac_state headeromac, ctomac;
+} eax_state;
+
+int eax_init(eax_state *eax, int cipher, const unsigned char *key, unsigned long keylen,
+ const unsigned char *nonce, unsigned long noncelen,
+ const unsigned char *header, unsigned long headerlen);
+
+int eax_encrypt(eax_state *eax, const unsigned char *pt, unsigned char *ct, unsigned long length);
+int eax_decrypt(eax_state *eax, const unsigned char *ct, unsigned char *pt, unsigned long length);
+int eax_addheader(eax_state *eax, const unsigned char *header, unsigned long length);
+int eax_done(eax_state *eax, unsigned char *tag, unsigned long *taglen);
+
+int eax_encrypt_authenticate_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *nonce, unsigned long noncelen,
+ const unsigned char *header, unsigned long headerlen,
+ const unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ unsigned char *tag, unsigned long *taglen);
+
+int eax_decrypt_verify_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *nonce, unsigned long noncelen,
+ const unsigned char *header, unsigned long headerlen,
+ const unsigned char *ct, unsigned long ctlen,
+ unsigned char *pt,
+ unsigned char *tag, unsigned long taglen,
+ int *stat);
+
+ int eax_test(void);
+#endif /* EAX MODE */
+
+#ifdef LTC_OCB_MODE
+typedef struct {
+ unsigned char L[MAXBLOCKSIZE], /* L value */
+ Ls[32][MAXBLOCKSIZE], /* L shifted by i bits to the left */
+ Li[MAXBLOCKSIZE], /* value of Li [current value, we calc from previous recall] */
+ Lr[MAXBLOCKSIZE], /* L * x^-1 */
+ R[MAXBLOCKSIZE], /* R value */
+ checksum[MAXBLOCKSIZE]; /* current checksum */
+
+ symmetric_key key; /* scheduled key for cipher */
+ unsigned long block_index; /* index # for current block */
+ int cipher, /* cipher idx */
+ block_len; /* length of block */
+} ocb_state;
+
+int ocb_init(ocb_state *ocb, int cipher,
+ const unsigned char *key, unsigned long keylen, const unsigned char *nonce);
+
+int ocb_encrypt(ocb_state *ocb, const unsigned char *pt, unsigned char *ct);
+int ocb_decrypt(ocb_state *ocb, const unsigned char *ct, unsigned char *pt);
+
+int ocb_done_encrypt(ocb_state *ocb,
+ const unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ unsigned char *tag, unsigned long *taglen);
+
+int ocb_done_decrypt(ocb_state *ocb,
+ const unsigned char *ct, unsigned long ctlen,
+ unsigned char *pt,
+ const unsigned char *tag, unsigned long taglen, int *stat);
+
+int ocb_encrypt_authenticate_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *nonce,
+ const unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ unsigned char *tag, unsigned long *taglen);
+
+int ocb_decrypt_verify_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *nonce,
+ const unsigned char *ct, unsigned long ctlen,
+ unsigned char *pt,
+ const unsigned char *tag, unsigned long taglen,
+ int *stat);
+
+int ocb_test(void);
+
+/* internal functions */
+void ocb_shift_xor(ocb_state *ocb, unsigned char *Z);
+int ocb_ntz(unsigned long x);
+int s_ocb_done(ocb_state *ocb, const unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct, unsigned char *tag, unsigned long *taglen, int mode);
+
+#endif /* LTC_OCB_MODE */
+
+#ifdef LTC_CCM_MODE
+
+#define CCM_ENCRYPT 0
+#define CCM_DECRYPT 1
+
+int ccm_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ symmetric_key *uskey,
+ const unsigned char *nonce, unsigned long noncelen,
+ const unsigned char *header, unsigned long headerlen,
+ unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ unsigned char *tag, unsigned long *taglen,
+ int direction);
+
+int ccm_test(void);
+
+#endif /* LTC_CCM_MODE */
+
+#if defined(LRW_MODE) || defined(LTC_GCM_MODE)
+void gcm_gf_mult(const unsigned char *a, const unsigned char *b, unsigned char *c);
+#endif
+
+
+/* table shared between GCM and LRW */
+#if defined(LTC_GCM_TABLES) || defined(LRW_TABLES) || ((defined(LTC_GCM_MODE) || defined(LTC_GCM_MODE)) && defined(LTC_FAST))
+extern const unsigned char gcm_shift_table[];
+#endif
+
+#ifdef LTC_GCM_MODE
+
+#define GCM_ENCRYPT 0
+#define GCM_DECRYPT 1
+
+#define LTC_GCM_MODE_IV 0
+#define LTC_GCM_MODE_AAD 1
+#define LTC_GCM_MODE_TEXT 2
+
+typedef struct {
+ symmetric_key K;
+ unsigned char H[16], /* multiplier */
+ X[16], /* accumulator */
+ Y[16], /* counter */
+ Y_0[16], /* initial counter */
+ buf[16]; /* buffer for stuff */
+
+ int cipher, /* which cipher */
+ ivmode, /* Which mode is the IV in? */
+ mode, /* mode the GCM code is in */
+ buflen; /* length of data in buf */
+
+ ulong64 totlen, /* 64-bit counter used for IV and AAD */
+ pttotlen; /* 64-bit counter for the PT */
+
+#ifdef LTC_GCM_TABLES
+ unsigned char PC[16][256][16] /* 16 tables of 8x128 */
+#ifdef LTC_GCM_TABLES_SSE2
+__attribute__ ((aligned (16)))
+#endif
+;
+#endif
+} gcm_state;
+
+void gcm_mult_h(gcm_state *gcm, unsigned char *I);
+
+int gcm_init(gcm_state *gcm, int cipher,
+ const unsigned char *key, int keylen);
+
+int gcm_reset(gcm_state *gcm);
+
+int gcm_add_iv(gcm_state *gcm,
+ const unsigned char *IV, unsigned long IVlen);
+
+int gcm_add_aad(gcm_state *gcm,
+ const unsigned char *adata, unsigned long adatalen);
+
+int gcm_process(gcm_state *gcm,
+ unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ int direction);
+
+int gcm_done(gcm_state *gcm,
+ unsigned char *tag, unsigned long *taglen);
+
+int gcm_memory( int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *IV, unsigned long IVlen,
+ const unsigned char *adata, unsigned long adatalen,
+ unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ unsigned char *tag, unsigned long *taglen,
+ int direction);
+int gcm_test(void);
+
+#endif /* LTC_GCM_MODE */
+
+#ifdef LTC_PELICAN
+
+typedef struct pelican_state
+{
+ symmetric_key K;
+ unsigned char state[16];
+ int buflen;
+} pelican_state;
+
+int pelican_init(pelican_state *pelmac, const unsigned char *key, unsigned long keylen);
+int pelican_process(pelican_state *pelmac, const unsigned char *in, unsigned long inlen);
+int pelican_done(pelican_state *pelmac, unsigned char *out);
+int pelican_test(void);
+
+int pelican_memory(const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out);
+
+#endif
+
+#ifdef LTC_XCBC
+
+/* add this to "keylen" to xcbc_init to use a pure three-key XCBC MAC */
+#define LTC_XCBC_PURE 0x8000UL
+
+typedef struct {
+ unsigned char K[3][MAXBLOCKSIZE],
+ IV[MAXBLOCKSIZE];
+
+ symmetric_key key;
+
+ int cipher,
+ buflen,
+ blocksize;
+} xcbc_state;
+
+int xcbc_init(xcbc_state *xcbc, int cipher, const unsigned char *key, unsigned long keylen);
+int xcbc_process(xcbc_state *xcbc, const unsigned char *in, unsigned long inlen);
+int xcbc_done(xcbc_state *xcbc, unsigned char *out, unsigned long *outlen);
+int xcbc_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int xcbc_memory_multi(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *in, unsigned long inlen, ...);
+int xcbc_file(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const char *filename,
+ unsigned char *out, unsigned long *outlen);
+int xcbc_test(void);
+
+#endif
+
+#ifdef LTC_F9_MODE
+
+typedef struct {
+ unsigned char akey[MAXBLOCKSIZE],
+ ACC[MAXBLOCKSIZE],
+ IV[MAXBLOCKSIZE];
+
+ symmetric_key key;
+
+ int cipher,
+ buflen,
+ keylen,
+ blocksize;
+} f9_state;
+
+int f9_init(f9_state *f9, int cipher, const unsigned char *key, unsigned long keylen);
+int f9_process(f9_state *f9, const unsigned char *in, unsigned long inlen);
+int f9_done(f9_state *f9, unsigned char *out, unsigned long *outlen);
+int f9_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int f9_memory_multi(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *in, unsigned long inlen, ...);
+int f9_file(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const char *filename,
+ unsigned char *out, unsigned long *outlen);
+int f9_test(void);
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_mac.h,v $ */
+/* $Revision: 1.23 $ */
+/* $Date: 2007/05/12 14:37:41 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_macros.h b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_macros.h
new file mode 100644
index 00000000000..53bda9bb4ba
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_macros.h
@@ -0,0 +1,424 @@
+/* fix for MSVC ...evil! */
+#ifdef _MSC_VER
+ #define CONST64(n) n ## ui64
+ typedef unsigned __int64 ulong64;
+#else
+ #define CONST64(n) n ## ULL
+ typedef unsigned long long ulong64;
+#endif
+
+/* this is the "32-bit at least" data type
+ * Re-define it to suit your platform but it must be at least 32-bits
+ */
+#if defined(__x86_64__) || (defined(__sparc__) && defined(__arch64__))
+ typedef unsigned ulong32;
+#else
+ typedef unsigned long ulong32;
+#endif
+
+/* ---- HELPER MACROS ---- */
+#ifdef ENDIAN_NEUTRAL
+
+#define STORE32L(x, y) \
+ { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD32L(x, y) \
+ { x = ((unsigned long)((y)[3] & 255)<<24) | \
+ ((unsigned long)((y)[2] & 255)<<16) | \
+ ((unsigned long)((y)[1] & 255)<<8) | \
+ ((unsigned long)((y)[0] & 255)); }
+
+#define STORE64L(x, y) \
+ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y) \
+ { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+ (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+ (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+ (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#define STORE32H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y) \
+ { x = ((unsigned long)((y)[0] & 255)<<24) | \
+ ((unsigned long)((y)[1] & 255)<<16) | \
+ ((unsigned long)((y)[2] & 255)<<8) | \
+ ((unsigned long)((y)[3] & 255)); }
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+ (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+ (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+ (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
+
+#endif /* ENDIAN_NEUTRAL */
+
+#ifdef ENDIAN_LITTLE
+
+#if !defined(LTC_NO_BSWAP) && (defined(INTEL_CC) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__) || defined(__x86_64__))))
+
+#define STORE32H(x, y) \
+asm __volatile__ ( \
+ "bswapl %0 \n\t" \
+ "movl %0,(%1)\n\t" \
+ "bswapl %0 \n\t" \
+ ::"r"(x), "r"(y));
+
+#define LOAD32H(x, y) \
+asm __volatile__ ( \
+ "movl (%1),%0\n\t" \
+ "bswapl %0\n\t" \
+ :"=r"(x): "r"(y));
+
+#else
+
+#define STORE32H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y) \
+ { x = ((unsigned long)((y)[0] & 255)<<24) | \
+ ((unsigned long)((y)[1] & 255)<<16) | \
+ ((unsigned long)((y)[2] & 255)<<8) | \
+ ((unsigned long)((y)[3] & 255)); }
+
+#endif
+
+
+/* x86_64 processor */
+#if !defined(LTC_NO_BSWAP) && (defined(__GNUC__) && defined(__x86_64__))
+
+#define STORE64H(x, y) \
+asm __volatile__ ( \
+ "bswapq %0 \n\t" \
+ "movq %0,(%1)\n\t" \
+ "bswapq %0 \n\t" \
+ ::"r"(x), "r"(y));
+
+#define LOAD64H(x, y) \
+asm __volatile__ ( \
+ "movq (%1),%0\n\t" \
+ "bswapq %0\n\t" \
+ :"=r"(x): "r"(y));
+
+#else
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+ (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+ (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+ (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
+
+#endif
+
+#ifdef ENDIAN_32BITWORD
+
+#define STORE32L(x, y) \
+ { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32L(x, y) \
+ XMEMCPY(&(x), y, 4);
+
+#define STORE64L(x, y) \
+ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y) \
+ { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+ (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+ (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+ (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#else /* 64-bit words then */
+
+#define STORE32L(x, y) \
+ { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32L(x, y) \
+ { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; }
+
+#define STORE64L(x, y) \
+ { ulong64 __t = (x); XMEMCPY(y, &__t, 8); }
+
+#define LOAD64L(x, y) \
+ { XMEMCPY(&(x), y, 8); }
+
+#endif /* ENDIAN_64BITWORD */
+
+#endif /* ENDIAN_LITTLE */
+
+#ifdef ENDIAN_BIG
+#define STORE32L(x, y) \
+ { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD32L(x, y) \
+ { x = ((unsigned long)((y)[3] & 255)<<24) | \
+ ((unsigned long)((y)[2] & 255)<<16) | \
+ ((unsigned long)((y)[1] & 255)<<8) | \
+ ((unsigned long)((y)[0] & 255)); }
+
+#define STORE64L(x, y) \
+ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y) \
+ { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48) | \
+ (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32) | \
+ (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16) | \
+ (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#ifdef ENDIAN_32BITWORD
+
+#define STORE32H(x, y) \
+ { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32H(x, y) \
+ XMEMCPY(&(x), y, 4);
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48)| \
+ (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32)| \
+ (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16)| \
+ (((ulong64)((y)[6] & 255))<<8)| (((ulong64)((y)[7] & 255))); }
+
+#else /* 64-bit words then */
+
+#define STORE32H(x, y) \
+ { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32H(x, y) \
+ { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; }
+
+#define STORE64H(x, y) \
+ { ulong64 __t = (x); XMEMCPY(y, &__t, 8); }
+
+#define LOAD64H(x, y) \
+ { XMEMCPY(&(x), y, 8); }
+
+#endif /* ENDIAN_64BITWORD */
+#endif /* ENDIAN_BIG */
+
+#define BSWAP(x) ( ((x>>24)&0x000000FFUL) | ((x<<24)&0xFF000000UL) | \
+ ((x>>8)&0x0000FF00UL) | ((x<<8)&0x00FF0000UL) )
+
+
+/* 32-bit Rotates */
+#if defined(_MSC_VER)
+
+/* instrinsic rotate */
+#include <stdlib.h>
+#pragma intrinsic(_lrotr,_lrotl)
+#define ROR(x,n) _lrotr(x,n)
+#define ROL(x,n) _lrotl(x,n)
+#define RORc(x,n) _lrotr(x,n)
+#define ROLc(x,n) _lrotl(x,n)
+
+#elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) && !defined(LTC_NO_ASM)
+
+static inline unsigned ROL(unsigned word, int i)
+{
+ asm ("roll %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+static inline unsigned ROR(unsigned word, int i)
+{
+ asm ("rorl %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+static inline unsigned ROLc(unsigned word, const int i)
+{
+ asm ("roll %2,%0"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+static inline unsigned RORc(unsigned word, const int i)
+{
+ asm ("rorl %2,%0"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+#else
+
+#define ROLc ROL
+#define RORc ROR
+
+#endif
+
+#elif !defined(__STRICT_ANSI__) && defined(LTC_PPC32)
+
+static inline unsigned ROL(unsigned word, int i)
+{
+ asm ("rotlw %0,%0,%2"
+ :"=r" (word)
+ :"0" (word),"r" (i));
+ return word;
+}
+
+static inline unsigned ROR(unsigned word, int i)
+{
+ asm ("rotlw %0,%0,%2"
+ :"=r" (word)
+ :"0" (word),"r" (32-i));
+ return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+static inline unsigned ROLc(unsigned word, const int i)
+{
+ asm ("rotlwi %0,%0,%2"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+static inline unsigned RORc(unsigned word, const int i)
+{
+ asm ("rotrwi %0,%0,%2"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+#else
+
+#define ROLc ROL
+#define RORc ROR
+
+#endif
+
+
+#else
+
+/* rotates the hard way */
+#define ROL(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROR(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROLc(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+
+#endif
+
+
+/* 64-bit Rotates */
+#if !defined(__STRICT_ANSI__) && defined(__GNUC__) && defined(__x86_64__) && !defined(LTC_NO_ASM)
+
+static inline unsigned long ROL64(unsigned long word, int i)
+{
+ asm("rolq %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+static inline unsigned long ROR64(unsigned long word, int i)
+{
+ asm("rorq %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+static inline unsigned long ROL64c(unsigned long word, const int i)
+{
+ asm("rolq %2,%0"
+ :"=r" (word)
+ :"0" (word),"J" (i));
+ return word;
+}
+
+static inline unsigned long ROR64c(unsigned long word, const int i)
+{
+ asm("rorq %2,%0"
+ :"=r" (word)
+ :"0" (word),"J" (i));
+ return word;
+}
+
+#else /* LTC_NO_ROLC */
+
+#define ROL64c ROL64
+#define ROR64c ROR64
+
+#endif
+
+#else /* Not x86_64 */
+
+#define ROL64(x, y) \
+ ( (((x)<<((ulong64)(y)&63)) | \
+ (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64(x, y) \
+ ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+ ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROL64c(x, y) \
+ ( (((x)<<((ulong64)(y)&63)) | \
+ (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64c(x, y) \
+ ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+ ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#endif
+
+#ifndef MAX
+ #define MAX(x, y) ( ((x)>(y))?(x):(y) )
+#endif
+
+#ifndef MIN
+ #define MIN(x, y) ( ((x)<(y))?(x):(y) )
+#endif
+
+/* extract a byte portably */
+#ifdef _MSC_VER
+ #define byte(x, n) ((unsigned char)((x) >> (8 * (n))))
+#else
+ #define byte(x, n) (((x) >> (8 * (n))) & 255)
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_macros.h,v $ */
+/* $Revision: 1.15 $ */
+/* $Date: 2006/11/29 23:43:57 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_math.h b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_math.h
new file mode 100644
index 00000000000..a05d7fff942
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_math.h
@@ -0,0 +1,500 @@
+/** math functions **/
+
+#define LTC_MP_LT -1
+#define LTC_MP_EQ 0
+#define LTC_MP_GT 1
+
+#define LTC_MP_NO 0
+#define LTC_MP_YES 1
+
+#ifndef LTC_MECC
+ typedef void ecc_point;
+#endif
+
+#ifndef LTC_MRSA
+ typedef void rsa_key;
+#endif
+
+/** math descriptor */
+typedef struct {
+ /** Name of the math provider */
+ char *name;
+
+ /** Bits per digit, amount of bits must fit in an unsigned long */
+ int bits_per_digit;
+
+/* ---- init/deinit functions ---- */
+
+ /** initialize a bignum
+ @param a The number to initialize
+ @return CRYPT_OK on success
+ */
+ int (*init)(void **a);
+
+ /** init copy
+ @param dst The number to initialize and write to
+ @param src The number to copy from
+ @return CRYPT_OK on success
+ */
+ int (*init_copy)(void **dst, void *src);
+
+ /** deinit
+ @param a The number to free
+ @return CRYPT_OK on success
+ */
+ void (*deinit)(void *a);
+
+/* ---- data movement ---- */
+
+ /** negate
+ @param src The number to negate
+ @param dst The destination
+ @return CRYPT_OK on success
+ */
+ int (*neg)(void *src, void *dst);
+
+ /** copy
+ @param src The number to copy from
+ @param dst The number to write to
+ @return CRYPT_OK on success
+ */
+ int (*copy)(void *src, void *dst);
+
+/* ---- trivial low level functions ---- */
+
+ /** set small constant
+ @param a Number to write to
+ @param n Source upto bits_per_digit (actually meant for very small constants)
+ @return CRYPT_OK on succcess
+ */
+ int (*set_int)(void *a, unsigned long n);
+
+ /** get small constant
+ @param a Number to read, only fetches upto bits_per_digit from the number
+ @return The lower bits_per_digit of the integer (unsigned)
+ */
+ unsigned long (*get_int)(void *a);
+
+ /** get digit n
+ @param a The number to read from
+ @param n The number of the digit to fetch
+ @return The bits_per_digit sized n'th digit of a
+ */
+ unsigned long (*get_digit)(void *a, int n);
+
+ /** Get the number of digits that represent the number
+ @param a The number to count
+ @return The number of digits used to represent the number
+ */
+ int (*get_digit_count)(void *a);
+
+ /** compare two integers
+ @param a The left side integer
+ @param b The right side integer
+ @return LTC_MP_LT if a < b, LTC_MP_GT if a > b and LTC_MP_EQ otherwise. (signed comparison)
+ */
+ int (*compare)(void *a, void *b);
+
+ /** compare against int
+ @param a The left side integer
+ @param b The right side integer (upto bits_per_digit)
+ @return LTC_MP_LT if a < b, LTC_MP_GT if a > b and LTC_MP_EQ otherwise. (signed comparison)
+ */
+ int (*compare_d)(void *a, unsigned long n);
+
+ /** Count the number of bits used to represent the integer
+ @param a The integer to count
+ @return The number of bits required to represent the integer
+ */
+ int (*count_bits)(void * a);
+
+ /** Count the number of LSB bits which are zero
+ @param a The integer to count
+ @return The number of contiguous zero LSB bits
+ */
+ int (*count_lsb_bits)(void *a);
+
+ /** Compute a power of two
+ @param a The integer to store the power in
+ @param n The power of two you want to store (a = 2^n)
+ @return CRYPT_OK on success
+ */
+ int (*twoexpt)(void *a , int n);
+
+/* ---- radix conversions ---- */
+
+ /** read ascii string
+ @param a The integer to store into
+ @param str The string to read
+ @param radix The radix the integer has been represented in (2-64)
+ @return CRYPT_OK on success
+ */
+ int (*read_radix)(void *a, const char *str, int radix);
+
+ /** write number to string
+ @param a The integer to store
+ @param str The destination for the string
+ @param radix The radix the integer is to be represented in (2-64)
+ @return CRYPT_OK on success
+ */
+ int (*write_radix)(void *a, char *str, int radix);
+
+ /** get size as unsigned char string
+ @param a The integer to get the size (when stored in array of octets)
+ @return The length of the integer
+ */
+ unsigned long (*unsigned_size)(void *a);
+
+ /** store an integer as an array of octets
+ @param src The integer to store
+ @param dst The buffer to store the integer in
+ @return CRYPT_OK on success
+ */
+ int (*unsigned_write)(void *src, unsigned char *dst);
+
+ /** read an array of octets and store as integer
+ @param dst The integer to load
+ @param src The array of octets
+ @param len The number of octets
+ @return CRYPT_OK on success
+ */
+ int (*unsigned_read)(void *dst, unsigned char *src, unsigned long len);
+
+/* ---- basic math ---- */
+
+ /** add two integers
+ @param a The first source integer
+ @param b The second source integer
+ @param c The destination of "a + b"
+ @return CRYPT_OK on success
+ */
+ int (*add)(void *a, void *b, void *c);
+
+
+ /** add two integers
+ @param a The first source integer
+ @param b The second source integer (single digit of upto bits_per_digit in length)
+ @param c The destination of "a + b"
+ @return CRYPT_OK on success
+ */
+ int (*addi)(void *a, unsigned long b, void *c);
+
+ /** subtract two integers
+ @param a The first source integer
+ @param b The second source integer
+ @param c The destination of "a - b"
+ @return CRYPT_OK on success
+ */
+ int (*sub)(void *a, void *b, void *c);
+
+ /** subtract two integers
+ @param a The first source integer
+ @param b The second source integer (single digit of upto bits_per_digit in length)
+ @param c The destination of "a - b"
+ @return CRYPT_OK on success
+ */
+ int (*subi)(void *a, unsigned long b, void *c);
+
+ /** multiply two integers
+ @param a The first source integer
+ @param b The second source integer (single digit of upto bits_per_digit in length)
+ @param c The destination of "a * b"
+ @return CRYPT_OK on success
+ */
+ int (*mul)(void *a, void *b, void *c);
+
+ /** multiply two integers
+ @param a The first source integer
+ @param b The second source integer (single digit of upto bits_per_digit in length)
+ @param c The destination of "a * b"
+ @return CRYPT_OK on success
+ */
+ int (*muli)(void *a, unsigned long b, void *c);
+
+ /** Square an integer
+ @param a The integer to square
+ @param b The destination
+ @return CRYPT_OK on success
+ */
+ int (*sqr)(void *a, void *b);
+
+ /** Divide an integer
+ @param a The dividend
+ @param b The divisor
+ @param c The quotient (can be NULL to signify don't care)
+ @param d The remainder (can be NULL to signify don't care)
+ @return CRYPT_OK on success
+ */
+ int (*mpdiv)(void *a, void *b, void *c, void *d);
+
+ /** divide by two
+ @param a The integer to divide (shift right)
+ @param b The destination
+ @return CRYPT_OK on success
+ */
+ int (*div_2)(void *a, void *b);
+
+ /** Get remainder (small value)
+ @param a The integer to reduce
+ @param b The modulus (upto bits_per_digit in length)
+ @param c The destination for the residue
+ @return CRYPT_OK on success
+ */
+ int (*modi)(void *a, unsigned long b, unsigned long *c);
+
+ /** gcd
+ @param a The first integer
+ @param b The second integer
+ @param c The destination for (a, b)
+ @return CRYPT_OK on success
+ */
+ int (*gcd)(void *a, void *b, void *c);
+
+ /** lcm
+ @param a The first integer
+ @param b The second integer
+ @param c The destination for [a, b]
+ @return CRYPT_OK on success
+ */
+ int (*lcm)(void *a, void *b, void *c);
+
+ /** Modular multiplication
+ @param a The first source
+ @param b The second source
+ @param c The modulus
+ @param d The destination (a*b mod c)
+ @return CRYPT_OK on success
+ */
+ int (*mulmod)(void *a, void *b, void *c, void *d);
+
+ /** Modular squaring
+ @param a The first source
+ @param b The modulus
+ @param c The destination (a*a mod b)
+ @return CRYPT_OK on success
+ */
+ int (*sqrmod)(void *a, void *b, void *c);
+
+ /** Modular inversion
+ @param a The value to invert
+ @param b The modulus
+ @param c The destination (1/a mod b)
+ @return CRYPT_OK on success
+ */
+ int (*invmod)(void *, void *, void *);
+
+/* ---- reduction ---- */
+
+ /** setup montgomery
+ @param a The modulus
+ @param b The destination for the reduction digit
+ @return CRYPT_OK on success
+ */
+ int (*montgomery_setup)(void *a, void **b);
+
+ /** get normalization value
+ @param a The destination for the normalization value
+ @param b The modulus
+ @return CRYPT_OK on success
+ */
+ int (*montgomery_normalization)(void *a, void *b);
+
+ /** reduce a number
+ @param a The number [and dest] to reduce
+ @param b The modulus
+ @param c The value "b" from montgomery_setup()
+ @return CRYPT_OK on success
+ */
+ int (*montgomery_reduce)(void *a, void *b, void *c);
+
+ /** clean up (frees memory)
+ @param a The value "b" from montgomery_setup()
+ @return CRYPT_OK on success
+ */
+ void (*montgomery_deinit)(void *a);
+
+/* ---- exponentiation ---- */
+
+ /** Modular exponentiation
+ @param a The base integer
+ @param b The power (can be negative) integer
+ @param c The modulus integer
+ @param d The destination
+ @return CRYPT_OK on success
+ */
+ int (*exptmod)(void *a, void *b, void *c, void *d);
+
+ /** Primality testing
+ @param a The integer to test
+ @param b The destination of the result (FP_YES if prime)
+ @return CRYPT_OK on success
+ */
+ int (*isprime)(void *a, int *b);
+
+/* ---- (optional) ecc point math ---- */
+
+ /** ECC GF(p) point multiplication (from the NIST curves)
+ @param k The integer to multiply the point by
+ @param G The point to multiply
+ @param R The destination for kG
+ @param modulus The modulus for the field
+ @param map Boolean indicated whether to map back to affine or not (can be ignored if you work in affine only)
+ @return CRYPT_OK on success
+ */
+ int (*ecc_ptmul)(void *k, ecc_point *G, ecc_point *R, void *modulus, int map);
+
+ /** ECC GF(p) point addition
+ @param P The first point
+ @param Q The second point
+ @param R The destination of P + Q
+ @param modulus The modulus
+ @param mp The "b" value from montgomery_setup()
+ @return CRYPT_OK on success
+ */
+ int (*ecc_ptadd)(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *mp);
+
+ /** ECC GF(p) point double
+ @param P The first point
+ @param R The destination of 2P
+ @param modulus The modulus
+ @param mp The "b" value from montgomery_setup()
+ @return CRYPT_OK on success
+ */
+ int (*ecc_ptdbl)(ecc_point *P, ecc_point *R, void *modulus, void *mp);
+
+ /** ECC mapping from projective to affine, currently uses (x,y,z) => (x/z^2, y/z^3, 1)
+ @param P The point to map
+ @param modulus The modulus
+ @param mp The "b" value from montgomery_setup()
+ @return CRYPT_OK on success
+ @remark The mapping can be different but keep in mind a ecc_point only has three
+ integers (x,y,z) so if you use a different mapping you have to make it fit.
+ */
+ int (*ecc_map)(ecc_point *P, void *modulus, void *mp);
+
+ /** Computes kA*A + kB*B = C using Shamir's Trick
+ @param A First point to multiply
+ @param kA What to multiple A by
+ @param B Second point to multiply
+ @param kB What to multiple B by
+ @param C [out] Destination point (can overlap with A or B
+ @param modulus Modulus for curve
+ @return CRYPT_OK on success
+ */
+ int (*ecc_mul2add)(ecc_point *A, void *kA,
+ ecc_point *B, void *kB,
+ ecc_point *C,
+ void *modulus);
+
+/* ---- (optional) rsa optimized math (for internal CRT) ---- */
+
+ /** RSA Key Generation
+ @param prng An active PRNG state
+ @param wprng The index of the PRNG desired
+ @param size The size of the modulus (key size) desired (octets)
+ @param e The "e" value (public key). e==65537 is a good choice
+ @param key [out] Destination of a newly created private key pair
+ @return CRYPT_OK if successful, upon error all allocated ram is freed
+ */
+ int (*rsa_keygen)(prng_state *prng, int wprng, int size, long e, rsa_key *key);
+
+
+ /** RSA exponentiation
+ @param in The octet array representing the base
+ @param inlen The length of the input
+ @param out The destination (to be stored in an octet array format)
+ @param outlen The length of the output buffer and the resulting size (zero padded to the size of the modulus)
+ @param which PK_PUBLIC for public RSA and PK_PRIVATE for private RSA
+ @param key The RSA key to use
+ @return CRYPT_OK on success
+ */
+ int (*rsa_me)(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen, int which,
+ rsa_key *key);
+} ltc_math_descriptor;
+
+extern ltc_math_descriptor ltc_mp;
+
+int ltc_init_multi(void **a, ...);
+void ltc_deinit_multi(void *a, ...);
+
+#ifdef LTM_DESC
+extern const ltc_math_descriptor ltm_desc;
+#endif
+
+#ifdef TFM_DESC
+extern const ltc_math_descriptor tfm_desc;
+#endif
+
+#ifdef GMP_DESC
+extern const ltc_math_descriptor gmp_desc;
+#endif
+
+#if !defined(DESC_DEF_ONLY) && defined(LTC_SOURCE)
+
+#define MP_DIGIT_BIT ltc_mp.bits_per_digit
+
+/* some handy macros */
+#define mp_init(a) ltc_mp.init(a)
+#define mp_init_multi ltc_init_multi
+#define mp_clear(a) ltc_mp.deinit(a)
+#define mp_clear_multi ltc_deinit_multi
+#define mp_init_copy(a, b) ltc_mp.init_copy(a, b)
+
+#define mp_neg(a, b) ltc_mp.neg(a, b)
+#define mp_copy(a, b) ltc_mp.copy(a, b)
+
+#define mp_set(a, b) ltc_mp.set_int(a, b)
+#define mp_set_int(a, b) ltc_mp.set_int(a, b)
+#define mp_get_int(a) ltc_mp.get_int(a)
+#define mp_get_digit(a, n) ltc_mp.get_digit(a, n)
+#define mp_get_digit_count(a) ltc_mp.get_digit_count(a)
+#define mp_cmp(a, b) ltc_mp.compare(a, b)
+#define mp_cmp_d(a, b) ltc_mp.compare_d(a, b)
+#define mp_count_bits(a) ltc_mp.count_bits(a)
+#define mp_cnt_lsb(a) ltc_mp.count_lsb_bits(a)
+#define mp_2expt(a, b) ltc_mp.twoexpt(a, b)
+
+#define mp_read_radix(a, b, c) ltc_mp.read_radix(a, b, c)
+#define mp_toradix(a, b, c) ltc_mp.write_radix(a, b, c)
+#define mp_unsigned_bin_size(a) ltc_mp.unsigned_size(a)
+#define mp_to_unsigned_bin(a, b) ltc_mp.unsigned_write(a, b)
+#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
+
+#define mp_add(a, b, c) ltc_mp.add(a, b, c)
+#define mp_add_d(a, b, c) ltc_mp.addi(a, b, c)
+#define mp_sub(a, b, c) ltc_mp.sub(a, b, c)
+#define mp_sub_d(a, b, c) ltc_mp.subi(a, b, c)
+#define mp_mul(a, b, c) ltc_mp.mul(a, b, c)
+#define mp_mul_d(a, b, c) ltc_mp.muli(a, b, c)
+#define mp_sqr(a, b) ltc_mp.sqr(a, b)
+#define mp_div(a, b, c, d) ltc_mp.mpdiv(a, b, c, d)
+#define mp_div_2(a, b) ltc_mp.div_2(a, b)
+#define mp_mod(a, b, c) ltc_mp.mpdiv(a, b, NULL, c)
+#define mp_mod_d(a, b, c) ltc_mp.modi(a, b, c)
+#define mp_gcd(a, b, c) ltc_mp.gcd(a, b, c)
+#define mp_lcm(a, b, c) ltc_mp.lcm(a, b, c)
+
+#define mp_mulmod(a, b, c, d) ltc_mp.mulmod(a, b, c, d)
+#define mp_sqrmod(a, b, c) ltc_mp.sqrmod(a, b, c)
+#define mp_invmod(a, b, c) ltc_mp.invmod(a, b, c)
+
+#define mp_montgomery_setup(a, b) ltc_mp.montgomery_setup(a, b)
+#define mp_montgomery_normalization(a, b) ltc_mp.montgomery_normalization(a, b)
+#define mp_montgomery_reduce(a, b, c) ltc_mp.montgomery_reduce(a, b, c)
+#define mp_montgomery_free(a) ltc_mp.montgomery_deinit(a)
+
+#define mp_exptmod(a,b,c,d) ltc_mp.exptmod(a,b,c,d)
+#define mp_prime_is_prime(a, b, c) ltc_mp.isprime(a, c)
+
+#define mp_iszero(a) (mp_cmp_d(a, 0) == LTC_MP_EQ ? LTC_MP_YES : LTC_MP_NO)
+#define mp_isodd(a) (mp_get_digit_count(a) > 0 ? (mp_get_digit(a, 0) & 1 ? LTC_MP_YES : LTC_MP_NO) : LTC_MP_NO)
+#define mp_exch(a, b) do { void *ABC__tmp = a; a = b; b = ABC__tmp; } while(0);
+
+#define mp_tohex(a, b) mp_toradix(a, b, 16)
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_math.h,v $ */
+/* $Revision: 1.44 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_misc.h b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_misc.h
new file mode 100644
index 00000000000..f5384cacc51
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_misc.h
@@ -0,0 +1,23 @@
+/* ---- LTC_BASE64 Routines ---- */
+#ifdef LTC_BASE64
+int base64_encode(const unsigned char *in, unsigned long len,
+ unsigned char *out, unsigned long *outlen);
+
+int base64_decode(const unsigned char *in, unsigned long len,
+ unsigned char *out, unsigned long *outlen);
+#endif
+
+/* ---- MEM routines ---- */
+void zeromem(void *dst, size_t len);
+void burn_stack(unsigned long len);
+
+const char *error_to_string(int err);
+
+extern const char *crypt_build_settings;
+
+/* ---- HMM ---- */
+int crypt_fsa(void *mp, ...);
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_misc.h,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_pk.h b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_pk.h
new file mode 100644
index 00000000000..b5f277a8848
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_pk.h
@@ -0,0 +1,558 @@
+/* ---- NUMBER THEORY ---- */
+
+enum {
+ PK_PUBLIC=0,
+ PK_PRIVATE=1
+};
+
+int rand_prime(void *N, long len, prng_state *prng, int wprng);
+
+/* ---- RSA ---- */
+#ifdef LTC_MRSA
+
+/* Min and Max RSA key sizes (in bits) */
+#define MIN_RSA_SIZE 1024
+#define MAX_RSA_SIZE 4096
+
+/** RSA LTC_PKCS style key */
+typedef struct Rsa_key {
+ /** Type of key, PK_PRIVATE or PK_PUBLIC */
+ int type;
+ /** The public exponent */
+ void *e;
+ /** The private exponent */
+ void *d;
+ /** The modulus */
+ void *N;
+ /** The p factor of N */
+ void *p;
+ /** The q factor of N */
+ void *q;
+ /** The 1/q mod p CRT param */
+ void *qP;
+ /** The d mod (p - 1) CRT param */
+ void *dP;
+ /** The d mod (q - 1) CRT param */
+ void *dQ;
+} rsa_key;
+
+int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key);
+
+int rsa_exptmod(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen, int which,
+ rsa_key *key);
+
+void rsa_free(rsa_key *key);
+
+/* These use LTC_PKCS #1 v2.0 padding */
+#define rsa_encrypt_key(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _prng, _prng_idx, _hash_idx, _key) \
+ rsa_encrypt_key_ex(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _prng, _prng_idx, _hash_idx, LTC_LTC_PKCS_1_OAEP, _key)
+
+#define rsa_decrypt_key(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _hash_idx, _stat, _key) \
+ rsa_decrypt_key_ex(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _hash_idx, LTC_LTC_PKCS_1_OAEP, _stat, _key)
+
+#define rsa_sign_hash(_in, _inlen, _out, _outlen, _prng, _prng_idx, _hash_idx, _saltlen, _key) \
+ rsa_sign_hash_ex(_in, _inlen, _out, _outlen, LTC_LTC_PKCS_1_PSS, _prng, _prng_idx, _hash_idx, _saltlen, _key)
+
+#define rsa_verify_hash(_sig, _siglen, _hash, _hashlen, _hash_idx, _saltlen, _stat, _key) \
+ rsa_verify_hash_ex(_sig, _siglen, _hash, _hashlen, LTC_LTC_PKCS_1_PSS, _hash_idx, _saltlen, _stat, _key)
+
+/* These can be switched between LTC_PKCS #1 v2.x and LTC_PKCS #1 v1.5 paddings */
+int rsa_encrypt_key_ex(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ prng_state *prng, int prng_idx, int hash_idx, int padding, rsa_key *key);
+
+int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ int hash_idx, int padding,
+ int *stat, rsa_key *key);
+
+int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ int padding,
+ prng_state *prng, int prng_idx,
+ int hash_idx, unsigned long saltlen,
+ rsa_key *key);
+
+int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int padding,
+ int hash_idx, unsigned long saltlen,
+ int *stat, rsa_key *key);
+
+/* LTC_PKCS #1 import/export */
+int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key);
+int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key);
+
+/* Ladik: Added for verifying Blizzard strong signature verification */
+int rsa_verify_simple(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int *stat,
+ rsa_key *key);
+
+#endif
+
+/* ---- Katja ---- */
+#ifdef MKAT
+
+/* Min and Max KAT key sizes (in bits) */
+#define MIN_KAT_SIZE 1024
+#define MAX_KAT_SIZE 4096
+
+/** Katja LTC_PKCS style key */
+typedef struct KAT_key {
+ /** Type of key, PK_PRIVATE or PK_PUBLIC */
+ int type;
+ /** The private exponent */
+ void *d;
+ /** The modulus */
+ void *N;
+ /** The p factor of N */
+ void *p;
+ /** The q factor of N */
+ void *q;
+ /** The 1/q mod p CRT param */
+ void *qP;
+ /** The d mod (p - 1) CRT param */
+ void *dP;
+ /** The d mod (q - 1) CRT param */
+ void *dQ;
+ /** The pq param */
+ void *pq;
+} katja_key;
+
+int katja_make_key(prng_state *prng, int wprng, int size, katja_key *key);
+
+int katja_exptmod(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen, int which,
+ katja_key *key);
+
+void katja_free(katja_key *key);
+
+/* These use LTC_PKCS #1 v2.0 padding */
+int katja_encrypt_key(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ prng_state *prng, int prng_idx, int hash_idx, katja_key *key);
+
+int katja_decrypt_key(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ int hash_idx, int *stat,
+ katja_key *key);
+
+/* LTC_PKCS #1 import/export */
+int katja_export(unsigned char *out, unsigned long *outlen, int type, katja_key *key);
+int katja_import(const unsigned char *in, unsigned long inlen, katja_key *key);
+
+#endif
+
+/* ---- ECC Routines ---- */
+#ifdef LTC_MECC
+
+/* size of our temp buffers for exported keys */
+#define ECC_BUF_SIZE 256
+
+/* max private key size */
+#define ECC_MAXSIZE 66
+
+/** Structure defines a NIST GF(p) curve */
+typedef struct {
+ /** The size of the curve in octets */
+ int size;
+
+ /** name of curve */
+ char *name;
+
+ /** The prime that defines the field the curve is in (encoded in hex) */
+ char *prime;
+
+ /** The fields B param (hex) */
+ char *B;
+
+ /** The order of the curve (hex) */
+ char *order;
+
+ /** The x co-ordinate of the base point on the curve (hex) */
+ char *Gx;
+
+ /** The y co-ordinate of the base point on the curve (hex) */
+ char *Gy;
+} ltc_ecc_set_type;
+
+/** A point on a ECC curve, stored in Jacbobian format such that (x,y,z) => (x/z^2, y/z^3, 1) when interpretted as affine */
+typedef struct {
+ /** The x co-ordinate */
+ void *x;
+
+ /** The y co-ordinate */
+ void *y;
+
+ /** The z co-ordinate */
+ void *z;
+} ecc_point;
+
+/** An ECC key */
+typedef struct {
+ /** Type of key, PK_PRIVATE or PK_PUBLIC */
+ int type;
+
+ /** Index into the ltc_ecc_sets[] for the parameters of this curve; if -1, then this key is using user supplied curve in dp */
+ int idx;
+
+ /** pointer to domain parameters; either points to NIST curves (identified by idx >= 0) or user supplied curve */
+ const ltc_ecc_set_type *dp;
+
+ /** The public key */
+ ecc_point pubkey;
+
+ /** The private key */
+ void *k;
+} ecc_key;
+
+/** the ECC params provided */
+extern const ltc_ecc_set_type ltc_ecc_sets[];
+
+int ecc_test(void);
+void ecc_sizes(int *low, int *high);
+int ecc_get_size(ecc_key *key);
+
+int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key);
+int ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_set_type *dp);
+void ecc_free(ecc_key *key);
+
+int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key);
+int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
+int ecc_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_set_type *dp);
+
+int ecc_ansi_x963_export(ecc_key *key, unsigned char *out, unsigned long *outlen);
+int ecc_ansi_x963_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
+int ecc_ansi_x963_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, ltc_ecc_set_type *dp);
+
+int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key,
+ unsigned char *out, unsigned long *outlen);
+
+int ecc_encrypt_key(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ prng_state *prng, int wprng, int hash,
+ ecc_key *key);
+
+int ecc_decrypt_key(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ ecc_key *key);
+
+int ecc_sign_hash(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ prng_state *prng, int wprng, ecc_key *key);
+
+int ecc_verify_hash(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int *stat, ecc_key *key);
+
+/* low level functions */
+ecc_point *ltc_ecc_new_point(void);
+void ltc_ecc_del_point(ecc_point *p);
+int ltc_ecc_is_valid_idx(int n);
+
+/* point ops (mp == montgomery digit) */
+#if !defined(LTC_MECC_ACCEL) || defined(LTM_LTC_DESC) || defined(GMP_LTC_DESC)
+/* R = 2P */
+int ltc_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *modulus, void *mp);
+
+/* R = P + Q */
+int ltc_ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *mp);
+#endif
+
+#if defined(LTC_MECC_FP)
+/* optimized point multiplication using fixed point cache (HAC algorithm 14.117) */
+int ltc_ecc_fp_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map);
+
+/* functions for saving/loading/freeing/adding to fixed point cache */
+int ltc_ecc_fp_save_state(unsigned char **out, unsigned long *outlen);
+int ltc_ecc_fp_restore_state(unsigned char *in, unsigned long inlen);
+void ltc_ecc_fp_free(void);
+int ltc_ecc_fp_add_point(ecc_point *g, void *modulus, int lock);
+
+/* lock/unlock all points currently in fixed point cache */
+void ltc_ecc_fp_tablelock(int lock);
+#endif
+
+/* R = kG */
+int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map);
+
+#ifdef LTC_ECC_SHAMIR
+/* kA*A + kB*B = C */
+int ltc_ecc_mul2add(ecc_point *A, void *kA,
+ ecc_point *B, void *kB,
+ ecc_point *C,
+ void *modulus);
+
+#ifdef LTC_MECC_FP
+/* Shamir's trick with optimized point multiplication using fixed point cache */
+int ltc_ecc_fp_mul2add(ecc_point *A, void *kA,
+ ecc_point *B, void *kB,
+ ecc_point *C, void *modulus);
+#endif
+
+#endif
+
+
+/* map P to affine from projective */
+int ltc_ecc_map(ecc_point *P, void *modulus, void *mp);
+
+#endif
+
+#ifdef LTC_MDSA
+
+/* Max diff between group and modulus size in bytes */
+#define LTC_MDSA_DELTA 512
+
+/* Max DSA group size in bytes (default allows 4k-bit groups) */
+#define LTC_MDSA_MAX_GROUP 512
+
+/** DSA key structure */
+typedef struct {
+ /** The key type, PK_PRIVATE or PK_PUBLIC */
+ int type;
+
+ /** The order of the sub-group used in octets */
+ int qord;
+
+ /** The generator */
+ void *g;
+
+ /** The prime used to generate the sub-group */
+ void *q;
+
+ /** The large prime that generats the field the contains the sub-group */
+ void *p;
+
+ /** The private key */
+ void *x;
+
+ /** The public key */
+ void *y;
+} dsa_key;
+
+int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key);
+void dsa_free(dsa_key *key);
+
+int dsa_sign_hash_raw(const unsigned char *in, unsigned long inlen,
+ void *r, void *s,
+ prng_state *prng, int wprng, dsa_key *key);
+
+int dsa_sign_hash(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ prng_state *prng, int wprng, dsa_key *key);
+
+int dsa_verify_hash_raw( void *r, void *s,
+ const unsigned char *hash, unsigned long hashlen,
+ int *stat, dsa_key *key);
+
+int dsa_verify_hash(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int *stat, dsa_key *key);
+
+int dsa_encrypt_key(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ prng_state *prng, int wprng, int hash,
+ dsa_key *key);
+
+int dsa_decrypt_key(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ dsa_key *key);
+
+int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key);
+int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key);
+int dsa_verify_key(dsa_key *key, int *stat);
+
+int dsa_shared_secret(void *private_key, void *base,
+ dsa_key *public_key,
+ unsigned char *out, unsigned long *outlen);
+#endif
+
+#ifdef LTC_DER
+/* DER handling */
+
+enum {
+ LTC_ASN1_EOL,
+ LTC_ASN1_BOOLEAN,
+ LTC_ASN1_INTEGER,
+ LTC_ASN1_SHORT_INTEGER,
+ LTC_ASN1_BIT_STRING,
+ LTC_ASN1_OCTET_STRING,
+ LTC_ASN1_NULL,
+ LTC_ASN1_OBJECT_IDENTIFIER,
+ LTC_ASN1_IA5_STRING,
+ LTC_ASN1_PRINTABLE_STRING,
+ LTC_ASN1_UTF8_STRING,
+ LTC_ASN1_UTCTIME,
+ LTC_ASN1_CHOICE,
+ LTC_ASN1_SEQUENCE,
+ LTC_ASN1_SET,
+ LTC_ASN1_SETOF
+};
+
+/** A LTC ASN.1 list type */
+typedef struct ltc_asn1_list_ {
+ /** The LTC ASN.1 enumerated type identifier */
+ int type;
+ /** The data to encode or place for decoding */
+ void *data;
+ /** The size of the input or resulting output */
+ unsigned long size;
+ /** The used flag, this is used by the CHOICE ASN.1 type to indicate which choice was made */
+ int used;
+ /** prev/next entry in the list */
+ struct ltc_asn1_list_ *prev, *next, *child, *parent;
+} ltc_asn1_list;
+
+#define LTC_SET_ASN1(list, index, Type, Data, Size) \
+ do { \
+ int LTC_MACRO_temp = (index); \
+ ltc_asn1_list *LTC_MACRO_list = (list); \
+ LTC_MACRO_list[LTC_MACRO_temp].type = (Type); \
+ LTC_MACRO_list[LTC_MACRO_temp].data = (void*)(Data); \
+ LTC_MACRO_list[LTC_MACRO_temp].size = (Size); \
+ LTC_MACRO_list[LTC_MACRO_temp].used = 0; \
+ } while (0);
+
+/* SEQUENCE */
+int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen, int type_of);
+
+#define der_encode_sequence(list, inlen, out, outlen) der_encode_sequence_ex(list, inlen, out, outlen, LTC_ASN1_SEQUENCE)
+
+int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen,
+ ltc_asn1_list *list, unsigned long outlen, int ordered);
+
+#define der_decode_sequence(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, 1)
+
+int der_length_sequence(ltc_asn1_list *list, unsigned long inlen,
+ unsigned long *outlen);
+
+/* SET */
+#define der_decode_set(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, 0)
+#define der_length_set der_length_sequence
+int der_encode_set(ltc_asn1_list *list, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+int der_encode_setof(ltc_asn1_list *list, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+/* VA list handy helpers with triplets of <type, size, data> */
+int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...);
+int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...);
+
+/* FLEXI DECODER handle unknown list decoder */
+int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out);
+void der_free_sequence_flexi(ltc_asn1_list *list);
+void der_sequence_free(ltc_asn1_list *in);
+
+/* BOOLEAN */
+int der_length_boolean(unsigned long *outlen);
+int der_encode_boolean(int in,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_boolean(const unsigned char *in, unsigned long inlen,
+ int *out);
+/* INTEGER */
+int der_encode_integer(void *num, unsigned char *out, unsigned long *outlen);
+int der_decode_integer(const unsigned char *in, unsigned long inlen, void *num);
+int der_length_integer(void *num, unsigned long *len);
+
+/* INTEGER -- handy for 0..2^32-1 values */
+int der_decode_short_integer(const unsigned char *in, unsigned long inlen, unsigned long *num);
+int der_encode_short_integer(unsigned long num, unsigned char *out, unsigned long *outlen);
+int der_length_short_integer(unsigned long num, unsigned long *outlen);
+
+/* BIT STRING */
+int der_encode_bit_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_bit_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_length_bit_string(unsigned long nbits, unsigned long *outlen);
+
+/* OCTET STRING */
+int der_encode_octet_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_octet_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_length_octet_string(unsigned long noctets, unsigned long *outlen);
+
+/* OBJECT IDENTIFIER */
+int der_encode_object_identifier(unsigned long *words, unsigned long nwords,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_object_identifier(const unsigned char *in, unsigned long inlen,
+ unsigned long *words, unsigned long *outlen);
+int der_length_object_identifier(unsigned long *words, unsigned long nwords, unsigned long *outlen);
+unsigned long der_object_identifier_bits(unsigned long x);
+
+/* IA5 STRING */
+int der_encode_ia5_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_ia5_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_length_ia5_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen);
+
+int der_ia5_char_encode(int c);
+int der_ia5_value_decode(int v);
+
+/* Printable STRING */
+int der_encode_printable_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_printable_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_length_printable_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen);
+
+int der_printable_char_encode(int c);
+int der_printable_value_decode(int v);
+
+/* UTF-8 */
+#if (defined(SIZE_MAX) || __STDC_VERSION__ >= 199901L || defined(WCHAR_MAX) || defined(_WCHAR_T) || defined(_WCHAR_T_DEFINED) || defined (__WCHAR_TYPE__)) && !defined(LTC_NO_WCHAR)
+#include <wchar.h>
+#else
+typedef ulong32 wchar_t;
+#endif
+
+int der_encode_utf8_string(const wchar_t *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+int der_decode_utf8_string(const unsigned char *in, unsigned long inlen,
+ wchar_t *out, unsigned long *outlen);
+unsigned long der_utf8_charsize(const wchar_t c);
+int der_length_utf8_string(const wchar_t *in, unsigned long noctets, unsigned long *outlen);
+
+
+/* CHOICE */
+int der_decode_choice(const unsigned char *in, unsigned long *inlen,
+ ltc_asn1_list *list, unsigned long outlen);
+
+/* UTCTime */
+typedef struct {
+ unsigned YY, /* year */
+ MM, /* month */
+ DD, /* day */
+ hh, /* hour */
+ mm, /* minute */
+ ss, /* second */
+ off_dir, /* timezone offset direction 0 == +, 1 == - */
+ off_hh, /* timezone offset hours */
+ off_mm; /* timezone offset minutes */
+} ltc_utctime;
+
+int der_encode_utctime(ltc_utctime *utctime,
+ unsigned char *out, unsigned long *outlen);
+
+int der_decode_utctime(const unsigned char *in, unsigned long *inlen,
+ ltc_utctime *out);
+
+int der_length_utctime(ltc_utctime *utctime, unsigned long *outlen);
+
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_pk.h,v $ */
+/* $Revision: 1.81 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_pkcs.h b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_pkcs.h
new file mode 100644
index 00000000000..84fb82a6229
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_pkcs.h
@@ -0,0 +1,89 @@
+/* LTC_PKCS Header Info */
+
+/* ===> LTC_PKCS #1 -- RSA Cryptography <=== */
+#ifdef LTC_PKCS_1
+
+enum ltc_pkcs_1_v1_5_blocks
+{
+ LTC_LTC_PKCS_1_EMSA = 1, /* Block type 1 (LTC_PKCS #1 v1.5 signature padding) */
+ LTC_LTC_PKCS_1_EME = 2 /* Block type 2 (LTC_PKCS #1 v1.5 encryption padding) */
+};
+
+enum ltc_pkcs_1_paddings
+{
+ LTC_LTC_PKCS_1_V1_5 = 1, /* LTC_PKCS #1 v1.5 padding (\sa ltc_pkcs_1_v1_5_blocks) */
+ LTC_LTC_PKCS_1_OAEP = 2, /* LTC_PKCS #1 v2.0 encryption padding */
+ LTC_LTC_PKCS_1_PSS = 3 /* LTC_PKCS #1 v2.1 signature padding */
+};
+
+int pkcs_1_mgf1( int hash_idx,
+ const unsigned char *seed, unsigned long seedlen,
+ unsigned char *mask, unsigned long masklen);
+
+int pkcs_1_i2osp(void *n, unsigned long modulus_len, unsigned char *out);
+int pkcs_1_os2ip(void *n, unsigned char *in, unsigned long inlen);
+
+/* *** v1.5 padding */
+int pkcs_1_v1_5_encode(const unsigned char *msg,
+ unsigned long msglen,
+ int block_type,
+ unsigned long modulus_bitlen,
+ prng_state *prng,
+ int prng_idx,
+ unsigned char *out,
+ unsigned long *outlen);
+
+int pkcs_1_v1_5_decode(const unsigned char *msg,
+ unsigned long msglen,
+ int block_type,
+ unsigned long modulus_bitlen,
+ unsigned char *out,
+ unsigned long *outlen,
+ int *is_valid);
+
+/* *** v2.1 padding */
+int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ unsigned long modulus_bitlen, prng_state *prng,
+ int prng_idx, int hash_idx,
+ unsigned char *out, unsigned long *outlen);
+
+int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ unsigned long modulus_bitlen, int hash_idx,
+ unsigned char *out, unsigned long *outlen,
+ int *res);
+
+int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen,
+ unsigned long saltlen, prng_state *prng,
+ int prng_idx, int hash_idx,
+ unsigned long modulus_bitlen,
+ unsigned char *out, unsigned long *outlen);
+
+int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
+ const unsigned char *sig, unsigned long siglen,
+ unsigned long saltlen, int hash_idx,
+ unsigned long modulus_bitlen, int *res);
+
+#endif /* LTC_PKCS_1 */
+
+/* ===> LTC_PKCS #5 -- Password Based Cryptography <=== */
+#ifdef LTC_PKCS_5
+
+/* Algorithm #1 (old) */
+int pkcs_5_alg1(const unsigned char *password, unsigned long password_len,
+ const unsigned char *salt,
+ int iteration_count, int hash_idx,
+ unsigned char *out, unsigned long *outlen);
+
+/* Algorithm #2 (new) */
+int pkcs_5_alg2(const unsigned char *password, unsigned long password_len,
+ const unsigned char *salt, unsigned long salt_len,
+ int iteration_count, int hash_idx,
+ unsigned char *out, unsigned long *outlen);
+
+#endif /* LTC_PKCS_5 */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_pkcs.h,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_prng.h b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_prng.h
new file mode 100644
index 00000000000..f3e3e550e88
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/headers/tomcrypt_prng.h
@@ -0,0 +1,199 @@
+/* ---- PRNG Stuff ---- */
+#ifdef LTC_YARROW
+struct yarrow_prng {
+ int cipher, hash;
+ unsigned char pool[MAXBLOCKSIZE];
+ symmetric_CTR ctr;
+ LTC_MUTEX_TYPE(prng_lock)
+};
+#endif
+
+#ifdef LTC_RC4
+struct rc4_prng {
+ int x, y;
+ unsigned char buf[256];
+};
+#endif
+
+#ifdef LTC_FORTUNA
+struct fortuna_prng {
+ hash_state pool[LTC_FORTUNA_POOLS]; /* the pools */
+
+ symmetric_key skey;
+
+ unsigned char K[32], /* the current key */
+ IV[16]; /* IV for CTR mode */
+
+ unsigned long pool_idx, /* current pool we will add to */
+ pool0_len, /* length of 0'th pool */
+ wd;
+
+ ulong64 reset_cnt; /* number of times we have reset */
+ LTC_MUTEX_TYPE(prng_lock)
+};
+#endif
+
+#ifdef LTC_SOBER128
+struct sober128_prng {
+ ulong32 R[17], /* Working storage for the shift register */
+ initR[17], /* saved register contents */
+ konst, /* key dependent constant */
+ sbuf; /* partial word encryption buffer */
+
+ int nbuf, /* number of part-word stream bits buffered */
+ flag, /* first add_entropy call or not? */
+ set; /* did we call add_entropy to set key? */
+
+};
+#endif
+
+typedef union Prng_state {
+ char dummy[1];
+#ifdef LTC_YARROW
+ struct yarrow_prng yarrow;
+#endif
+#ifdef LTC_RC4
+ struct rc4_prng rc4;
+#endif
+#ifdef LTC_FORTUNA
+ struct fortuna_prng fortuna;
+#endif
+#ifdef LTC_SOBER128
+ struct sober128_prng sober128;
+#endif
+} prng_state;
+
+/** PRNG descriptor */
+extern struct ltc_prng_descriptor {
+ /** Name of the PRNG */
+ char *name;
+ /** size in bytes of exported state */
+ int export_size;
+ /** Start a PRNG state
+ @param prng [out] The state to initialize
+ @return CRYPT_OK if successful
+ */
+ int (*start)(prng_state *prng);
+ /** Add entropy to the PRNG
+ @param in The entropy
+ @param inlen Length of the entropy (octets)\
+ @param prng The PRNG state
+ @return CRYPT_OK if successful
+ */
+ int (*add_entropy)(const unsigned char *in, unsigned long inlen, prng_state *prng);
+ /** Ready a PRNG state to read from
+ @param prng The PRNG state to ready
+ @return CRYPT_OK if successful
+ */
+ int (*ready)(prng_state *prng);
+ /** Read from the PRNG
+ @param out [out] Where to store the data
+ @param outlen Length of data desired (octets)
+ @param prng The PRNG state to read from
+ @return Number of octets read
+ */
+ unsigned long (*read)(unsigned char *out, unsigned long outlen, prng_state *prng);
+ /** Terminate a PRNG state
+ @param prng The PRNG state to terminate
+ @return CRYPT_OK if successful
+ */
+ int (*done)(prng_state *prng);
+ /** Export a PRNG state
+ @param out [out] The destination for the state
+ @param outlen [in/out] The max size and resulting size of the PRNG state
+ @param prng The PRNG to export
+ @return CRYPT_OK if successful
+ */
+ int (*pexport)(unsigned char *out, unsigned long *outlen, prng_state *prng);
+ /** Import a PRNG state
+ @param in The data to import
+ @param inlen The length of the data to import (octets)
+ @param prng The PRNG to initialize/import
+ @return CRYPT_OK if successful
+ */
+ int (*pimport)(const unsigned char *in, unsigned long inlen, prng_state *prng);
+ /** Self-test the PRNG
+ @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+ */
+ int (*test)(void);
+} prng_descriptor[];
+
+#ifdef LTC_YARROW
+int yarrow_start(prng_state *prng);
+int yarrow_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int yarrow_ready(prng_state *prng);
+unsigned long yarrow_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int yarrow_done(prng_state *prng);
+int yarrow_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int yarrow_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int yarrow_test(void);
+extern const struct ltc_prng_descriptor yarrow_desc;
+#endif
+
+#ifdef LTC_FORTUNA
+int fortuna_start(prng_state *prng);
+int fortuna_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int fortuna_ready(prng_state *prng);
+unsigned long fortuna_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int fortuna_done(prng_state *prng);
+int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int fortuna_test(void);
+extern const struct ltc_prng_descriptor fortuna_desc;
+#endif
+
+#ifdef LTC_RC4
+int rc4_start(prng_state *prng);
+int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int rc4_ready(prng_state *prng);
+unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int rc4_done(prng_state *prng);
+int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int rc4_test(void);
+extern const struct ltc_prng_descriptor rc4_desc;
+#endif
+
+#ifdef LTC_SPRNG
+int sprng_start(prng_state *prng);
+int sprng_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int sprng_ready(prng_state *prng);
+unsigned long sprng_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int sprng_done(prng_state *prng);
+int sprng_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int sprng_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int sprng_test(void);
+extern const struct ltc_prng_descriptor sprng_desc;
+#endif
+
+#ifdef LTC_SOBER128
+int sober128_start(prng_state *prng);
+int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int sober128_ready(prng_state *prng);
+unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int sober128_done(prng_state *prng);
+int sober128_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int sober128_test(void);
+extern const struct ltc_prng_descriptor sober128_desc;
+#endif
+
+int find_prng(const char *name);
+int register_prng(const struct ltc_prng_descriptor *prng);
+int unregister_prng(const struct ltc_prng_descriptor *prng);
+int prng_is_valid(int idx);
+LTC_MUTEX_PROTO(ltc_prng_mutex)
+
+/* Slow RNG you **might** be able to use to seed a PRNG with. Be careful as this
+ * might not work on all platforms as planned
+ */
+unsigned long rng_get_bytes(unsigned char *out,
+ unsigned long outlen,
+ void (*callback)(void));
+
+int rng_make_prng(int bits, int wprng, prng_state *prng, void (*callback)(void));
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_prng.h,v $ */
+/* $Revision: 1.9 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/math/ltm_desc.c b/dep/StormLib/src/libtomcrypt/src/math/ltm_desc.c
new file mode 100644
index 00000000000..25dc0b32279
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/math/ltm_desc.c
@@ -0,0 +1,483 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+#define DESC_DEF_ONLY
+#include "../headers/tomcrypt.h"
+
+#ifdef LTM_DESC
+
+#include "../../../libtommath/tommath.h"
+
+static const struct {
+ int mpi_code, ltc_code;
+} mpi_to_ltc_codes[] = {
+ { MP_OKAY , CRYPT_OK},
+ { MP_MEM , CRYPT_MEM},
+ { MP_VAL , CRYPT_INVALID_ARG},
+};
+
+/**
+ Convert a MPI error to a LTC error (Possibly the most powerful function ever! Oh wait... no)
+ @param err The error to convert
+ @return The equivalent LTC error code or CRYPT_ERROR if none found
+*/
+static int mpi_to_ltc_error(int err)
+{
+ int x;
+
+ for (x = 0; x < (int)(sizeof(mpi_to_ltc_codes)/sizeof(mpi_to_ltc_codes[0])); x++) {
+ if (err == mpi_to_ltc_codes[x].mpi_code) {
+ return mpi_to_ltc_codes[x].ltc_code;
+ }
+ }
+ return CRYPT_ERROR;
+}
+
+static int init(void **a)
+{
+ int err;
+
+ LTC_ARGCHK(a != NULL);
+
+ *a = XCALLOC(1, sizeof(mp_int));
+ if (*a == NULL) {
+ return CRYPT_MEM;
+ }
+
+ if ((err = mpi_to_ltc_error(mp_init(*a))) != CRYPT_OK) {
+ XFREE(*a);
+ }
+ return err;
+}
+
+static void deinit(void *a)
+{
+ LTC_ARGCHKVD(a != NULL);
+ mp_clear(a);
+ XFREE(a);
+}
+
+static int neg(void *a, void *b)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ return mpi_to_ltc_error(mp_neg(a, b));
+}
+
+static int copy(void *a, void *b)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ return mpi_to_ltc_error(mp_copy(a, b));
+}
+
+static int init_copy(void **a, void *b)
+{
+ if (init(a) != CRYPT_OK) {
+ return CRYPT_MEM;
+ }
+ return copy(b, *a);
+}
+
+/* ---- trivial ---- */
+static int set_int(void *a, unsigned long b)
+{
+ LTC_ARGCHK(a != NULL);
+ return mpi_to_ltc_error(mp_set_int(a, b));
+}
+
+static unsigned long get_int(void *a)
+{
+ LTC_ARGCHK(a != NULL);
+ return mp_get_int(a);
+}
+
+static unsigned long get_digit(void *a, int n)
+{
+ mp_int *A;
+ LTC_ARGCHK(a != NULL);
+ A = a;
+ return (n >= A->used || n < 0) ? 0 : A->dp[n];
+}
+
+static int get_digit_count(void *a)
+{
+ mp_int *A;
+ LTC_ARGCHK(a != NULL);
+ A = a;
+ return A->used;
+}
+
+static int compare(void *a, void *b)
+{
+ int ret;
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ ret = mp_cmp(a, b);
+ switch (ret) {
+ case MP_LT: return LTC_MP_LT;
+ case MP_EQ: return LTC_MP_EQ;
+ case MP_GT: return LTC_MP_GT;
+ }
+ return 0;
+}
+
+static int compare_d(void *a, unsigned long b)
+{
+ int ret;
+ LTC_ARGCHK(a != NULL);
+ ret = mp_cmp_d(a, b);
+ switch (ret) {
+ case MP_LT: return LTC_MP_LT;
+ case MP_EQ: return LTC_MP_EQ;
+ case MP_GT: return LTC_MP_GT;
+ }
+ return 0;
+}
+
+static int count_bits(void *a)
+{
+ LTC_ARGCHK(a != NULL);
+ return mp_count_bits(a);
+}
+
+static int count_lsb_bits(void *a)
+{
+ LTC_ARGCHK(a != NULL);
+ return mp_cnt_lsb(a);
+}
+
+
+static int twoexpt(void *a, int n)
+{
+ LTC_ARGCHK(a != NULL);
+ return mpi_to_ltc_error(mp_2expt(a, n));
+}
+
+/* ---- conversions ---- */
+
+/* read ascii string */
+static int read_radix(void *a, const char *b, int radix)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ return mpi_to_ltc_error(mp_read_radix(a, b, radix));
+}
+
+/* write one */
+static int write_radix(void *a, char *b, int radix)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ return mpi_to_ltc_error(mp_toradix(a, b, radix));
+}
+
+/* get size as unsigned char string */
+static unsigned long unsigned_size(void *a)
+{
+ LTC_ARGCHK(a != NULL);
+ return mp_unsigned_bin_size(a);
+}
+
+/* store */
+static int unsigned_write(void *a, unsigned char *b)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ return mpi_to_ltc_error(mp_to_unsigned_bin(a, b));
+}
+
+/* read */
+static int unsigned_read(void *a, unsigned char *b, unsigned long len)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ return mpi_to_ltc_error(mp_read_unsigned_bin(a, b, len));
+}
+
+/* add */
+static int add(void *a, void *b, void *c)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ LTC_ARGCHK(c != NULL);
+ return mpi_to_ltc_error(mp_add(a, b, c));
+}
+
+static int addi(void *a, unsigned long b, void *c)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(c != NULL);
+ return mpi_to_ltc_error(mp_add_d(a, b, c));
+}
+
+/* sub */
+static int sub(void *a, void *b, void *c)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ LTC_ARGCHK(c != NULL);
+ return mpi_to_ltc_error(mp_sub(a, b, c));
+}
+
+static int subi(void *a, unsigned long b, void *c)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(c != NULL);
+ return mpi_to_ltc_error(mp_sub_d(a, b, c));
+}
+
+/* mul */
+static int mul(void *a, void *b, void *c)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ LTC_ARGCHK(c != NULL);
+ return mpi_to_ltc_error(mp_mul(a, b, c));
+}
+
+static int muli(void *a, unsigned long b, void *c)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(c != NULL);
+ return mpi_to_ltc_error(mp_mul_d(a, b, c));
+}
+
+/* sqr */
+static int sqr(void *a, void *b)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ return mpi_to_ltc_error(mp_sqr(a, b));
+}
+
+/* div */
+static int divide(void *a, void *b, void *c, void *d)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ return mpi_to_ltc_error(mp_div(a, b, c, d));
+}
+
+static int div_2(void *a, void *b)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ return mpi_to_ltc_error(mp_div_2(a, b));
+}
+
+/* modi */
+static int modi(void *a, unsigned long b, unsigned long *c)
+{
+ mp_digit tmp;
+ int err;
+
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(c != NULL);
+
+ if ((err = mpi_to_ltc_error(mp_mod_d(a, b, &tmp))) != CRYPT_OK) {
+ return err;
+ }
+ *c = tmp;
+ return CRYPT_OK;
+}
+
+/* gcd */
+static int gcd(void *a, void *b, void *c)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ LTC_ARGCHK(c != NULL);
+ return mpi_to_ltc_error(mp_gcd(a, b, c));
+}
+
+/* lcm */
+static int lcm(void *a, void *b, void *c)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ LTC_ARGCHK(c != NULL);
+ return mpi_to_ltc_error(mp_lcm(a, b, c));
+}
+
+static int mulmod(void *a, void *b, void *c, void *d)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ LTC_ARGCHK(c != NULL);
+ LTC_ARGCHK(d != NULL);
+ return mpi_to_ltc_error(mp_mulmod(a,b,c,d));
+}
+
+static int sqrmod(void *a, void *b, void *c)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ LTC_ARGCHK(c != NULL);
+ return mpi_to_ltc_error(mp_sqrmod(a,b,c));
+}
+
+/* invmod */
+static int invmod(void *a, void *b, void *c)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ LTC_ARGCHK(c != NULL);
+ return mpi_to_ltc_error(mp_invmod(a, b, c));
+}
+
+/* setup */
+static int montgomery_setup(void *a, void **b)
+{
+ int err;
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ *b = XCALLOC(1, sizeof(mp_digit));
+ if (*b == NULL) {
+ return CRYPT_MEM;
+ }
+ if ((err = mpi_to_ltc_error(mp_montgomery_setup(a, (mp_digit *)*b))) != CRYPT_OK) {
+ XFREE(*b);
+ }
+ return err;
+}
+
+/* get normalization value */
+static int montgomery_normalization(void *a, void *b)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ return mpi_to_ltc_error(mp_montgomery_calc_normalization(a, b));
+}
+
+/* reduce */
+static int montgomery_reduce(void *a, void *b, void *c)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ LTC_ARGCHK(c != NULL);
+ return mpi_to_ltc_error(mp_montgomery_reduce(a, b, *((mp_digit *)c)));
+}
+
+/* clean up */
+static void montgomery_deinit(void *a)
+{
+ XFREE(a);
+}
+
+static int exptmod(void *a, void *b, void *c, void *d)
+{
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ LTC_ARGCHK(c != NULL);
+ LTC_ARGCHK(d != NULL);
+ return mpi_to_ltc_error(mp_exptmod(a,b,c,d));
+}
+
+static int isprime(void *a, int *b)
+{
+ int err;
+ LTC_ARGCHK(a != NULL);
+ LTC_ARGCHK(b != NULL);
+ err = mpi_to_ltc_error(mp_prime_is_prime(a, 8, b));
+ *b = (*b == MP_YES) ? LTC_MP_YES : LTC_MP_NO;
+ return err;
+}
+
+const ltc_math_descriptor ltm_desc = {
+
+ "LibTomMath",
+ (int)DIGIT_BIT,
+
+ &init,
+ &init_copy,
+ &deinit,
+
+ &neg,
+ &copy,
+
+ &set_int,
+ &get_int,
+ &get_digit,
+ &get_digit_count,
+ &compare,
+ &compare_d,
+ &count_bits,
+ &count_lsb_bits,
+ &twoexpt,
+
+ &read_radix,
+ &write_radix,
+ &unsigned_size,
+ &unsigned_write,
+ &unsigned_read,
+
+ &add,
+ &addi,
+ &sub,
+ &subi,
+ &mul,
+ &muli,
+ &sqr,
+ &divide,
+ &div_2,
+ &modi,
+ &gcd,
+ &lcm,
+
+ &mulmod,
+ &sqrmod,
+ &invmod,
+
+ &montgomery_setup,
+ &montgomery_normalization,
+ &montgomery_reduce,
+ &montgomery_deinit,
+
+ &exptmod,
+ &isprime,
+
+#ifdef LTC_MECC
+#ifdef LTC_MECC_FP
+ &ltc_ecc_fp_mulmod,
+#else
+ &ltc_ecc_mulmod,
+#endif
+ &ltc_ecc_projective_add_point,
+ &ltc_ecc_projective_dbl_point,
+ &ltc_ecc_map,
+#ifdef LTC_ECC_SHAMIR
+#ifdef LTC_MECC_FP
+ &ltc_ecc_fp_mul2add,
+#else
+ &ltc_ecc_mul2add,
+#endif /* LTC_MECC_FP */
+#else
+ NULL,
+#endif /* LTC_ECC_SHAMIR */
+#else
+ NULL, NULL, NULL, NULL, NULL,
+#endif /* LTC_MECC */
+
+#ifdef LTC_MRSA
+ &rsa_make_key,
+ &rsa_exptmod,
+#else
+ NULL, NULL
+#endif
+};
+
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/math/ltm_desc.c,v $ */
+/* $Revision: 1.31 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/math/multi.c b/dep/StormLib/src/libtomcrypt/src/math/multi.c
new file mode 100644
index 00000000000..7d40040a1de
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/math/multi.c
@@ -0,0 +1,61 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+#ifdef MPI
+#include <stdarg.h>
+
+int ltc_init_multi(void **a, ...)
+{
+ void **cur = a;
+ int np = 0;
+ va_list args;
+
+ va_start(args, a);
+ while (cur != NULL) {
+ if (mp_init(cur) != CRYPT_OK) {
+ /* failed */
+ va_list clean_list;
+
+ va_start(clean_list, a);
+ cur = a;
+ while (np--) {
+ mp_clear(*cur);
+ cur = va_arg(clean_list, void**);
+ }
+ va_end(clean_list);
+ return CRYPT_MEM;
+ }
+ ++np;
+ cur = va_arg(args, void**);
+ }
+ va_end(args);
+ return CRYPT_OK;
+}
+
+void ltc_deinit_multi(void *a, ...)
+{
+ void *cur = a;
+ va_list args;
+
+ va_start(args, a);
+ while (cur != NULL) {
+ mp_clear(cur);
+ cur = va_arg(args, void *);
+ }
+ va_end(args);
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/math/multi.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:27:23 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/math/rand_prime.c b/dep/StormLib/src/libtomcrypt/src/math/rand_prime.c
new file mode 100644
index 00000000000..913fa95a4a3
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/math/rand_prime.c
@@ -0,0 +1,87 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+/**
+ @file rand_prime.c
+ Generate a random prime, Tom St Denis
+*/
+
+#define USE_BBS 1
+
+int rand_prime(void *N, long len, prng_state *prng, int wprng)
+{
+ int err, res, type;
+ unsigned char *buf;
+
+ LTC_ARGCHK(N != NULL);
+
+ /* get type */
+ if (len < 0) {
+ type = USE_BBS;
+ len = -len;
+ } else {
+ type = 0;
+ }
+
+ /* allow sizes between 2 and 512 bytes for a prime size */
+ if (len < 2 || len > 512) {
+ return CRYPT_INVALID_PRIME_SIZE;
+ }
+
+ /* valid PRNG? Better be! */
+ if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+ return err;
+ }
+
+ /* allocate buffer to work with */
+ buf = XCALLOC(1, len);
+ if (buf == NULL) {
+ return CRYPT_MEM;
+ }
+
+ do {
+ /* generate value */
+ if (prng_descriptor[wprng].read(buf, len, prng) != (unsigned long)len) {
+ XFREE(buf);
+ return CRYPT_ERROR_READPRNG;
+ }
+
+ /* munge bits */
+ buf[0] |= 0x80 | 0x40;
+ buf[len-1] |= 0x01 | ((type & USE_BBS) ? 0x02 : 0x00);
+
+ /* load value */
+ if ((err = mp_read_unsigned_bin(N, buf, len)) != CRYPT_OK) {
+ XFREE(buf);
+ return err;
+ }
+
+ /* test */
+ if ((err = mp_prime_is_prime(N, 8, &res)) != CRYPT_OK) {
+ XFREE(buf);
+ return err;
+ }
+ } while (res == LTC_MP_NO);
+
+#ifdef LTC_CLEAN_STACK
+ zeromem(buf, len);
+#endif
+
+ XFREE(buf);
+ return CRYPT_OK;
+}
+
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/math/rand_prime.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2006/12/28 01:27:23 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/misc/base64_decode.c b/dep/StormLib/src/libtomcrypt/src/misc/base64_decode.c
new file mode 100644
index 00000000000..3d13393a1dc
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/misc/base64_decode.c
@@ -0,0 +1,104 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+/**
+ @file base64_decode.c
+ Compliant base64 code donated by Wayne Scott (wscott@bitmover.com)
+*/
+
+
+#ifdef LTC_BASE64
+
+static const unsigned char map[256] = {
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
+255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
+255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255 };
+
+/**
+ base64 decode a block of memory
+ @param in The base64 data to decode
+ @param inlen The length of the base64 data
+ @param out [out] The destination of the binary decoded data
+ @param outlen [in/out] The max size and resulting size of the decoded data
+ @return CRYPT_OK if successful
+*/
+int base64_decode(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long t, x, y, z;
+ unsigned char c;
+ int g;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ g = 3;
+ for (x = y = z = t = 0; x < inlen; x++) {
+ c = map[in[x]&0xFF];
+ if (c == 255) continue;
+ /* the final = symbols are read and used to trim the remaining bytes */
+ if (c == 254) {
+ c = 0;
+ /* prevent g < 0 which would potentially allow an overflow later */
+ if (--g < 0) {
+ return CRYPT_INVALID_PACKET;
+ }
+ } else if (g != 3) {
+ /* we only allow = to be at the end */
+ return CRYPT_INVALID_PACKET;
+ }
+
+ t = (t<<6)|c;
+
+ if (++y == 4) {
+ if (z + g > *outlen) {
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+ out[z++] = (unsigned char)((t>>16)&255);
+ if (g > 1) out[z++] = (unsigned char)((t>>8)&255);
+ if (g > 2) out[z++] = (unsigned char)(t&255);
+ y = t = 0;
+ }
+ }
+ if (y != 0) {
+ return CRYPT_INVALID_PACKET;
+ }
+ *outlen = z;
+ return CRYPT_OK;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/base64/base64_decode.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/misc/crypt_argchk.c b/dep/StormLib/src/libtomcrypt/src/misc/crypt_argchk.c
new file mode 100644
index 00000000000..537516d80d9
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/misc/crypt_argchk.c
@@ -0,0 +1,30 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+#include <signal.h>
+
+/**
+ @file crypt_argchk.c
+ Perform argument checking, Tom St Denis
+*/
+
+#if (ARGTYPE == 0)
+void crypt_argchk(char *v, char *s, int d)
+{
+ fprintf(stderr, "LTC_ARGCHK '%s' failure on line %d of file %s\n",
+ v, d, s);
+ (void)raise(SIGABRT);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_argchk.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/misc/crypt_find_hash.c b/dep/StormLib/src/libtomcrypt/src/misc/crypt_find_hash.c
new file mode 100644
index 00000000000..fef2d8cca32
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/misc/crypt_find_hash.c
@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+/**
+ @file crypt_find_hash.c
+ Find a hash, Tom St Denis
+*/
+
+/**
+ Find a registered hash by name
+ @param name The name of the hash to look for
+ @return >= 0 if found, -1 if not present
+*/
+int find_hash(const char *name)
+{
+ int x;
+ LTC_ARGCHK(name != NULL);
+ LTC_MUTEX_LOCK(&ltc_hash_mutex);
+ for (x = 0; x < TAB_SIZE; x++) {
+ if (hash_descriptor[x].name != NULL && XSTRCMP(hash_descriptor[x].name, name) == 0) {
+ LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+ return x;
+ }
+ }
+ LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+ return -1;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_find_hash.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/misc/crypt_find_prng.c b/dep/StormLib/src/libtomcrypt/src/misc/crypt_find_prng.c
new file mode 100644
index 00000000000..fafbb0e226f
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/misc/crypt_find_prng.c
@@ -0,0 +1,41 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+/**
+ @file crypt_find_prng.c
+ Find a PRNG, Tom St Denis
+*/
+
+/**
+ Find a registered PRNG by name
+ @param name The name of the PRNG to look for
+ @return >= 0 if found, -1 if not present
+*/
+int find_prng(const char *name)
+{
+ int x;
+ LTC_ARGCHK(name != NULL);
+ LTC_MUTEX_LOCK(&ltc_prng_mutex);
+ for (x = 0; x < TAB_SIZE; x++) {
+ if ((prng_descriptor[x].name != NULL) && XSTRCMP(prng_descriptor[x].name, name) == 0) {
+ LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+ return x;
+ }
+ }
+ LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+ return -1;
+}
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_find_prng.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/misc/crypt_hash_descriptor.c b/dep/StormLib/src/libtomcrypt/src/misc/crypt_hash_descriptor.c
new file mode 100644
index 00000000000..5925fd27302
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/misc/crypt_hash_descriptor.c
@@ -0,0 +1,27 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+/**
+ @file crypt_hash_descriptor.c
+ Stores the hash descriptor table, Tom St Denis
+*/
+
+struct ltc_hash_descriptor hash_descriptor[TAB_SIZE] = {
+{ NULL, 0, 0, 0, { 0 }, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+LTC_MUTEX_GLOBAL(ltc_hash_mutex)
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_hash_descriptor.c,v $ */
+/* $Revision: 1.10 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/misc/crypt_hash_is_valid.c b/dep/StormLib/src/libtomcrypt/src/misc/crypt_hash_is_valid.c
new file mode 100644
index 00000000000..8ed5105b56c
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/misc/crypt_hash_is_valid.c
@@ -0,0 +1,36 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+/**
+ @file crypt_hash_is_valid.c
+ Determine if hash is valid, Tom St Denis
+*/
+
+/*
+ Test if a hash index is valid
+ @param idx The index of the hash to search for
+ @return CRYPT_OK if valid
+*/
+int hash_is_valid(int idx)
+{
+ LTC_MUTEX_LOCK(&ltc_hash_mutex);
+ if (idx < 0 || idx >= TAB_SIZE || hash_descriptor[idx].name == NULL) {
+ LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+ return CRYPT_INVALID_HASH;
+ }
+ LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+ return CRYPT_OK;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_hash_is_valid.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/misc/crypt_libc.c b/dep/StormLib/src/libtomcrypt/src/misc/crypt_libc.c
new file mode 100644
index 00000000000..bcc89f4f94d
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/misc/crypt_libc.c
@@ -0,0 +1,43 @@
+/*****************************************************************************/
+/* crypt_libc.c Copyright (c) Ladislav Zezula 2010 */
+/*---------------------------------------------------------------------------*/
+/* Description: */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 05.05.10 1.00 Lad The first version of crypt_libc.c */
+/*****************************************************************************/
+
+// LibTomCrypt header
+#include <stdlib.h>
+#include "../headers/tomcrypt.h"
+
+void * LibTomMalloc(size_t n)
+{
+ return malloc(n);
+}
+
+void * LibTomCalloc(size_t n, size_t s)
+{
+ return calloc(n, s);
+}
+
+void * LibTomRealloc(void *p, size_t n)
+{
+ return realloc(p, n);
+}
+
+void LibTomFree(void * p)
+{
+ free(p);
+}
+
+clock_t LibTomClock(void)
+{
+ return clock();
+}
+
+void LibTomQsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *))
+{
+ qsort(base, nmemb, size, compar);
+}
diff --git a/dep/StormLib/src/libtomcrypt/src/misc/crypt_ltc_mp_descriptor.c b/dep/StormLib/src/libtomcrypt/src/misc/crypt_ltc_mp_descriptor.c
new file mode 100644
index 00000000000..91ba9d162d2
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/misc/crypt_ltc_mp_descriptor.c
@@ -0,0 +1,13 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+ltc_math_descriptor ltc_mp;
diff --git a/dep/StormLib/src/libtomcrypt/src/misc/crypt_prng_descriptor.c b/dep/StormLib/src/libtomcrypt/src/misc/crypt_prng_descriptor.c
new file mode 100644
index 00000000000..c5b39e0c26f
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/misc/crypt_prng_descriptor.c
@@ -0,0 +1,26 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+/**
+ @file crypt_prng_descriptor.c
+ Stores the PRNG descriptors, Tom St Denis
+*/
+struct ltc_prng_descriptor prng_descriptor[TAB_SIZE] = {
+{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+LTC_MUTEX_GLOBAL(ltc_prng_mutex)
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_prng_descriptor.c,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/misc/crypt_prng_is_valid.c b/dep/StormLib/src/libtomcrypt/src/misc/crypt_prng_is_valid.c
new file mode 100644
index 00000000000..d38fd3a3c9d
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/misc/crypt_prng_is_valid.c
@@ -0,0 +1,36 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+/**
+ @file crypt_prng_is_valid.c
+ Determine if PRNG is valid, Tom St Denis
+*/
+
+/*
+ Test if a PRNG index is valid
+ @param idx The index of the PRNG to search for
+ @return CRYPT_OK if valid
+*/
+int prng_is_valid(int idx)
+{
+ LTC_MUTEX_LOCK(&ltc_prng_mutex);
+ if (idx < 0 || idx >= TAB_SIZE || prng_descriptor[idx].name == NULL) {
+ LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+ return CRYPT_INVALID_PRNG;
+ }
+ LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+ return CRYPT_OK;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_prng_is_valid.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/misc/crypt_register_hash.c b/dep/StormLib/src/libtomcrypt/src/misc/crypt_register_hash.c
new file mode 100644
index 00000000000..17300915487
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/misc/crypt_register_hash.c
@@ -0,0 +1,54 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+/**
+ @file crypt_register_hash.c
+ Register a HASH, Tom St Denis
+*/
+
+/**
+ Register a hash with the descriptor table
+ @param hash The hash you wish to register
+ @return value >= 0 if successfully added (or already present), -1 if unsuccessful
+*/
+int register_hash(const struct ltc_hash_descriptor *hash)
+{
+ int x;
+
+ LTC_ARGCHK(hash != NULL);
+
+ /* is it already registered? */
+ LTC_MUTEX_LOCK(&ltc_hash_mutex);
+ for (x = 0; x < TAB_SIZE; x++) {
+ if (XMEMCMP(&hash_descriptor[x], hash, sizeof(struct ltc_hash_descriptor)) == 0) {
+ LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+ return x;
+ }
+ }
+
+ /* find a blank spot */
+ for (x = 0; x < TAB_SIZE; x++) {
+ if (hash_descriptor[x].name == NULL) {
+ XMEMCPY(&hash_descriptor[x], hash, sizeof(struct ltc_hash_descriptor));
+ LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+ return x;
+ }
+ }
+
+ /* no spot */
+ LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+ return -1;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_register_hash.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/misc/crypt_register_prng.c b/dep/StormLib/src/libtomcrypt/src/misc/crypt_register_prng.c
new file mode 100644
index 00000000000..29fc9bdf63d
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/misc/crypt_register_prng.c
@@ -0,0 +1,54 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+/**
+ @file crypt_register_prng.c
+ Register a PRNG, Tom St Denis
+*/
+
+/**
+ Register a PRNG with the descriptor table
+ @param prng The PRNG you wish to register
+ @return value >= 0 if successfully added (or already present), -1 if unsuccessful
+*/
+int register_prng(const struct ltc_prng_descriptor *prng)
+{
+ int x;
+
+ LTC_ARGCHK(prng != NULL);
+
+ /* is it already registered? */
+ LTC_MUTEX_LOCK(&ltc_prng_mutex);
+ for (x = 0; x < TAB_SIZE; x++) {
+ if (XMEMCMP(&prng_descriptor[x], prng, sizeof(struct ltc_prng_descriptor)) == 0) {
+ LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+ return x;
+ }
+ }
+
+ /* find a blank spot */
+ for (x = 0; x < TAB_SIZE; x++) {
+ if (prng_descriptor[x].name == NULL) {
+ XMEMCPY(&prng_descriptor[x], prng, sizeof(struct ltc_prng_descriptor));
+ LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+ return x;
+ }
+ }
+
+ /* no spot */
+ LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+ return -1;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_register_prng.c,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/misc/zeromem.c b/dep/StormLib/src/libtomcrypt/src/misc/zeromem.c
new file mode 100644
index 00000000000..faa0efa7842
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/misc/zeromem.c
@@ -0,0 +1,34 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../headers/tomcrypt.h"
+
+/**
+ @file zeromem.c
+ Zero a block of memory, Tom St Denis
+*/
+
+/**
+ Zero a block of memory
+ @param out The destination of the area to zero
+ @param outlen The length of the area to zero (octets)
+*/
+void zeromem(void *out, size_t outlen)
+{
+ unsigned char *mem = out;
+ LTC_ARGCHKVD(out != NULL);
+ while (outlen-- > 0) {
+ *mem++ = 0;
+ }
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/zeromem.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_bit_string.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_bit_string.c
new file mode 100644
index 00000000000..e53686750fd
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_bit_string.c
@@ -0,0 +1,102 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_decode_bit_string.c
+ ASN.1 DER, encode a BIT STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Store a BIT STRING
+ @param in The DER encoded BIT STRING
+ @param inlen The size of the DER BIT STRING
+ @param out [out] The array of bits stored (one per char)
+ @param outlen [in/out] The number of bits stored
+ @return CRYPT_OK if successful
+*/
+int der_decode_bit_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long dlen, blen, x, y;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* packet must be at least 4 bytes */
+ if (inlen < 4) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* check for 0x03 */
+ if ((in[0]&0x1F) != 0x03) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* offset in the data */
+ x = 1;
+
+ /* get the length of the data */
+ if (in[x] & 0x80) {
+ /* long format get number of length bytes */
+ y = in[x++] & 0x7F;
+
+ /* invalid if 0 or > 2 */
+ if (y == 0 || y > 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the data len */
+ dlen = 0;
+ while (y--) {
+ dlen = (dlen << 8) | (unsigned long)in[x++];
+ }
+ } else {
+ /* short format */
+ dlen = in[x++] & 0x7F;
+ }
+
+ /* is the data len too long or too short? */
+ if ((dlen == 0) || (dlen + x > inlen)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* get padding count */
+ blen = ((dlen - 1) << 3) - (in[x++] & 7);
+
+ /* too many bits? */
+ if (blen > *outlen) {
+ *outlen = blen;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ /* decode/store the bits */
+ for (y = 0; y < blen; y++) {
+ out[y] = (in[x] & (1 << (7 - (y & 7)))) ? 1 : 0;
+ if ((y & 7) == 7) {
+ ++x;
+ }
+ }
+
+ /* we done */
+ *outlen = blen;
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/bit/der_decode_bit_string.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_boolean.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_boolean.c
new file mode 100644
index 00000000000..617d4e8611d
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_boolean.c
@@ -0,0 +1,47 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_decode_boolean.c
+ ASN.1 DER, decode a BOOLEAN, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Read a BOOLEAN
+ @param in The destination for the DER encoded BOOLEAN
+ @param inlen The size of the DER BOOLEAN
+ @param out [out] The boolean to decode
+ @return CRYPT_OK if successful
+*/
+int der_decode_boolean(const unsigned char *in, unsigned long inlen,
+ int *out)
+{
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+
+ if (inlen != 3 || in[0] != 0x01 || in[1] != 0x01 || (in[2] != 0x00 && in[2] != 0xFF)) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ *out = (in[2]==0xFF) ? 1 : 0;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/boolean/der_decode_boolean.c,v $ */
+/* $Revision: 1.2 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_choice.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_choice.c
new file mode 100644
index 00000000000..44a0891bead
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_choice.c
@@ -0,0 +1,182 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_decode_choice.c
+ ASN.1 DER, decode a CHOICE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Decode a CHOICE
+ @param in The DER encoded input
+ @param inlen [in/out] The size of the input and resulting size of read type
+ @param list The list of items to decode
+ @param outlen The number of items in the list
+ @return CRYPT_OK on success
+*/
+int der_decode_choice(const unsigned char *in, unsigned long *inlen,
+ ltc_asn1_list *list, unsigned long outlen)
+{
+ unsigned long size, x, z;
+ void *data;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(inlen != NULL);
+ LTC_ARGCHK(list != NULL);
+
+ /* get blk size */
+ if (*inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* set all of the "used" flags to zero */
+ for (x = 0; x < outlen; x++) {
+ list[x].used = 0;
+ }
+
+ /* now scan until we have a winner */
+ for (x = 0; x < outlen; x++) {
+ size = list[x].size;
+ data = list[x].data;
+
+ switch (list[x].type) {
+ case LTC_ASN1_INTEGER:
+ if (der_decode_integer(in, *inlen, data) == CRYPT_OK) {
+ if (der_length_integer(data, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ case LTC_ASN1_SHORT_INTEGER:
+ if (der_decode_short_integer(in, *inlen, data) == CRYPT_OK) {
+ if (der_length_short_integer(size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ case LTC_ASN1_BIT_STRING:
+ if (der_decode_bit_string(in, *inlen, data, &size) == CRYPT_OK) {
+ if (der_length_bit_string(size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ list[x].size = size;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ case LTC_ASN1_OCTET_STRING:
+ if (der_decode_octet_string(in, *inlen, data, &size) == CRYPT_OK) {
+ if (der_length_octet_string(size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ list[x].size = size;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ case LTC_ASN1_NULL:
+ if (*inlen == 2 && in[x] == 0x05 && in[x+1] == 0x00) {
+ *inlen = 2;
+ list[x].used = 1;
+ return CRYPT_OK;
+ }
+ break;
+
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ if (der_decode_object_identifier(in, *inlen, data, &size) == CRYPT_OK) {
+ if (der_length_object_identifier(data, size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ list[x].size = size;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ case LTC_ASN1_IA5_STRING:
+ if (der_decode_ia5_string(in, *inlen, data, &size) == CRYPT_OK) {
+ if (der_length_ia5_string(data, size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ list[x].size = size;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+
+ case LTC_ASN1_PRINTABLE_STRING:
+ if (der_decode_printable_string(in, *inlen, data, &size) == CRYPT_OK) {
+ if (der_length_printable_string(data, size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ list[x].size = size;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ case LTC_ASN1_UTF8_STRING:
+ if (der_decode_utf8_string(in, *inlen, data, &size) == CRYPT_OK) {
+ if (der_length_utf8_string(data, size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ list[x].size = size;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ case LTC_ASN1_UTCTIME:
+ z = *inlen;
+ if (der_decode_utctime(in, &z, data) == CRYPT_OK) {
+ list[x].used = 1;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ break;
+
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_SEQUENCE:
+ if (der_decode_sequence(in, *inlen, data, size) == CRYPT_OK) {
+ if (der_length_sequence(data, size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ default:
+ return CRYPT_INVALID_ARG;
+ }
+ }
+
+ return CRYPT_INVALID_PACKET;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/choice/der_decode_choice.c,v $ */
+/* $Revision: 1.9 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_ia5_string.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_ia5_string.c
new file mode 100644
index 00000000000..f2e073b8d84
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_ia5_string.c
@@ -0,0 +1,96 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_decode_ia5_string.c
+ ASN.1 DER, encode a IA5 STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Store a IA5 STRING
+ @param in The DER encoded IA5 STRING
+ @param inlen The size of the DER IA5 STRING
+ @param out [out] The array of octets stored (one per char)
+ @param outlen [in/out] The number of octets stored
+ @return CRYPT_OK if successful
+*/
+int der_decode_ia5_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long x, y, len;
+ int t;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* must have header at least */
+ if (inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* check for 0x16 */
+ if ((in[0] & 0x1F) != 0x16) {
+ return CRYPT_INVALID_PACKET;
+ }
+ x = 1;
+
+ /* decode the length */
+ if (in[x] & 0x80) {
+ /* valid # of bytes in length are 1,2,3 */
+ y = in[x] & 0x7F;
+ if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the length in */
+ len = 0;
+ ++x;
+ while (y--) {
+ len = (len << 8) | in[x++];
+ }
+ } else {
+ len = in[x++] & 0x7F;
+ }
+
+ /* is it too long? */
+ if (len > *outlen) {
+ *outlen = len;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ if (len + x > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the data */
+ for (y = 0; y < len; y++) {
+ t = der_ia5_value_decode(in[x++]);
+ if (t == -1) {
+ return CRYPT_INVALID_ARG;
+ }
+ out[y] = t;
+ }
+
+ *outlen = y;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/ia5/der_decode_ia5_string.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_integer.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_integer.c
new file mode 100644
index 00000000000..cca27451963
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_integer.c
@@ -0,0 +1,110 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_decode_integer.c
+ ASN.1 DER, decode an integer, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Read a mp_int integer
+ @param in The DER encoded data
+ @param inlen Size of DER encoded data
+ @param num The first mp_int to decode
+ @return CRYPT_OK if successful
+*/
+int der_decode_integer(const unsigned char *in, unsigned long inlen, void *num)
+{
+ unsigned long x, y, z;
+ int err;
+
+ LTC_ARGCHK(num != NULL);
+ LTC_ARGCHK(in != NULL);
+
+ /* min DER INTEGER is 0x02 01 00 == 0 */
+ if (inlen < (1 + 1 + 1)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* ok expect 0x02 when we AND with 0001 1111 [1F] */
+ x = 0;
+ if ((in[x++] & 0x1F) != 0x02) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* now decode the len stuff */
+ z = in[x++];
+
+ if ((z & 0x80) == 0x00) {
+ /* short form */
+
+ /* will it overflow? */
+ if (x + z > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* no so read it */
+ if ((err = mp_read_unsigned_bin(num, (unsigned char *)in + x, z)) != CRYPT_OK) {
+ return err;
+ }
+ } else {
+ /* long form */
+ z &= 0x7F;
+
+ /* will number of length bytes overflow? (or > 4) */
+ if (((x + z) > inlen) || (z > 4) || (z == 0)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* now read it in */
+ y = 0;
+ while (z--) {
+ y = ((unsigned long)(in[x++])) | (y << 8);
+ }
+
+ /* now will reading y bytes overrun? */
+ if ((x + y) > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* no so read it */
+ if ((err = mp_read_unsigned_bin(num, (unsigned char *)in + x, y)) != CRYPT_OK) {
+ return err;
+ }
+ }
+
+ /* see if it's negative */
+ if (in[x] & 0x80) {
+ void *tmp;
+ if (mp_init(&tmp) != CRYPT_OK) {
+ return CRYPT_MEM;
+ }
+
+ if (mp_2expt(tmp, mp_count_bits(num)) != CRYPT_OK || mp_sub(num, tmp, num) != CRYPT_OK) {
+ mp_clear(tmp);
+ return CRYPT_MEM;
+ }
+ mp_clear(tmp);
+ }
+
+ return CRYPT_OK;
+
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/integer/der_decode_integer.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_object_identifier.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_object_identifier.c
new file mode 100644
index 00000000000..e7baae88e0c
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_object_identifier.c
@@ -0,0 +1,99 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_decode_object_identifier.c
+ ASN.1 DER, Decode Object Identifier, Tom St Denis
+*/
+
+#ifdef LTC_DER
+/**
+ Decode OID data and store the array of integers in words
+ @param in The OID DER encoded data
+ @param inlen The length of the OID data
+ @param words [out] The destination of the OID words
+ @param outlen [in/out] The number of OID words
+ @return CRYPT_OK if successful
+*/
+int der_decode_object_identifier(const unsigned char *in, unsigned long inlen,
+ unsigned long *words, unsigned long *outlen)
+{
+ unsigned long x, y, t, len;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(words != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* header is at least 3 bytes */
+ if (inlen < 3) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* must be room for at least two words */
+ if (*outlen < 2) {
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ /* decode the packet header */
+ x = 0;
+ if ((in[x++] & 0x1F) != 0x06) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* get the length */
+ if (in[x] < 128) {
+ len = in[x++];
+ } else {
+ if (in[x] < 0x81 || in[x] > 0x82) {
+ return CRYPT_INVALID_PACKET;
+ }
+ y = in[x++] & 0x7F;
+ len = 0;
+ while (y--) {
+ len = (len << 8) | (unsigned long)in[x++];
+ }
+ }
+
+ if (len < 1 || (len + x) > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* decode words */
+ y = 0;
+ t = 0;
+ while (len--) {
+ t = (t << 7) | (in[x] & 0x7F);
+ if (!(in[x++] & 0x80)) {
+ /* store t */
+ if (y >= *outlen) {
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+ if (y == 0) {
+ words[0] = t / 40;
+ words[1] = t % 40;
+ y = 2;
+ } else {
+ words[y++] = t;
+ }
+ t = 0;
+ }
+ }
+
+ *outlen = y;
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_octet_string.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_octet_string.c
new file mode 100644
index 00000000000..523d0baa057
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_octet_string.c
@@ -0,0 +1,91 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_decode_octet_string.c
+ ASN.1 DER, encode a OCTET STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Store a OCTET STRING
+ @param in The DER encoded OCTET STRING
+ @param inlen The size of the DER OCTET STRING
+ @param out [out] The array of octets stored (one per char)
+ @param outlen [in/out] The number of octets stored
+ @return CRYPT_OK if successful
+*/
+int der_decode_octet_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long x, y, len;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* must have header at least */
+ if (inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* check for 0x04 */
+ if ((in[0] & 0x1F) != 0x04) {
+ return CRYPT_INVALID_PACKET;
+ }
+ x = 1;
+
+ /* decode the length */
+ if (in[x] & 0x80) {
+ /* valid # of bytes in length are 1,2,3 */
+ y = in[x] & 0x7F;
+ if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the length in */
+ len = 0;
+ ++x;
+ while (y--) {
+ len = (len << 8) | in[x++];
+ }
+ } else {
+ len = in[x++] & 0x7F;
+ }
+
+ /* is it too long? */
+ if (len > *outlen) {
+ *outlen = len;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ if (len + x > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the data */
+ for (y = 0; y < len; y++) {
+ out[y] = in[x++];
+ }
+
+ *outlen = y;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/octet/der_decode_octet_string.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_printable_string.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_printable_string.c
new file mode 100644
index 00000000000..f8325934395
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_printable_string.c
@@ -0,0 +1,96 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_decode_printable_string.c
+ ASN.1 DER, encode a printable STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Store a printable STRING
+ @param in The DER encoded printable STRING
+ @param inlen The size of the DER printable STRING
+ @param out [out] The array of octets stored (one per char)
+ @param outlen [in/out] The number of octets stored
+ @return CRYPT_OK if successful
+*/
+int der_decode_printable_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long x, y, len;
+ int t;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* must have header at least */
+ if (inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* check for 0x13 */
+ if ((in[0] & 0x1F) != 0x13) {
+ return CRYPT_INVALID_PACKET;
+ }
+ x = 1;
+
+ /* decode the length */
+ if (in[x] & 0x80) {
+ /* valid # of bytes in length are 1,2,3 */
+ y = in[x] & 0x7F;
+ if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the length in */
+ len = 0;
+ ++x;
+ while (y--) {
+ len = (len << 8) | in[x++];
+ }
+ } else {
+ len = in[x++] & 0x7F;
+ }
+
+ /* is it too long? */
+ if (len > *outlen) {
+ *outlen = len;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ if (len + x > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the data */
+ for (y = 0; y < len; y++) {
+ t = der_printable_value_decode(in[x++]);
+ if (t == -1) {
+ return CRYPT_INVALID_ARG;
+ }
+ out[y] = t;
+ }
+
+ *outlen = y;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/printable_string/der_decode_printable_string.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_ex.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_ex.c
new file mode 100644
index 00000000000..9b00f61b09a
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_ex.c
@@ -0,0 +1,287 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+#include <stdarg.h>
+
+
+/**
+ @file der_decode_sequence_ex.c
+ ASN.1 DER, decode a SEQUENCE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Decode a SEQUENCE
+ @param in The DER encoded input
+ @param inlen The size of the input
+ @param list The list of items to decode
+ @param outlen The number of items in the list
+ @param ordered Search an unordeded or ordered list
+ @return CRYPT_OK on success
+*/
+int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen,
+ ltc_asn1_list *list, unsigned long outlen, int ordered)
+{
+ int err, type;
+ unsigned long size, x, y, z, i, blksize;
+ void *data;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(list != NULL);
+
+ /* get blk size */
+ if (inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* sequence type? We allow 0x30 SEQUENCE and 0x31 SET since fundamentally they're the same structure */
+ x = 0;
+ if (in[x] != 0x30 && in[x] != 0x31) {
+ return CRYPT_INVALID_PACKET;
+ }
+ ++x;
+
+ if (in[x] < 128) {
+ blksize = in[x++];
+ } else if (in[x] & 0x80) {
+ if (in[x] < 0x81 || in[x] > 0x83) {
+ return CRYPT_INVALID_PACKET;
+ }
+ y = in[x++] & 0x7F;
+
+ /* would reading the len bytes overrun? */
+ if (x + y > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read len */
+ blksize = 0;
+ while (y--) {
+ blksize = (blksize << 8) | (unsigned long)in[x++];
+ }
+ }
+
+ /* would this blksize overflow? */
+ if (x + blksize > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* mark all as unused */
+ for (i = 0; i < outlen; i++) {
+ list[i].used = 0;
+ }
+
+ /* ok read data */
+ inlen = blksize;
+ for (i = 0; i < outlen; i++) {
+ z = 0;
+ type = list[i].type;
+ size = list[i].size;
+ data = list[i].data;
+ if (!ordered && list[i].used == 1) { continue; }
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ z = inlen;
+ if ((err = der_decode_boolean(in + x, z, ((int *)data))) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ if ((err = der_length_boolean(&z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_INTEGER:
+ z = inlen;
+ if ((err = der_decode_integer(in + x, z, data)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ if ((err = der_length_integer(data, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_SHORT_INTEGER:
+ z = inlen;
+ if ((err = der_decode_short_integer(in + x, z, data)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ if ((err = der_length_short_integer(((unsigned long*)data)[0], &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ break;
+
+ case LTC_ASN1_BIT_STRING:
+ z = inlen;
+ if ((err = der_decode_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_OCTET_STRING:
+ z = inlen;
+ if ((err = der_decode_octet_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_octet_string(size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_NULL:
+ if (inlen < 2 || in[x] != 0x05 || in[x+1] != 0x00) {
+ if (!ordered) { continue; }
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+ z = 2;
+ break;
+
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ z = inlen;
+ if ((err = der_decode_object_identifier(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_object_identifier(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_IA5_STRING:
+ z = inlen;
+ if ((err = der_decode_ia5_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_ia5_string(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+
+ case LTC_ASN1_PRINTABLE_STRING:
+ z = inlen;
+ if ((err = der_decode_printable_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_printable_string(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_UTF8_STRING:
+ z = inlen;
+ if ((err = der_decode_utf8_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_utf8_string(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_UTCTIME:
+ z = inlen;
+ if ((err = der_decode_utctime(in + x, &z, data)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_SET:
+ z = inlen;
+ if ((err = der_decode_set(in + x, z, data, size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_SEQUENCE:
+ /* detect if we have the right type */
+ if ((type == LTC_ASN1_SETOF && (in[x] & 0x3F) != 0x31) || (type == LTC_ASN1_SEQUENCE && (in[x] & 0x3F) != 0x30)) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+
+ z = inlen;
+ if ((err = der_decode_sequence(in + x, z, data, size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+
+ case LTC_ASN1_CHOICE:
+ z = inlen;
+ if ((err = der_decode_choice(in + x, &z, data, size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ break;
+
+ default:
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+ x += z;
+ inlen -= z;
+ list[i].used = 1;
+ if (!ordered) {
+ /* restart the decoder */
+ i = -1;
+ }
+ }
+
+ for (i = 0; i < outlen; i++) {
+ if (list[i].used == 0) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+ }
+ err = CRYPT_OK;
+
+LBL_ERR:
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_ex.c,v $ */
+/* $Revision: 1.16 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_flexi.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_flexi.c
new file mode 100644
index 00000000000..9c648bc89c6
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_flexi.c
@@ -0,0 +1,386 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_decode_sequence_flexi.c
+ ASN.1 DER, decode an array of ASN.1 types with a flexi parser, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+static unsigned long fetch_length(const unsigned char *in, unsigned long inlen)
+{
+ unsigned long x, y, z;
+
+ y = 0;
+
+ /* skip type and read len */
+ if (inlen < 2) {
+ return 0xFFFFFFFF;
+ }
+ ++in; ++y;
+
+ /* read len */
+ x = *in++; ++y;
+
+ /* <128 means literal */
+ if (x < 128) {
+ return x+y;
+ }
+ x &= 0x7F; /* the lower 7 bits are the length of the length */
+ inlen -= 2;
+
+ /* len means len of len! */
+ if (x == 0 || x > 4 || x > inlen) {
+ return 0xFFFFFFFF;
+ }
+
+ y += x;
+ z = 0;
+ while (x--) {
+ z = (z<<8) | ((unsigned long)*in);
+ ++in;
+ }
+ return z+y;
+}
+
+/**
+ ASN.1 DER Flexi(ble) decoder will decode arbitrary DER packets and create a linked list of the decoded elements.
+ @param in The input buffer
+ @param inlen [in/out] The length of the input buffer and on output the amount of decoded data
+ @param out [out] A pointer to the linked list
+ @return CRYPT_OK on success.
+*/
+int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out)
+{
+ ltc_asn1_list *l;
+ unsigned long err, type, len, totlen, x, y;
+ void *realloc_tmp;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(inlen != NULL);
+ LTC_ARGCHK(out != NULL);
+
+ l = NULL;
+ totlen = 0;
+
+ /* scan the input and and get lengths and what not */
+ while (*inlen) {
+ /* read the type byte */
+ type = *in;
+
+ /* fetch length */
+ len = fetch_length(in, *inlen);
+ if (len > *inlen) {
+ err = CRYPT_INVALID_PACKET;
+ goto error;
+ }
+
+ /* alloc new link */
+ if (l == NULL) {
+ l = XCALLOC(1, sizeof(*l));
+ if (l == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+ } else {
+ l->next = XCALLOC(1, sizeof(*l));
+ if (l->next == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+ l->next->prev = l;
+ l = l->next;
+ }
+
+ /* now switch on type */
+ switch (type) {
+ case 0x01: /* BOOLEAN */
+ l->type = LTC_ASN1_BOOLEAN;
+ l->size = 1;
+ l->data = XCALLOC(1, sizeof(int));
+
+ if ((err = der_decode_boolean(in, *inlen, l->data)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_boolean(&len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x02: /* INTEGER */
+ /* init field */
+ l->type = LTC_ASN1_INTEGER;
+ l->size = 1;
+ if ((err = mp_init(&l->data)) != CRYPT_OK) {
+ goto error;
+ }
+
+ /* decode field */
+ if ((err = der_decode_integer(in, *inlen, l->data)) != CRYPT_OK) {
+ goto error;
+ }
+
+ /* calc length of object */
+ if ((err = der_length_integer(l->data, &len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x03: /* BIT */
+ /* init field */
+ l->type = LTC_ASN1_BIT_STRING;
+ l->size = len * 8; /* *8 because we store decoded bits one per char and they are encoded 8 per char. */
+
+ if ((l->data = XCALLOC(1, l->size)) == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ if ((err = der_decode_bit_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_bit_string(l->size, &len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x04: /* OCTET */
+
+ /* init field */
+ l->type = LTC_ASN1_OCTET_STRING;
+ l->size = len;
+
+ if ((l->data = XCALLOC(1, l->size)) == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ if ((err = der_decode_octet_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_octet_string(l->size, &len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x05: /* NULL */
+
+ /* valid NULL is 0x05 0x00 */
+ if (in[0] != 0x05 || in[1] != 0x00) {
+ err = CRYPT_INVALID_PACKET;
+ goto error;
+ }
+
+ /* simple to store ;-) */
+ l->type = LTC_ASN1_NULL;
+ l->data = NULL;
+ l->size = 0;
+ len = 2;
+
+ break;
+
+ case 0x06: /* OID */
+
+ /* init field */
+ l->type = LTC_ASN1_OBJECT_IDENTIFIER;
+ l->size = len;
+
+ if ((l->data = XCALLOC(len, sizeof(unsigned long))) == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ if ((err = der_decode_object_identifier(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_object_identifier(l->data, l->size, &len)) != CRYPT_OK) {
+ goto error;
+ }
+
+ /* resize it to save a bunch of mem */
+ if ((realloc_tmp = XREALLOC(l->data, l->size * sizeof(unsigned long))) == NULL) {
+ /* out of heap but this is not an error */
+ break;
+ }
+ l->data = realloc_tmp;
+ break;
+
+ case 0x0C: /* UTF8 */
+
+ /* init field */
+ l->type = LTC_ASN1_UTF8_STRING;
+ l->size = len;
+
+ if ((l->data = XCALLOC(sizeof(wchar_t), l->size)) == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ if ((err = der_decode_utf8_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_utf8_string(l->data, l->size, &len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x13: /* PRINTABLE */
+
+ /* init field */
+ l->type = LTC_ASN1_PRINTABLE_STRING;
+ l->size = len;
+
+ if ((l->data = XCALLOC(1, l->size)) == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ if ((err = der_decode_printable_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_printable_string(l->data, l->size, &len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x16: /* IA5 */
+
+ /* init field */
+ l->type = LTC_ASN1_IA5_STRING;
+ l->size = len;
+
+ if ((l->data = XCALLOC(1, l->size)) == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ if ((err = der_decode_ia5_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_ia5_string(l->data, l->size, &len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x17: /* UTC TIME */
+
+ /* init field */
+ l->type = LTC_ASN1_UTCTIME;
+ l->size = 1;
+
+ if ((l->data = XCALLOC(1, sizeof(ltc_utctime))) == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ len = *inlen;
+ if ((err = der_decode_utctime(in, &len, l->data)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_utctime(l->data, &len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x30: /* SEQUENCE */
+ case 0x31: /* SET */
+
+ /* init field */
+ l->type = (type == 0x30) ? LTC_ASN1_SEQUENCE : LTC_ASN1_SET;
+
+ /* we have to decode the SEQUENCE header and get it's length */
+
+ /* move past type */
+ ++in; --(*inlen);
+
+ /* read length byte */
+ x = *in++; --(*inlen);
+
+ /* smallest SEQUENCE/SET header */
+ y = 2;
+
+ /* now if it's > 127 the next bytes are the length of the length */
+ if (x > 128) {
+ x &= 0x7F;
+ in += x;
+ *inlen -= x;
+
+ /* update sequence header len */
+ y += x;
+ }
+
+ /* Sequence elements go as child */
+ len = len - y;
+ if ((err = der_decode_sequence_flexi(in, &len, &(l->child))) != CRYPT_OK) {
+ goto error;
+ }
+
+ /* len update */
+ totlen += y;
+
+ /* link them up y0 */
+ l->child->parent = l;
+
+ break;
+ default:
+ /* invalid byte ... this is a soft error */
+ /* remove link */
+ l = l->prev;
+ XFREE(l->next);
+ l->next = NULL;
+ goto outside;
+ }
+
+ /* advance pointers */
+ totlen += len;
+ in += len;
+ *inlen -= len;
+ }
+
+outside:
+
+ /* rewind l please */
+ while (l->prev != NULL || l->parent != NULL) {
+ if (l->parent != NULL) {
+ l = l->parent;
+ } else {
+ l = l->prev;
+ }
+ }
+
+ /* return */
+ *out = l;
+ *inlen = totlen;
+ return CRYPT_OK;
+
+error:
+ /* free list */
+ der_sequence_free(l);
+
+ return err;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c,v $ */
+/* $Revision: 1.26 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_multi.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_multi.c
new file mode 100644
index 00000000000..ff633df3511
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_sequence_multi.c
@@ -0,0 +1,139 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+#include <stdarg.h>
+
+
+/**
+ @file der_decode_sequence_multi.c
+ ASN.1 DER, decode a SEQUENCE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Decode a SEQUENCE type using a VA list
+ @param in Input buffer
+ @param inlen Length of input in octets
+ @remark <...> is of the form <type, size, data> (int, unsigned long, void*)
+ @return CRYPT_OK on success
+*/
+int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
+{
+ int err, type;
+ unsigned long size, x;
+ void *data;
+ va_list args;
+ ltc_asn1_list *list;
+
+ LTC_ARGCHK(in != NULL);
+
+ /* get size of output that will be required */
+ va_start(args, inlen);
+ x = 0;
+ for (;;) {
+ type = va_arg(args, int);
+ size = va_arg(args, unsigned long);
+ data = va_arg(args, void*);
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ case LTC_ASN1_INTEGER:
+ case LTC_ASN1_SHORT_INTEGER:
+ case LTC_ASN1_BIT_STRING:
+ case LTC_ASN1_OCTET_STRING:
+ case LTC_ASN1_NULL:
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ case LTC_ASN1_IA5_STRING:
+ case LTC_ASN1_PRINTABLE_STRING:
+ case LTC_ASN1_UTF8_STRING:
+ case LTC_ASN1_UTCTIME:
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_SEQUENCE:
+ case LTC_ASN1_CHOICE:
+ ++x;
+ break;
+
+ default:
+ va_end(args);
+ return CRYPT_INVALID_ARG;
+ }
+ }
+ va_end(args);
+
+ /* allocate structure for x elements */
+ if (x == 0) {
+ return CRYPT_NOP;
+ }
+
+ list = XCALLOC(sizeof(*list), x);
+ if (list == NULL) {
+ return CRYPT_MEM;
+ }
+
+ /* fill in the structure */
+ va_start(args, inlen);
+ x = 0;
+ for (;;) {
+ type = va_arg(args, int);
+ size = va_arg(args, unsigned long);
+ data = va_arg(args, void*);
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ case LTC_ASN1_INTEGER:
+ case LTC_ASN1_SHORT_INTEGER:
+ case LTC_ASN1_BIT_STRING:
+ case LTC_ASN1_OCTET_STRING:
+ case LTC_ASN1_NULL:
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ case LTC_ASN1_IA5_STRING:
+ case LTC_ASN1_PRINTABLE_STRING:
+ case LTC_ASN1_UTF8_STRING:
+ case LTC_ASN1_UTCTIME:
+ case LTC_ASN1_SEQUENCE:
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_CHOICE:
+ list[x].type = type;
+ list[x].size = size;
+ list[x++].data = data;
+ break;
+
+ default:
+ va_end(args);
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+ }
+ va_end(args);
+
+ err = der_decode_sequence(in, inlen, list, x);
+LBL_ERR:
+ XFREE(list);
+ return err;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_multi.c,v $ */
+/* $Revision: 1.13 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_short_integer.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_short_integer.c
new file mode 100644
index 00000000000..907e4e1c3bb
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_short_integer.c
@@ -0,0 +1,68 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_decode_short_integer.c
+ ASN.1 DER, decode an integer, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Read a short integer
+ @param in The DER encoded data
+ @param inlen Size of data
+ @param num [out] The integer to decode
+ @return CRYPT_OK if successful
+*/
+int der_decode_short_integer(const unsigned char *in, unsigned long inlen, unsigned long *num)
+{
+ unsigned long len, x, y;
+
+ LTC_ARGCHK(num != NULL);
+ LTC_ARGCHK(in != NULL);
+
+ /* check length */
+ if (inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* check header */
+ x = 0;
+ if ((in[x++] & 0x1F) != 0x02) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* get the packet len */
+ len = in[x++];
+
+ if (x + len > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read number */
+ y = 0;
+ while (len--) {
+ y = (y<<8) | (unsigned long)in[x++];
+ }
+ *num = y;
+
+ return CRYPT_OK;
+
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/short_integer/der_decode_short_integer.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_utctime.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_utctime.c
new file mode 100644
index 00000000000..7f3f0d76683
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_utctime.c
@@ -0,0 +1,127 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_decode_utctime.c
+ ASN.1 DER, decode a UTCTIME, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+static int char_to_int(unsigned char x)
+{
+ switch (x) {
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ }
+ return 100;
+}
+
+#define DECODE_V(y, max) \
+ y = char_to_int(buf[x])*10 + char_to_int(buf[x+1]); \
+ if (y >= max) return CRYPT_INVALID_PACKET; \
+ x += 2;
+
+/**
+ Decodes a UTC time structure in DER format (reads all 6 valid encoding formats)
+ @param in Input buffer
+ @param inlen Length of input buffer in octets
+ @param out [out] Destination of UTC time structure
+ @return CRYPT_OK if successful
+*/
+int der_decode_utctime(const unsigned char *in, unsigned long *inlen,
+ ltc_utctime *out)
+{
+ unsigned char buf[32];
+ unsigned long x;
+ int y;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(inlen != NULL);
+ LTC_ARGCHK(out != NULL);
+
+ /* check header */
+ if (*inlen < 2UL || (in[1] >= sizeof(buf)) || ((in[1] + 2UL) > *inlen)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* decode the string */
+ for (x = 0; x < in[1]; x++) {
+ y = der_ia5_value_decode(in[x+2]);
+ if (y == -1) {
+ return CRYPT_INVALID_PACKET;
+ }
+ buf[x] = y;
+ }
+ *inlen = 2 + x;
+
+
+ /* possible encodings are
+YYMMDDhhmmZ
+YYMMDDhhmm+hh'mm'
+YYMMDDhhmm-hh'mm'
+YYMMDDhhmmssZ
+YYMMDDhhmmss+hh'mm'
+YYMMDDhhmmss-hh'mm'
+
+ So let's do a trivial decode upto [including] mm
+ */
+
+ x = 0;
+ DECODE_V(out->YY, 100);
+ DECODE_V(out->MM, 13);
+ DECODE_V(out->DD, 32);
+ DECODE_V(out->hh, 24);
+ DECODE_V(out->mm, 60);
+
+ /* clear timezone and seconds info */
+ out->off_dir = out->off_hh = out->off_mm = out->ss = 0;
+
+ /* now is it Z, +, - or 0-9 */
+ if (buf[x] == 'Z') {
+ return CRYPT_OK;
+ } else if (buf[x] == '+' || buf[x] == '-') {
+ out->off_dir = (buf[x++] == '+') ? 0 : 1;
+ DECODE_V(out->off_hh, 24);
+ DECODE_V(out->off_mm, 60);
+ return CRYPT_OK;
+ }
+
+ /* decode seconds */
+ DECODE_V(out->ss, 60);
+
+ /* now is it Z, +, - */
+ if (buf[x] == 'Z') {
+ return CRYPT_OK;
+ } else if (buf[x] == '+' || buf[x] == '-') {
+ out->off_dir = (buf[x++] == '+') ? 0 : 1;
+ DECODE_V(out->off_hh, 24);
+ DECODE_V(out->off_mm, 60);
+ return CRYPT_OK;
+ } else {
+ return CRYPT_INVALID_PACKET;
+ }
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/utctime/der_decode_utctime.c,v $ */
+/* $Revision: 1.9 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_utf8_string.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_utf8_string.c
new file mode 100644
index 00000000000..898d6cd2a76
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_decode_utf8_string.c
@@ -0,0 +1,111 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_decode_utf8_string.c
+ ASN.1 DER, encode a UTF8 STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Store a UTF8 STRING
+ @param in The DER encoded UTF8 STRING
+ @param inlen The size of the DER UTF8 STRING
+ @param out [out] The array of utf8s stored (one per char)
+ @param outlen [in/out] The number of utf8s stored
+ @return CRYPT_OK if successful
+*/
+int der_decode_utf8_string(const unsigned char *in, unsigned long inlen,
+ wchar_t *out, unsigned long *outlen)
+{
+ wchar_t tmp;
+ unsigned long x, y, z, len;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* must have header at least */
+ if (inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* check for 0x0C */
+ if ((in[0] & 0x1F) != 0x0C) {
+ return CRYPT_INVALID_PACKET;
+ }
+ x = 1;
+
+ /* decode the length */
+ if (in[x] & 0x80) {
+ /* valid # of bytes in length are 1,2,3 */
+ y = in[x] & 0x7F;
+ if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the length in */
+ len = 0;
+ ++x;
+ while (y--) {
+ len = (len << 8) | in[x++];
+ }
+ } else {
+ len = in[x++] & 0x7F;
+ }
+
+ if (len + x > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* proceed to decode */
+ for (y = 0; x < inlen; ) {
+ /* get first byte */
+ tmp = in[x++];
+
+ /* count number of bytes */
+ for (z = 0; (tmp & 0x80) && (z <= 4); z++, tmp = (tmp << 1) & 0xFF);
+
+ if (z > 4 || (x + (z - 1) > inlen)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* decode, grab upper bits */
+ tmp >>= z;
+
+ /* grab remaining bytes */
+ if (z > 1) { --z; }
+ while (z-- != 0) {
+ if ((in[x] & 0xC0) != 0x80) {
+ return CRYPT_INVALID_PACKET;
+ }
+ tmp = (tmp << 6) | ((wchar_t)in[x++] & 0x3F);
+ }
+
+ if (y > *outlen) {
+ *outlen = y;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+ out[y++] = tmp;
+ }
+ *outlen = y;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/utf8/der_decode_utf8_string.c,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_bit_string.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_bit_string.c
new file mode 100644
index 00000000000..2bffa3b6341
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_bit_string.c
@@ -0,0 +1,54 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_length_bit_string.c
+ ASN.1 DER, get length of BIT STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+/**
+ Gets length of DER encoding of BIT STRING
+ @param nbits The number of bits in the string to encode
+ @param outlen [out] The length of the DER encoding for the given string
+ @return CRYPT_OK if successful
+*/
+int der_length_bit_string(unsigned long nbits, unsigned long *outlen)
+{
+ unsigned long nbytes;
+ LTC_ARGCHK(outlen != NULL);
+
+ /* get the number of the bytes */
+ nbytes = (nbits >> 3) + ((nbits & 7) ? 1 : 0) + 1;
+
+ if (nbytes < 128) {
+ /* 03 LL PP DD DD DD ... */
+ *outlen = 2 + nbytes;
+ } else if (nbytes < 256) {
+ /* 03 81 LL PP DD DD DD ... */
+ *outlen = 3 + nbytes;
+ } else if (nbytes < 65536) {
+ /* 03 82 LL LL PP DD DD DD ... */
+ *outlen = 4 + nbytes;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ return CRYPT_OK;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/bit/der_length_bit_string.c,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_boolean.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_boolean.c
new file mode 100644
index 00000000000..e34ce5c65d8
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_boolean.c
@@ -0,0 +1,35 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_length_boolean.c
+ ASN.1 DER, get length of a BOOLEAN, Tom St Denis
+*/
+
+#ifdef LTC_DER
+/**
+ Gets length of DER encoding of a BOOLEAN
+ @param outlen [out] The length of the DER encoding
+ @return CRYPT_OK if successful
+*/
+int der_length_boolean(unsigned long *outlen)
+{
+ LTC_ARGCHK(outlen != NULL);
+ *outlen = 3;
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/boolean/der_length_boolean.c,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_ia5_string.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_ia5_string.c
new file mode 100644
index 00000000000..473bc793257
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_ia5_string.c
@@ -0,0 +1,194 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_length_ia5_string.c
+ ASN.1 DER, get length of IA5 STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+static const struct {
+ int code, value;
+} ia5_table[] = {
+{ '\0', 0 },
+{ '\a', 7 },
+{ '\b', 8 },
+{ '\t', 9 },
+{ '\n', 10 },
+{ '\f', 12 },
+{ '\r', 13 },
+{ ' ', 32 },
+{ '!', 33 },
+{ '"', 34 },
+{ '#', 35 },
+{ '$', 36 },
+{ '%', 37 },
+{ '&', 38 },
+{ '\'', 39 },
+{ '(', 40 },
+{ ')', 41 },
+{ '*', 42 },
+{ '+', 43 },
+{ ',', 44 },
+{ '-', 45 },
+{ '.', 46 },
+{ '/', 47 },
+{ '0', 48 },
+{ '1', 49 },
+{ '2', 50 },
+{ '3', 51 },
+{ '4', 52 },
+{ '5', 53 },
+{ '6', 54 },
+{ '7', 55 },
+{ '8', 56 },
+{ '9', 57 },
+{ ':', 58 },
+{ ';', 59 },
+{ '<', 60 },
+{ '=', 61 },
+{ '>', 62 },
+{ '?', 63 },
+{ '@', 64 },
+{ 'A', 65 },
+{ 'B', 66 },
+{ 'C', 67 },
+{ 'D', 68 },
+{ 'E', 69 },
+{ 'F', 70 },
+{ 'G', 71 },
+{ 'H', 72 },
+{ 'I', 73 },
+{ 'J', 74 },
+{ 'K', 75 },
+{ 'L', 76 },
+{ 'M', 77 },
+{ 'N', 78 },
+{ 'O', 79 },
+{ 'P', 80 },
+{ 'Q', 81 },
+{ 'R', 82 },
+{ 'S', 83 },
+{ 'T', 84 },
+{ 'U', 85 },
+{ 'V', 86 },
+{ 'W', 87 },
+{ 'X', 88 },
+{ 'Y', 89 },
+{ 'Z', 90 },
+{ '[', 91 },
+{ '\\', 92 },
+{ ']', 93 },
+{ '^', 94 },
+{ '_', 95 },
+{ '`', 96 },
+{ 'a', 97 },
+{ 'b', 98 },
+{ 'c', 99 },
+{ 'd', 100 },
+{ 'e', 101 },
+{ 'f', 102 },
+{ 'g', 103 },
+{ 'h', 104 },
+{ 'i', 105 },
+{ 'j', 106 },
+{ 'k', 107 },
+{ 'l', 108 },
+{ 'm', 109 },
+{ 'n', 110 },
+{ 'o', 111 },
+{ 'p', 112 },
+{ 'q', 113 },
+{ 'r', 114 },
+{ 's', 115 },
+{ 't', 116 },
+{ 'u', 117 },
+{ 'v', 118 },
+{ 'w', 119 },
+{ 'x', 120 },
+{ 'y', 121 },
+{ 'z', 122 },
+{ '{', 123 },
+{ '|', 124 },
+{ '}', 125 },
+{ '~', 126 }
+};
+
+int der_ia5_char_encode(int c)
+{
+ int x;
+ for (x = 0; x < (int)(sizeof(ia5_table)/sizeof(ia5_table[0])); x++) {
+ if (ia5_table[x].code == c) {
+ return ia5_table[x].value;
+ }
+ }
+ return -1;
+}
+
+int der_ia5_value_decode(int v)
+{
+ int x;
+ for (x = 0; x < (int)(sizeof(ia5_table)/sizeof(ia5_table[0])); x++) {
+ if (ia5_table[x].value == v) {
+ return ia5_table[x].code;
+ }
+ }
+ return -1;
+}
+
+/**
+ Gets length of DER encoding of IA5 STRING
+ @param octets The values you want to encode
+ @param noctets The number of octets in the string to encode
+ @param outlen [out] The length of the DER encoding for the given string
+ @return CRYPT_OK if successful
+*/
+int der_length_ia5_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen)
+{
+ unsigned long x;
+
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(octets != NULL);
+
+ /* scan string for validity */
+ for (x = 0; x < noctets; x++) {
+ if (der_ia5_char_encode(octets[x]) == -1) {
+ return CRYPT_INVALID_ARG;
+ }
+ }
+
+ if (noctets < 128) {
+ /* 16 LL DD DD DD ... */
+ *outlen = 2 + noctets;
+ } else if (noctets < 256) {
+ /* 16 81 LL DD DD DD ... */
+ *outlen = 3 + noctets;
+ } else if (noctets < 65536UL) {
+ /* 16 82 LL LL DD DD DD ... */
+ *outlen = 4 + noctets;
+ } else if (noctets < 16777216UL) {
+ /* 16 83 LL LL LL DD DD DD ... */
+ *outlen = 5 + noctets;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ return CRYPT_OK;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/ia5/der_length_ia5_string.c,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_integer.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_integer.c
new file mode 100644
index 00000000000..540d205f028
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_integer.c
@@ -0,0 +1,82 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_length_integer.c
+ ASN.1 DER, get length of encoding, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+/**
+ Gets length of DER encoding of num
+ @param num The int to get the size of
+ @param outlen [out] The length of the DER encoding for the given integer
+ @return CRYPT_OK if successful
+*/
+int der_length_integer(void *num, unsigned long *outlen)
+{
+ unsigned long z, len;
+ int leading_zero;
+
+ LTC_ARGCHK(num != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ if (mp_cmp_d(num, 0) != LTC_MP_LT) {
+ /* positive */
+
+ /* we only need a leading zero if the msb of the first byte is one */
+ if ((mp_count_bits(num) & 7) == 0 || mp_iszero(num) == LTC_MP_YES) {
+ leading_zero = 1;
+ } else {
+ leading_zero = 0;
+ }
+
+ /* size for bignum */
+ z = len = leading_zero + mp_unsigned_bin_size(num);
+ } else {
+ /* it's negative */
+ /* find power of 2 that is a multiple of eight and greater than count bits */
+ leading_zero = 0;
+ z = mp_count_bits(num);
+ z = z + (8 - (z & 7));
+ if (((mp_cnt_lsb(num)+1)==mp_count_bits(num)) && ((mp_count_bits(num)&7)==0)) --z;
+ len = z = z >> 3;
+ }
+
+ /* now we need a length */
+ if (z < 128) {
+ /* short form */
+ ++len;
+ } else {
+ /* long form (relies on z != 0), assumes length bytes < 128 */
+ ++len;
+
+ while (z) {
+ ++len;
+ z >>= 8;
+ }
+ }
+
+ /* we need a 0x02 to indicate it's INTEGER */
+ ++len;
+
+ /* return length */
+ *outlen = len;
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/integer/der_length_integer.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_object_identifier.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_object_identifier.c
new file mode 100644
index 00000000000..94c326f7cac
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_object_identifier.c
@@ -0,0 +1,89 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_length_object_identifier.c
+ ASN.1 DER, get length of Object Identifier, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+unsigned long der_object_identifier_bits(unsigned long x)
+{
+ unsigned long c;
+ x &= 0xFFFFFFFF;
+ c = 0;
+ while (x) {
+ ++c;
+ x >>= 1;
+ }
+ return c;
+}
+
+
+/**
+ Gets length of DER encoding of Object Identifier
+ @param nwords The number of OID words
+ @param words The actual OID words to get the size of
+ @param outlen [out] The length of the DER encoding for the given string
+ @return CRYPT_OK if successful
+*/
+int der_length_object_identifier(unsigned long *words, unsigned long nwords, unsigned long *outlen)
+{
+ unsigned long y, z, t, wordbuf;
+
+ LTC_ARGCHK(words != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+
+ /* must be >= 2 words */
+ if (nwords < 2) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* word1 = 0,1,2,3 and word2 0..39 */
+ if (words[0] > 3 || (words[0] < 2 && words[1] > 39)) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* leading word is the first two */
+ z = 0;
+ wordbuf = words[0] * 40 + words[1];
+ for (y = 1; y < nwords; y++) {
+ t = der_object_identifier_bits(wordbuf);
+ z += t/7 + ((t%7) ? 1 : 0) + (wordbuf == 0 ? 1 : 0);
+ if (y < nwords - 1) {
+ /* grab next word */
+ wordbuf = words[y+1];
+ }
+ }
+
+ /* now depending on the length our length encoding changes */
+ if (z < 128) {
+ z += 2;
+ } else if (z < 256) {
+ z += 3;
+ } else if (z < 65536UL) {
+ z += 4;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ *outlen = z;
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/object_identifier/der_length_object_identifier.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_octet_string.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_octet_string.c
new file mode 100644
index 00000000000..acd4053c16a
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_octet_string.c
@@ -0,0 +1,53 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_length_octet_string.c
+ ASN.1 DER, get length of OCTET STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+/**
+ Gets length of DER encoding of OCTET STRING
+ @param noctets The number of octets in the string to encode
+ @param outlen [out] The length of the DER encoding for the given string
+ @return CRYPT_OK if successful
+*/
+int der_length_octet_string(unsigned long noctets, unsigned long *outlen)
+{
+ LTC_ARGCHK(outlen != NULL);
+
+ if (noctets < 128) {
+ /* 04 LL DD DD DD ... */
+ *outlen = 2 + noctets;
+ } else if (noctets < 256) {
+ /* 04 81 LL DD DD DD ... */
+ *outlen = 3 + noctets;
+ } else if (noctets < 65536UL) {
+ /* 04 82 LL LL DD DD DD ... */
+ *outlen = 4 + noctets;
+ } else if (noctets < 16777216UL) {
+ /* 04 83 LL LL LL DD DD DD ... */
+ *outlen = 5 + noctets;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ return CRYPT_OK;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/octet/der_length_octet_string.c,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_printable_string.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_printable_string.c
new file mode 100644
index 00000000000..ef1ed0ede37
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_printable_string.c
@@ -0,0 +1,166 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_length_printable_string.c
+ ASN.1 DER, get length of Printable STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+static const struct {
+ int code, value;
+} printable_table[] = {
+{ ' ', 32 },
+{ '\'', 39 },
+{ '(', 40 },
+{ ')', 41 },
+{ '+', 43 },
+{ ',', 44 },
+{ '-', 45 },
+{ '.', 46 },
+{ '/', 47 },
+{ '0', 48 },
+{ '1', 49 },
+{ '2', 50 },
+{ '3', 51 },
+{ '4', 52 },
+{ '5', 53 },
+{ '6', 54 },
+{ '7', 55 },
+{ '8', 56 },
+{ '9', 57 },
+{ ':', 58 },
+{ '=', 61 },
+{ '?', 63 },
+{ 'A', 65 },
+{ 'B', 66 },
+{ 'C', 67 },
+{ 'D', 68 },
+{ 'E', 69 },
+{ 'F', 70 },
+{ 'G', 71 },
+{ 'H', 72 },
+{ 'I', 73 },
+{ 'J', 74 },
+{ 'K', 75 },
+{ 'L', 76 },
+{ 'M', 77 },
+{ 'N', 78 },
+{ 'O', 79 },
+{ 'P', 80 },
+{ 'Q', 81 },
+{ 'R', 82 },
+{ 'S', 83 },
+{ 'T', 84 },
+{ 'U', 85 },
+{ 'V', 86 },
+{ 'W', 87 },
+{ 'X', 88 },
+{ 'Y', 89 },
+{ 'Z', 90 },
+{ 'a', 97 },
+{ 'b', 98 },
+{ 'c', 99 },
+{ 'd', 100 },
+{ 'e', 101 },
+{ 'f', 102 },
+{ 'g', 103 },
+{ 'h', 104 },
+{ 'i', 105 },
+{ 'j', 106 },
+{ 'k', 107 },
+{ 'l', 108 },
+{ 'm', 109 },
+{ 'n', 110 },
+{ 'o', 111 },
+{ 'p', 112 },
+{ 'q', 113 },
+{ 'r', 114 },
+{ 's', 115 },
+{ 't', 116 },
+{ 'u', 117 },
+{ 'v', 118 },
+{ 'w', 119 },
+{ 'x', 120 },
+{ 'y', 121 },
+{ 'z', 122 },
+};
+
+int der_printable_char_encode(int c)
+{
+ int x;
+ for (x = 0; x < (int)(sizeof(printable_table)/sizeof(printable_table[0])); x++) {
+ if (printable_table[x].code == c) {
+ return printable_table[x].value;
+ }
+ }
+ return -1;
+}
+
+int der_printable_value_decode(int v)
+{
+ int x;
+ for (x = 0; x < (int)(sizeof(printable_table)/sizeof(printable_table[0])); x++) {
+ if (printable_table[x].value == v) {
+ return printable_table[x].code;
+ }
+ }
+ return -1;
+}
+
+/**
+ Gets length of DER encoding of Printable STRING
+ @param octets The values you want to encode
+ @param noctets The number of octets in the string to encode
+ @param outlen [out] The length of the DER encoding for the given string
+ @return CRYPT_OK if successful
+*/
+int der_length_printable_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen)
+{
+ unsigned long x;
+
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(octets != NULL);
+
+ /* scan string for validity */
+ for (x = 0; x < noctets; x++) {
+ if (der_printable_char_encode(octets[x]) == -1) {
+ return CRYPT_INVALID_ARG;
+ }
+ }
+
+ if (noctets < 128) {
+ /* 16 LL DD DD DD ... */
+ *outlen = 2 + noctets;
+ } else if (noctets < 256) {
+ /* 16 81 LL DD DD DD ... */
+ *outlen = 3 + noctets;
+ } else if (noctets < 65536UL) {
+ /* 16 82 LL LL DD DD DD ... */
+ *outlen = 4 + noctets;
+ } else if (noctets < 16777216UL) {
+ /* 16 83 LL LL LL DD DD DD ... */
+ *outlen = 5 + noctets;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ return CRYPT_OK;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/printable_string/der_length_printable_string.c,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_sequence.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_sequence.c
new file mode 100644
index 00000000000..e75ed7e7eeb
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_sequence.c
@@ -0,0 +1,169 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_length_sequence.c
+ ASN.1 DER, length a SEQUENCE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Get the length of a DER sequence
+ @param list The sequences of items in the SEQUENCE
+ @param inlen The number of items
+ @param outlen [out] The length required in octets to store it
+ @return CRYPT_OK on success
+*/
+int der_length_sequence(ltc_asn1_list *list, unsigned long inlen,
+ unsigned long *outlen)
+{
+ int err, type;
+ unsigned long size, x, y, z, i;
+ void *data;
+
+ LTC_ARGCHK(list != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* get size of output that will be required */
+ y = 0;
+ for (i = 0; i < inlen; i++) {
+ type = list[i].type;
+ size = list[i].size;
+ data = list[i].data;
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ if ((err = der_length_boolean(&x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_INTEGER:
+ if ((err = der_length_integer(data, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_SHORT_INTEGER:
+ if ((err = der_length_short_integer(*((unsigned long *)data), &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_BIT_STRING:
+ if ((err = der_length_bit_string(size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_OCTET_STRING:
+ if ((err = der_length_octet_string(size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_NULL:
+ y += 2;
+ break;
+
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ if ((err = der_length_object_identifier(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_IA5_STRING:
+ if ((err = der_length_ia5_string(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_PRINTABLE_STRING:
+ if ((err = der_length_printable_string(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_UTCTIME:
+ if ((err = der_length_utctime(data, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_UTF8_STRING:
+ if ((err = der_length_utf8_string(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_SEQUENCE:
+ if ((err = der_length_sequence(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+
+ default:
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+ }
+
+ /* calc header size */
+ z = y;
+ if (y < 128) {
+ y += 2;
+ } else if (y < 256) {
+ /* 0x30 0x81 LL */
+ y += 3;
+ } else if (y < 65536UL) {
+ /* 0x30 0x82 LL LL */
+ y += 4;
+ } else if (y < 16777216UL) {
+ /* 0x30 0x83 LL LL LL */
+ y += 5;
+ } else {
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+
+ /* store size */
+ *outlen = y;
+ err = CRYPT_OK;
+
+LBL_ERR:
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/sequence/der_length_sequence.c,v $ */
+/* $Revision: 1.14 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_short_integer.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_short_integer.c
new file mode 100644
index 00000000000..afa6dd0ee61
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_short_integer.c
@@ -0,0 +1,70 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_length_short_integer.c
+ ASN.1 DER, get length of encoding, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+/**
+ Gets length of DER encoding of num
+ @param num The integer to get the size of
+ @param outlen [out] The length of the DER encoding for the given integer
+ @return CRYPT_OK if successful
+*/
+int der_length_short_integer(unsigned long num, unsigned long *outlen)
+{
+ unsigned long z, y, len;
+
+ LTC_ARGCHK(outlen != NULL);
+
+ /* force to 32 bits */
+ num &= 0xFFFFFFFFUL;
+
+ /* get the number of bytes */
+ z = 0;
+ y = num;
+ while (y) {
+ ++z;
+ y >>= 8;
+ }
+
+ /* handle zero */
+ if (z == 0) {
+ z = 1;
+ }
+
+ /* we need a 0x02 to indicate it's INTEGER */
+ len = 1;
+
+ /* length byte */
+ ++len;
+
+ /* bytes in value */
+ len += z;
+
+ /* see if msb is set */
+ len += (num&(1UL<<((z<<3) - 1))) ? 1 : 0;
+
+ /* return length */
+ *outlen = len;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/short_integer/der_length_short_integer.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_utctime.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_utctime.c
new file mode 100644
index 00000000000..1296babbadf
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_utctime.c
@@ -0,0 +1,46 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_length_utctime.c
+ ASN.1 DER, get length of UTCTIME, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Gets length of DER encoding of UTCTIME
+ @param utctime The UTC time structure to get the size of
+ @param outlen [out] The length of the DER encoding
+ @return CRYPT_OK if successful
+*/
+int der_length_utctime(ltc_utctime *utctime, unsigned long *outlen)
+{
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(utctime != NULL);
+
+ if (utctime->off_hh == 0 && utctime->off_mm == 0) {
+ /* we encode as YYMMDDhhmmssZ */
+ *outlen = 2 + 13;
+ } else {
+ /* we encode as YYMMDDhhmmss{+|-}hh'mm' */
+ *outlen = 2 + 17;
+ }
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/utctime/der_length_utctime.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_utf8_string.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_utf8_string.c
new file mode 100644
index 00000000000..514db8450ef
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_length_utf8_string.c
@@ -0,0 +1,83 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_length_utf8_string.c
+ ASN.1 DER, get length of UTF8 STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/** Return the size in bytes of a UTF-8 character
+ @param c The UTF-8 character to measure
+ @return The size in bytes
+*/
+unsigned long der_utf8_charsize(const wchar_t c)
+{
+ if (c <= 0x7F) {
+ return 1;
+ } else if (c <= 0x7FF) {
+ return 2;
+ } else if (c <= 0xFFFF) {
+ return 3;
+ } else {
+ return 4;
+ }
+}
+
+/**
+ Gets length of DER encoding of UTF8 STRING
+ @param in The characters to measure the length of
+ @param noctets The number of octets in the string to encode
+ @param outlen [out] The length of the DER encoding for the given string
+ @return CRYPT_OK if successful
+*/
+int der_length_utf8_string(const wchar_t *in, unsigned long noctets, unsigned long *outlen)
+{
+ unsigned long x, len;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ len = 0;
+ for (x = 0; x < noctets; x++) {
+ if (in[x] < 0 || in[x] > 0x10FFFF) {
+ return CRYPT_INVALID_ARG;
+ }
+ len += der_utf8_charsize(in[x]);
+ }
+
+ if (len < 128) {
+ /* 0C LL DD DD DD ... */
+ *outlen = 2 + len;
+ } else if (len < 256) {
+ /* 0C 81 LL DD DD DD ... */
+ *outlen = 3 + len;
+ } else if (len < 65536UL) {
+ /* 0C 82 LL LL DD DD DD ... */
+ *outlen = 4 + len;
+ } else if (len < 16777216UL) {
+ /* 0C 83 LL LL LL DD DD DD ... */
+ *outlen = 5 + len;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ return CRYPT_OK;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/utf8/der_length_utf8_string.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_sequence_free.c b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_sequence_free.c
new file mode 100644
index 00000000000..4887215397f
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/asn1/der_sequence_free.c
@@ -0,0 +1,65 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file der_sequence_free.c
+ ASN.1 DER, free's a structure allocated by der_decode_sequence_flexi(), Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Free memory allocated by der_decode_sequence_flexi()
+ @param in The list to free
+*/
+void der_sequence_free(ltc_asn1_list *in)
+{
+ ltc_asn1_list *l;
+
+ /* walk to the start of the chain */
+ while (in->prev != NULL || in->parent != NULL) {
+ if (in->parent != NULL) {
+ in = in->parent;
+ } else {
+ in = in->prev;
+ }
+ }
+
+ /* now walk the list and free stuff */
+ while (in != NULL) {
+ /* is there a child? */
+ if (in->child) {
+ /* disconnect */
+ in->child->parent = NULL;
+ der_sequence_free(in->child);
+ }
+
+ switch (in->type) {
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_SEQUENCE: break;
+ case LTC_ASN1_INTEGER : if (in->data != NULL) { mp_clear(in->data); } break;
+ default : if (in->data != NULL) { XFREE(in->data); }
+ }
+
+ /* move to next and free current */
+ l = in->next;
+ free(in);
+ in = l;
+ }
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/sequence/der_sequence_free.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_map.c b/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_map.c
new file mode 100644
index 00000000000..5a1324c4986
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_map.c
@@ -0,0 +1,76 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file ltc_ecc_map.c
+ ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/**
+ Map a projective jacbobian point back to affine space
+ @param P [in/out] The point to map
+ @param modulus The modulus of the field the ECC curve is in
+ @param mp The "b" value from montgomery_setup()
+ @return CRYPT_OK on success
+*/
+int ltc_ecc_map(ecc_point *P, void *modulus, void *mp)
+{
+ void *t1, *t2;
+ int err;
+
+ LTC_ARGCHK(P != NULL);
+ LTC_ARGCHK(modulus != NULL);
+ LTC_ARGCHK(mp != NULL);
+
+ if ((err = mp_init_multi(&t1, &t2, NULL)) != CRYPT_OK) {
+ return CRYPT_MEM;
+ }
+
+ /* first map z back to normal */
+ if ((err = mp_montgomery_reduce(P->z, modulus, mp)) != CRYPT_OK) { goto done; }
+
+ /* get 1/z */
+ if ((err = mp_invmod(P->z, modulus, t1)) != CRYPT_OK) { goto done; }
+
+ /* get 1/z^2 and 1/z^3 */
+ if ((err = mp_sqr(t1, t2)) != CRYPT_OK) { goto done; }
+ if ((err = mp_mod(t2, modulus, t2)) != CRYPT_OK) { goto done; }
+ if ((err = mp_mul(t1, t2, t1)) != CRYPT_OK) { goto done; }
+ if ((err = mp_mod(t1, modulus, t1)) != CRYPT_OK) { goto done; }
+
+ /* multiply against x/y */
+ if ((err = mp_mul(P->x, t2, P->x)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(P->x, modulus, mp)) != CRYPT_OK) { goto done; }
+ if ((err = mp_mul(P->y, t1, P->y)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(P->y, modulus, mp)) != CRYPT_OK) { goto done; }
+ if ((err = mp_set(P->z, 1)) != CRYPT_OK) { goto done; }
+
+ err = CRYPT_OK;
+done:
+ mp_clear_multi(t1, t2, NULL);
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ltc_ecc_map.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
+
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_mul2add.c b/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_mul2add.c
new file mode 100644
index 00000000000..2c468eaafa1
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_mul2add.c
@@ -0,0 +1,207 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file ltc_ecc_mul2add.c
+ ECC Crypto, Shamir's Trick, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+#ifdef LTC_ECC_SHAMIR
+
+/** Computes kA*A + kB*B = C using Shamir's Trick
+ @param A First point to multiply
+ @param kA What to multiple A by
+ @param B Second point to multiply
+ @param kB What to multiple B by
+ @param C [out] Destination point (can overlap with A or B
+ @param modulus Modulus for curve
+ @return CRYPT_OK on success
+*/
+int ltc_ecc_mul2add(ecc_point *A, void *kA,
+ ecc_point *B, void *kB,
+ ecc_point *C,
+ void *modulus)
+{
+ ecc_point *precomp[16];
+ unsigned bitbufA, bitbufB, lenA, lenB, len, x, y, nA, nB, nibble;
+ unsigned char *tA, *tB;
+ int err, first;
+ void *mp, *mu;
+
+ /* argchks */
+ LTC_ARGCHK(A != NULL);
+ LTC_ARGCHK(B != NULL);
+ LTC_ARGCHK(C != NULL);
+ LTC_ARGCHK(kA != NULL);
+ LTC_ARGCHK(kB != NULL);
+ LTC_ARGCHK(modulus != NULL);
+
+ /* allocate memory */
+ tA = XCALLOC(1, ECC_BUF_SIZE);
+ if (tA == NULL) {
+ return CRYPT_MEM;
+ }
+ tB = XCALLOC(1, ECC_BUF_SIZE);
+ if (tB == NULL) {
+ XFREE(tA);
+ return CRYPT_MEM;
+ }
+
+ /* get sizes */
+ lenA = mp_unsigned_bin_size(kA);
+ lenB = mp_unsigned_bin_size(kB);
+ len = MAX(lenA, lenB);
+
+ /* sanity check */
+ if ((lenA > ECC_BUF_SIZE) || (lenB > ECC_BUF_SIZE)) {
+ err = CRYPT_INVALID_ARG;
+ goto ERR_T;
+ }
+
+ /* extract and justify kA */
+ mp_to_unsigned_bin(kA, (len - lenA) + tA);
+
+ /* extract and justify kB */
+ mp_to_unsigned_bin(kB, (len - lenB) + tB);
+
+ /* allocate the table */
+ for (x = 0; x < 16; x++) {
+ precomp[x] = ltc_ecc_new_point();
+ if (precomp[x] == NULL) {
+ for (y = 0; y < x; ++y) {
+ ltc_ecc_del_point(precomp[y]);
+ }
+ err = CRYPT_MEM;
+ goto ERR_T;
+ }
+ }
+
+ /* init montgomery reduction */
+ if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) {
+ goto ERR_P;
+ }
+ if ((err = mp_init(&mu)) != CRYPT_OK) {
+ goto ERR_MP;
+ }
+ if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) {
+ goto ERR_MU;
+ }
+
+ /* copy ones ... */
+ if ((err = mp_mulmod(A->x, mu, modulus, precomp[1]->x)) != CRYPT_OK) { goto ERR_MU; }
+ if ((err = mp_mulmod(A->y, mu, modulus, precomp[1]->y)) != CRYPT_OK) { goto ERR_MU; }
+ if ((err = mp_mulmod(A->z, mu, modulus, precomp[1]->z)) != CRYPT_OK) { goto ERR_MU; }
+
+ if ((err = mp_mulmod(B->x, mu, modulus, precomp[1<<2]->x)) != CRYPT_OK) { goto ERR_MU; }
+ if ((err = mp_mulmod(B->y, mu, modulus, precomp[1<<2]->y)) != CRYPT_OK) { goto ERR_MU; }
+ if ((err = mp_mulmod(B->z, mu, modulus, precomp[1<<2]->z)) != CRYPT_OK) { goto ERR_MU; }
+
+ /* precomp [i,0](A + B) table */
+ if ((err = ltc_mp.ecc_ptdbl(precomp[1], precomp[2], modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
+ if ((err = ltc_mp.ecc_ptadd(precomp[1], precomp[2], precomp[3], modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
+
+ /* precomp [0,i](A + B) table */
+ if ((err = ltc_mp.ecc_ptdbl(precomp[1<<2], precomp[2<<2], modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
+ if ((err = ltc_mp.ecc_ptadd(precomp[1<<2], precomp[2<<2], precomp[3<<2], modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
+
+ /* precomp [i,j](A + B) table (i != 0, j != 0) */
+ for (x = 1; x < 4; x++) {
+ for (y = 1; y < 4; y++) {
+ if ((err = ltc_mp.ecc_ptadd(precomp[x], precomp[(y<<2)], precomp[x+(y<<2)], modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
+ }
+ }
+
+ nibble = 3;
+ first = 1;
+ bitbufA = tA[0];
+ bitbufB = tB[0];
+
+ /* for every byte of the multiplicands */
+ for (x = -1;; ) {
+ /* grab a nibble */
+ if (++nibble == 4) {
+ ++x; if (x == len) break;
+ bitbufA = tA[x];
+ bitbufB = tB[x];
+ nibble = 0;
+ }
+
+ /* extract two bits from both, shift/update */
+ nA = (bitbufA >> 6) & 0x03;
+ nB = (bitbufB >> 6) & 0x03;
+ bitbufA = (bitbufA << 2) & 0xFF;
+ bitbufB = (bitbufB << 2) & 0xFF;
+
+ /* if both zero, if first, continue */
+ if ((nA == 0) && (nB == 0) && (first == 1)) {
+ continue;
+ }
+
+ /* double twice, only if this isn't the first */
+ if (first == 0) {
+ /* double twice */
+ if ((err = ltc_mp.ecc_ptdbl(C, C, modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
+ if ((err = ltc_mp.ecc_ptdbl(C, C, modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
+ }
+
+ /* if not both zero */
+ if ((nA != 0) || (nB != 0)) {
+ if (first == 1) {
+ /* if first, copy from table */
+ first = 0;
+ if ((err = mp_copy(precomp[nA + (nB<<2)]->x, C->x)) != CRYPT_OK) { goto ERR_MU; }
+ if ((err = mp_copy(precomp[nA + (nB<<2)]->y, C->y)) != CRYPT_OK) { goto ERR_MU; }
+ if ((err = mp_copy(precomp[nA + (nB<<2)]->z, C->z)) != CRYPT_OK) { goto ERR_MU; }
+ } else {
+ /* if not first, add from table */
+ if ((err = ltc_mp.ecc_ptadd(C, precomp[nA + (nB<<2)], C, modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
+ }
+ }
+ }
+
+ /* reduce to affine */
+ err = ltc_ecc_map(C, modulus, mp);
+
+ /* clean up */
+ERR_MU:
+ mp_clear(mu);
+ERR_MP:
+ mp_montgomery_free(mp);
+ERR_P:
+ for (x = 0; x < 16; x++) {
+ ltc_ecc_del_point(precomp[x]);
+ }
+ERR_T:
+#ifdef LTC_CLEAN_STACK
+ zeromem(tA, ECC_BUF_SIZE);
+ zeromem(tB, ECC_BUF_SIZE);
+#endif
+ XFREE(tA);
+ XFREE(tB);
+
+ return err;
+}
+
+#endif
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ltc_ecc_mul2add.c,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod.c b/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod.c
new file mode 100644
index 00000000000..f9d0cad832d
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod.c
@@ -0,0 +1,222 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file ltc_ecc_mulmod.c
+ ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+#ifndef LTC_ECC_TIMING_RESISTANT
+
+/* size of sliding window, don't change this! */
+#define WINSIZE 4
+
+/**
+ Perform a point multiplication
+ @param k The scalar to multiply by
+ @param G The base point
+ @param R [out] Destination for kG
+ @param modulus The modulus of the field the ECC curve is in
+ @param map Boolean whether to map back to affine or not (1==map, 0 == leave in projective)
+ @return CRYPT_OK on success
+*/
+int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map)
+{
+ ecc_point *tG, *M[8];
+ int i, j, err;
+ void *mu, *mp;
+ unsigned long buf;
+ int first, bitbuf, bitcpy, bitcnt, mode, digidx;
+
+ LTC_ARGCHK(k != NULL);
+ LTC_ARGCHK(G != NULL);
+ LTC_ARGCHK(R != NULL);
+ LTC_ARGCHK(modulus != NULL);
+
+ /* init montgomery reduction */
+ if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) {
+ return err;
+ }
+ if ((err = mp_init(&mu)) != CRYPT_OK) {
+ mp_montgomery_free(mp);
+ return err;
+ }
+ if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) {
+ mp_montgomery_free(mp);
+ mp_clear(mu);
+ return err;
+ }
+
+ /* alloc ram for window temps */
+ for (i = 0; i < 8; i++) {
+ M[i] = ltc_ecc_new_point();
+ if (M[i] == NULL) {
+ for (j = 0; j < i; j++) {
+ ltc_ecc_del_point(M[j]);
+ }
+ mp_montgomery_free(mp);
+ mp_clear(mu);
+ return CRYPT_MEM;
+ }
+ }
+
+ /* make a copy of G incase R==G */
+ tG = ltc_ecc_new_point();
+ if (tG == NULL) { err = CRYPT_MEM; goto done; }
+
+ /* tG = G and convert to montgomery */
+ if (mp_cmp_d(mu, 1) == LTC_MP_EQ) {
+ if ((err = mp_copy(G->x, tG->x)) != CRYPT_OK) { goto done; }
+ if ((err = mp_copy(G->y, tG->y)) != CRYPT_OK) { goto done; }
+ if ((err = mp_copy(G->z, tG->z)) != CRYPT_OK) { goto done; }
+ } else {
+ if ((err = mp_mulmod(G->x, mu, modulus, tG->x)) != CRYPT_OK) { goto done; }
+ if ((err = mp_mulmod(G->y, mu, modulus, tG->y)) != CRYPT_OK) { goto done; }
+ if ((err = mp_mulmod(G->z, mu, modulus, tG->z)) != CRYPT_OK) { goto done; }
+ }
+ mp_clear(mu);
+ mu = NULL;
+
+ /* calc the M tab, which holds kG for k==8..15 */
+ /* M[0] == 8G */
+ if ((err = ltc_mp.ecc_ptdbl(tG, M[0], modulus, mp)) != CRYPT_OK) { goto done; }
+ if ((err = ltc_mp.ecc_ptdbl(M[0], M[0], modulus, mp)) != CRYPT_OK) { goto done; }
+ if ((err = ltc_mp.ecc_ptdbl(M[0], M[0], modulus, mp)) != CRYPT_OK) { goto done; }
+
+ /* now find (8+k)G for k=1..7 */
+ for (j = 9; j < 16; j++) {
+ if ((err = ltc_mp.ecc_ptadd(M[j-9], tG, M[j-8], modulus, mp)) != CRYPT_OK) { goto done; }
+ }
+
+ /* setup sliding window */
+ mode = 0;
+ bitcnt = 1;
+ buf = 0;
+ digidx = mp_get_digit_count(k) - 1;
+ bitcpy = bitbuf = 0;
+ first = 1;
+
+ /* perform ops */
+ for (;;) {
+ /* grab next digit as required */
+ if (--bitcnt == 0) {
+ if (digidx == -1) {
+ break;
+ }
+ buf = mp_get_digit(k, digidx);
+ bitcnt = (int) ltc_mp.bits_per_digit;
+ --digidx;
+ }
+
+ /* grab the next msb from the ltiplicand */
+ i = (buf >> (ltc_mp.bits_per_digit - 1)) & 1;
+ buf <<= 1;
+
+ /* skip leading zero bits */
+ if (mode == 0 && i == 0) {
+ continue;
+ }
+
+ /* if the bit is zero and mode == 1 then we double */
+ if (mode == 1 && i == 0) {
+ if ((err = ltc_mp.ecc_ptdbl(R, R, modulus, mp)) != CRYPT_OK) { goto done; }
+ continue;
+ }
+
+ /* else we add it to the window */
+ bitbuf |= (i << (WINSIZE - ++bitcpy));
+ mode = 2;
+
+ if (bitcpy == WINSIZE) {
+ /* if this is the first window we do a simple copy */
+ if (first == 1) {
+ /* R = kG [k = first window] */
+ if ((err = mp_copy(M[bitbuf-8]->x, R->x)) != CRYPT_OK) { goto done; }
+ if ((err = mp_copy(M[bitbuf-8]->y, R->y)) != CRYPT_OK) { goto done; }
+ if ((err = mp_copy(M[bitbuf-8]->z, R->z)) != CRYPT_OK) { goto done; }
+ first = 0;
+ } else {
+ /* normal window */
+ /* ok window is filled so double as required and add */
+ /* double first */
+ for (j = 0; j < WINSIZE; j++) {
+ if ((err = ltc_mp.ecc_ptdbl(R, R, modulus, mp)) != CRYPT_OK) { goto done; }
+ }
+
+ /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranteed */
+ if ((err = ltc_mp.ecc_ptadd(R, M[bitbuf-8], R, modulus, mp)) != CRYPT_OK) { goto done; }
+ }
+ /* empty window and reset */
+ bitcpy = bitbuf = 0;
+ mode = 1;
+ }
+ }
+
+ /* if bits remain then double/add */
+ if (mode == 2 && bitcpy > 0) {
+ /* double then add */
+ for (j = 0; j < bitcpy; j++) {
+ /* only double if we have had at least one add first */
+ if (first == 0) {
+ if ((err = ltc_mp.ecc_ptdbl(R, R, modulus, mp)) != CRYPT_OK) { goto done; }
+ }
+
+ bitbuf <<= 1;
+ if ((bitbuf & (1 << WINSIZE)) != 0) {
+ if (first == 1){
+ /* first add, so copy */
+ if ((err = mp_copy(tG->x, R->x)) != CRYPT_OK) { goto done; }
+ if ((err = mp_copy(tG->y, R->y)) != CRYPT_OK) { goto done; }
+ if ((err = mp_copy(tG->z, R->z)) != CRYPT_OK) { goto done; }
+ first = 0;
+ } else {
+ /* then add */
+ if ((err = ltc_mp.ecc_ptadd(R, tG, R, modulus, mp)) != CRYPT_OK) { goto done; }
+ }
+ }
+ }
+ }
+
+ /* map R back from projective space */
+ if (map) {
+ err = ltc_ecc_map(R, modulus, mp);
+ } else {
+ err = CRYPT_OK;
+ }
+done:
+ if (mu != NULL) {
+ mp_clear(mu);
+ }
+ mp_montgomery_free(mp);
+ ltc_ecc_del_point(tG);
+ for (i = 0; i < 8; i++) {
+ ltc_ecc_del_point(M[i]);
+ }
+ return err;
+}
+
+#endif
+
+#undef WINSIZE
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod.c,v $ */
+/* $Revision: 1.26 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_points.c b/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_points.c
new file mode 100644
index 00000000000..f5a4acb4c5a
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_points.c
@@ -0,0 +1,60 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file ltc_ecc_points.c
+ ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/**
+ Allocate a new ECC point
+ @return A newly allocated point or NULL on error
+*/
+ecc_point *ltc_ecc_new_point(void)
+{
+ ecc_point *p;
+ p = XCALLOC(1, sizeof(*p));
+ if (p == NULL) {
+ return NULL;
+ }
+ if (mp_init_multi(&p->x, &p->y, &p->z, NULL) != CRYPT_OK) {
+ XFREE(p);
+ return NULL;
+ }
+ return p;
+}
+
+/** Free an ECC point from memory
+ @param p The point to free
+*/
+void ltc_ecc_del_point(ecc_point *p)
+{
+ /* prevents free'ing null arguments */
+ if (p != NULL) {
+ mp_clear_multi(p->x, p->y, p->z, NULL); /* note: p->z may be NULL but that's ok with this function anyways */
+ XFREE(p);
+ }
+}
+
+#endif
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ltc_ecc_points.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
+
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_projective_add_point.c b/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_projective_add_point.c
new file mode 100644
index 00000000000..b4416fc77de
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_projective_add_point.c
@@ -0,0 +1,196 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file ltc_ecc_projective_add_point.c
+ ECC Crypto, Tom St Denis
+*/
+
+#if defined(LTC_MECC) && (!defined(LTC_MECC_ACCEL) || defined(LTM_LTC_DESC))
+
+/**
+ Add two ECC points
+ @param P The point to add
+ @param Q The point to add
+ @param R [out] The destination of the double
+ @param modulus The modulus of the field the ECC curve is in
+ @param mp The "b" value from montgomery_setup()
+ @return CRYPT_OK on success
+*/
+int ltc_ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *mp)
+{
+ void *t1, *t2, *x, *y, *z;
+ int err;
+
+ LTC_ARGCHK(P != NULL);
+ LTC_ARGCHK(Q != NULL);
+ LTC_ARGCHK(R != NULL);
+ LTC_ARGCHK(modulus != NULL);
+ LTC_ARGCHK(mp != NULL);
+
+ if ((err = mp_init_multi(&t1, &t2, &x, &y, &z, NULL)) != CRYPT_OK) {
+ return err;
+ }
+
+ /* should we dbl instead? */
+ if ((err = mp_sub(modulus, Q->y, t1)) != CRYPT_OK) { goto done; }
+
+ if ( (mp_cmp(P->x, Q->x) == LTC_MP_EQ) &&
+ (Q->z != NULL && mp_cmp(P->z, Q->z) == LTC_MP_EQ) &&
+ (mp_cmp(P->y, Q->y) == LTC_MP_EQ || mp_cmp(P->y, t1) == LTC_MP_EQ)) {
+ mp_clear_multi(t1, t2, x, y, z, NULL);
+ return ltc_ecc_projective_dbl_point(P, R, modulus, mp);
+ }
+
+ if ((err = mp_copy(P->x, x)) != CRYPT_OK) { goto done; }
+ if ((err = mp_copy(P->y, y)) != CRYPT_OK) { goto done; }
+ if ((err = mp_copy(P->z, z)) != CRYPT_OK) { goto done; }
+
+ /* if Z is one then these are no-operations */
+ if (Q->z != NULL) {
+ /* T1 = Z' * Z' */
+ if ((err = mp_sqr(Q->z, t1)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* X = X * T1 */
+ if ((err = mp_mul(t1, x, x)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(x, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* T1 = Z' * T1 */
+ if ((err = mp_mul(Q->z, t1, t1)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* Y = Y * T1 */
+ if ((err = mp_mul(t1, y, y)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(y, modulus, mp)) != CRYPT_OK) { goto done; }
+ }
+
+ /* T1 = Z*Z */
+ if ((err = mp_sqr(z, t1)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* T2 = X' * T1 */
+ if ((err = mp_mul(Q->x, t1, t2)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* T1 = Z * T1 */
+ if ((err = mp_mul(z, t1, t1)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* T1 = Y' * T1 */
+ if ((err = mp_mul(Q->y, t1, t1)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
+
+ /* Y = Y - T1 */
+ if ((err = mp_sub(y, t1, y)) != CRYPT_OK) { goto done; }
+ if (mp_cmp_d(y, 0) == LTC_MP_LT) {
+ if ((err = mp_add(y, modulus, y)) != CRYPT_OK) { goto done; }
+ }
+ /* T1 = 2T1 */
+ if ((err = mp_add(t1, t1, t1)) != CRYPT_OK) { goto done; }
+ if (mp_cmp(t1, modulus) != LTC_MP_LT) {
+ if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; }
+ }
+ /* T1 = Y + T1 */
+ if ((err = mp_add(t1, y, t1)) != CRYPT_OK) { goto done; }
+ if (mp_cmp(t1, modulus) != LTC_MP_LT) {
+ if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; }
+ }
+ /* X = X - T2 */
+ if ((err = mp_sub(x, t2, x)) != CRYPT_OK) { goto done; }
+ if (mp_cmp_d(x, 0) == LTC_MP_LT) {
+ if ((err = mp_add(x, modulus, x)) != CRYPT_OK) { goto done; }
+ }
+ /* T2 = 2T2 */
+ if ((err = mp_add(t2, t2, t2)) != CRYPT_OK) { goto done; }
+ if (mp_cmp(t2, modulus) != LTC_MP_LT) {
+ if ((err = mp_sub(t2, modulus, t2)) != CRYPT_OK) { goto done; }
+ }
+ /* T2 = X + T2 */
+ if ((err = mp_add(t2, x, t2)) != CRYPT_OK) { goto done; }
+ if (mp_cmp(t2, modulus) != LTC_MP_LT) {
+ if ((err = mp_sub(t2, modulus, t2)) != CRYPT_OK) { goto done; }
+ }
+
+ /* if Z' != 1 */
+ if (Q->z != NULL) {
+ /* Z = Z * Z' */
+ if ((err = mp_mul(z, Q->z, z)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(z, modulus, mp)) != CRYPT_OK) { goto done; }
+ }
+
+ /* Z = Z * X */
+ if ((err = mp_mul(z, x, z)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(z, modulus, mp)) != CRYPT_OK) { goto done; }
+
+ /* T1 = T1 * X */
+ if ((err = mp_mul(t1, x, t1)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* X = X * X */
+ if ((err = mp_sqr(x, x)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(x, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* T2 = T2 * x */
+ if ((err = mp_mul(t2, x, t2)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* T1 = T1 * X */
+ if ((err = mp_mul(t1, x, t1)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
+
+ /* X = Y*Y */
+ if ((err = mp_sqr(y, x)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(x, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* X = X - T2 */
+ if ((err = mp_sub(x, t2, x)) != CRYPT_OK) { goto done; }
+ if (mp_cmp_d(x, 0) == LTC_MP_LT) {
+ if ((err = mp_add(x, modulus, x)) != CRYPT_OK) { goto done; }
+ }
+
+ /* T2 = T2 - X */
+ if ((err = mp_sub(t2, x, t2)) != CRYPT_OK) { goto done; }
+ if (mp_cmp_d(t2, 0) == LTC_MP_LT) {
+ if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK) { goto done; }
+ }
+ /* T2 = T2 - X */
+ if ((err = mp_sub(t2, x, t2)) != CRYPT_OK) { goto done; }
+ if (mp_cmp_d(t2, 0) == LTC_MP_LT) {
+ if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK) { goto done; }
+ }
+ /* T2 = T2 * Y */
+ if ((err = mp_mul(t2, y, t2)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* Y = T2 - T1 */
+ if ((err = mp_sub(t2, t1, y)) != CRYPT_OK) { goto done; }
+ if (mp_cmp_d(y, 0) == LTC_MP_LT) {
+ if ((err = mp_add(y, modulus, y)) != CRYPT_OK) { goto done; }
+ }
+ /* Y = Y/2 */
+ if (mp_isodd(y)) {
+ if ((err = mp_add(y, modulus, y)) != CRYPT_OK) { goto done; }
+ }
+ if ((err = mp_div_2(y, y)) != CRYPT_OK) { goto done; }
+
+ if ((err = mp_copy(x, R->x)) != CRYPT_OK) { goto done; }
+ if ((err = mp_copy(y, R->y)) != CRYPT_OK) { goto done; }
+ if ((err = mp_copy(z, R->z)) != CRYPT_OK) { goto done; }
+
+ err = CRYPT_OK;
+done:
+ mp_clear_multi(t1, t2, x, y, z, NULL);
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ltc_ecc_projective_add_point.c,v $ */
+/* $Revision: 1.16 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
+
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_projective_dbl_point.c b/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_projective_dbl_point.c
new file mode 100644
index 00000000000..b990e0a14aa
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/ecc/ltc_ecc_projective_dbl_point.c
@@ -0,0 +1,147 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file ltc_ecc_projective_dbl_point.c
+ ECC Crypto, Tom St Denis
+*/
+
+#if defined(LTC_MECC) && (!defined(LTC_MECC_ACCEL) || defined(LTM_LTC_DESC))
+
+/**
+ Double an ECC point
+ @param P The point to double
+ @param R [out] The destination of the double
+ @param modulus The modulus of the field the ECC curve is in
+ @param mp The "b" value from montgomery_setup()
+ @return CRYPT_OK on success
+*/
+int ltc_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *modulus, void *mp)
+{
+ void *t1, *t2;
+ int err;
+
+ LTC_ARGCHK(P != NULL);
+ LTC_ARGCHK(R != NULL);
+ LTC_ARGCHK(modulus != NULL);
+ LTC_ARGCHK(mp != NULL);
+
+ if ((err = mp_init_multi(&t1, &t2, NULL)) != CRYPT_OK) {
+ return err;
+ }
+
+ if (P != R) {
+ if ((err = mp_copy(P->x, R->x)) != CRYPT_OK) { goto done; }
+ if ((err = mp_copy(P->y, R->y)) != CRYPT_OK) { goto done; }
+ if ((err = mp_copy(P->z, R->z)) != CRYPT_OK) { goto done; }
+ }
+
+ /* t1 = Z * Z */
+ if ((err = mp_sqr(R->z, t1)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* Z = Y * Z */
+ if ((err = mp_mul(R->z, R->y, R->z)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(R->z, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* Z = 2Z */
+ if ((err = mp_add(R->z, R->z, R->z)) != CRYPT_OK) { goto done; }
+ if (mp_cmp(R->z, modulus) != LTC_MP_LT) {
+ if ((err = mp_sub(R->z, modulus, R->z)) != CRYPT_OK) { goto done; }
+ }
+
+ /* T2 = X - T1 */
+ if ((err = mp_sub(R->x, t1, t2)) != CRYPT_OK) { goto done; }
+ if (mp_cmp_d(t2, 0) == LTC_MP_LT) {
+ if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK) { goto done; }
+ }
+ /* T1 = X + T1 */
+ if ((err = mp_add(t1, R->x, t1)) != CRYPT_OK) { goto done; }
+ if (mp_cmp(t1, modulus) != LTC_MP_LT) {
+ if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; }
+ }
+ /* T2 = T1 * T2 */
+ if ((err = mp_mul(t1, t2, t2)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* T1 = 2T2 */
+ if ((err = mp_add(t2, t2, t1)) != CRYPT_OK) { goto done; }
+ if (mp_cmp(t1, modulus) != LTC_MP_LT) {
+ if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; }
+ }
+ /* T1 = T1 + T2 */
+ if ((err = mp_add(t1, t2, t1)) != CRYPT_OK) { goto done; }
+ if (mp_cmp(t1, modulus) != LTC_MP_LT) {
+ if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; }
+ }
+
+ /* Y = 2Y */
+ if ((err = mp_add(R->y, R->y, R->y)) != CRYPT_OK) { goto done; }
+ if (mp_cmp(R->y, modulus) != LTC_MP_LT) {
+ if ((err = mp_sub(R->y, modulus, R->y)) != CRYPT_OK) { goto done; }
+ }
+ /* Y = Y * Y */
+ if ((err = mp_sqr(R->y, R->y)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* T2 = Y * Y */
+ if ((err = mp_sqr(R->y, t2)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* T2 = T2/2 */
+ if (mp_isodd(t2)) {
+ if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK) { goto done; }
+ }
+ if ((err = mp_div_2(t2, t2)) != CRYPT_OK) { goto done; }
+ /* Y = Y * X */
+ if ((err = mp_mul(R->y, R->x, R->y)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK) { goto done; }
+
+ /* X = T1 * T1 */
+ if ((err = mp_sqr(t1, R->x)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(R->x, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* X = X - Y */
+ if ((err = mp_sub(R->x, R->y, R->x)) != CRYPT_OK) { goto done; }
+ if (mp_cmp_d(R->x, 0) == LTC_MP_LT) {
+ if ((err = mp_add(R->x, modulus, R->x)) != CRYPT_OK) { goto done; }
+ }
+ /* X = X - Y */
+ if ((err = mp_sub(R->x, R->y, R->x)) != CRYPT_OK) { goto done; }
+ if (mp_cmp_d(R->x, 0) == LTC_MP_LT) {
+ if ((err = mp_add(R->x, modulus, R->x)) != CRYPT_OK) { goto done; }
+ }
+
+ /* Y = Y - X */
+ if ((err = mp_sub(R->y, R->x, R->y)) != CRYPT_OK) { goto done; }
+ if (mp_cmp_d(R->y, 0) == LTC_MP_LT) {
+ if ((err = mp_add(R->y, modulus, R->y)) != CRYPT_OK) { goto done; }
+ }
+ /* Y = Y * T1 */
+ if ((err = mp_mul(R->y, t1, R->y)) != CRYPT_OK) { goto done; }
+ if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK) { goto done; }
+ /* Y = Y - T2 */
+ if ((err = mp_sub(R->y, t2, R->y)) != CRYPT_OK) { goto done; }
+ if (mp_cmp_d(R->y, 0) == LTC_MP_LT) {
+ if ((err = mp_add(R->y, modulus, R->y)) != CRYPT_OK) { goto done; }
+ }
+
+ err = CRYPT_OK;
+done:
+ mp_clear_multi(t1, t2, NULL);
+ return err;
+}
+#endif
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ltc_ecc_projective_dbl_point.c,v $ */
+/* $Revision: 1.11 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
+
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_mgf1.c b/dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_mgf1.c
new file mode 100644
index 00000000000..e8f6418067c
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_mgf1.c
@@ -0,0 +1,108 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file pkcs_1_mgf1.c
+ The Mask Generation Function (MGF1) for LTC_PKCS #1, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/**
+ Perform LTC_PKCS #1 MGF1 (internal)
+ @param seed The seed for MGF1
+ @param seedlen The length of the seed
+ @param hash_idx The index of the hash desired
+ @param mask [out] The destination
+ @param masklen The length of the mask desired
+ @return CRYPT_OK if successful
+*/
+int pkcs_1_mgf1(int hash_idx,
+ const unsigned char *seed, unsigned long seedlen,
+ unsigned char *mask, unsigned long masklen)
+{
+ unsigned long hLen, x;
+ ulong32 counter;
+ int err;
+ hash_state *md;
+ unsigned char *buf;
+
+ LTC_ARGCHK(seed != NULL);
+ LTC_ARGCHK(mask != NULL);
+
+ /* ensure valid hash */
+ if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+ return err;
+ }
+
+ /* get hash output size */
+ hLen = hash_descriptor[hash_idx].hashsize;
+
+ /* allocate memory */
+ md = XMALLOC(sizeof(hash_state));
+ buf = XMALLOC(hLen);
+ if (md == NULL || buf == NULL) {
+ if (md != NULL) {
+ XFREE(md);
+ }
+ if (buf != NULL) {
+ XFREE(buf);
+ }
+ return CRYPT_MEM;
+ }
+
+ /* start counter */
+ counter = 0;
+
+ while (masklen > 0) {
+ /* handle counter */
+ STORE32H(counter, buf);
+ ++counter;
+
+ /* get hash of seed || counter */
+ if ((err = hash_descriptor[hash_idx].init(md)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ if ((err = hash_descriptor[hash_idx].process(md, seed, seedlen)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ if ((err = hash_descriptor[hash_idx].process(md, buf, 4)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ if ((err = hash_descriptor[hash_idx].done(md, buf)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* store it */
+ for (x = 0; x < hLen && masklen > 0; x++, masklen--) {
+ *mask++ = buf[x];
+ }
+ }
+
+ err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+ zeromem(buf, hLen);
+ zeromem(md, sizeof(hash_state));
+#endif
+
+ XFREE(buf);
+ XFREE(md);
+
+ return err;
+}
+
+#endif /* LTC_PKCS_1 */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/pkcs1/pkcs_1_mgf1.c,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_decode.c b/dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_decode.c
new file mode 100644
index 00000000000..709ab8a8cd2
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_decode.c
@@ -0,0 +1,189 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file pkcs_1_oaep_decode.c
+ OAEP Padding for LTC_PKCS #1, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/**
+ LTC_PKCS #1 v2.00 OAEP decode
+ @param msg The encoded data to decode
+ @param msglen The length of the encoded data (octets)
+ @param lparam The session or system data (can be NULL)
+ @param lparamlen The length of the lparam
+ @param modulus_bitlen The bit length of the RSA modulus
+ @param hash_idx The index of the hash desired
+ @param out [out] Destination of decoding
+ @param outlen [in/out] The max size and resulting size of the decoding
+ @param res [out] Result of decoding, 1==valid, 0==invalid
+ @return CRYPT_OK if successful (even if invalid)
+*/
+int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ unsigned long modulus_bitlen, int hash_idx,
+ unsigned char *out, unsigned long *outlen,
+ int *res)
+{
+ unsigned char *DB, *seed, *mask;
+ unsigned long hLen, x, y, modulus_len;
+ int err;
+
+ LTC_ARGCHK(msg != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(res != NULL);
+
+ /* default to invalid packet */
+ *res = 0;
+
+ /* test valid hash */
+ if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+ return err;
+ }
+ hLen = hash_descriptor[hash_idx].hashsize;
+ modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
+
+ /* test hash/message size */
+ if ((2*hLen >= (modulus_len - 2)) || (msglen != modulus_len)) {
+ return CRYPT_PK_INVALID_SIZE;
+ }
+
+ /* allocate ram for DB/mask/salt of size modulus_len */
+ DB = XMALLOC(modulus_len);
+ mask = XMALLOC(modulus_len);
+ seed = XMALLOC(hLen);
+ if (DB == NULL || mask == NULL || seed == NULL) {
+ if (DB != NULL) {
+ XFREE(DB);
+ }
+ if (mask != NULL) {
+ XFREE(mask);
+ }
+ if (seed != NULL) {
+ XFREE(seed);
+ }
+ return CRYPT_MEM;
+ }
+
+ /* ok so it's now in the form
+
+ 0x00 || maskedseed || maskedDB
+
+ 1 || hLen || modulus_len - hLen - 1
+
+ */
+
+ /* must have leading 0x00 byte */
+ if (msg[0] != 0x00) {
+ err = CRYPT_OK;
+ goto LBL_ERR;
+ }
+
+ /* now read the masked seed */
+ x = 1;
+ XMEMCPY(seed, msg + x, hLen);
+ x += hLen;
+
+ /* now read the masked DB */
+ XMEMCPY(DB, msg + x, modulus_len - hLen - 1);
+ x += modulus_len - hLen - 1;
+
+ /* compute MGF1 of maskedDB (hLen) */
+ if ((err = pkcs_1_mgf1(hash_idx, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* XOR against seed */
+ for (y = 0; y < hLen; y++) {
+ seed[y] ^= mask[y];
+ }
+
+ /* compute MGF1 of seed (k - hlen - 1) */
+ if ((err = pkcs_1_mgf1(hash_idx, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* xor against DB */
+ for (y = 0; y < (modulus_len - hLen - 1); y++) {
+ DB[y] ^= mask[y];
+ }
+
+ /* now DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes */
+
+ /* compute lhash and store it in seed [reuse temps!] */
+ x = modulus_len;
+ if (lparam != NULL) {
+ if ((err = hash_memory(hash_idx, lparam, lparamlen, seed, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ } else {
+ /* can't pass hash_memory a NULL so use DB with zero length */
+ if ((err = hash_memory(hash_idx, DB, 0, seed, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* compare the lhash'es */
+ if (XMEMCMP(seed, DB, hLen) != 0) {
+ err = CRYPT_OK;
+ goto LBL_ERR;
+ }
+
+ /* now zeroes before a 0x01 */
+ for (x = hLen; x < (modulus_len - hLen - 1) && DB[x] == 0x00; x++) {
+ /* step... */
+ }
+
+ /* error out if wasn't 0x01 */
+ if (x == (modulus_len - hLen - 1) || DB[x] != 0x01) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+
+ /* rest is the message (and skip 0x01) */
+ if ((modulus_len - hLen - 1 - ++x) > *outlen) {
+ *outlen = modulus_len - hLen - 1 - x;
+ err = CRYPT_BUFFER_OVERFLOW;
+ goto LBL_ERR;
+ }
+
+ /* copy message */
+ *outlen = modulus_len - hLen - 1 - x;
+ XMEMCPY(out, DB + x, modulus_len - hLen - 1 - x);
+ x += modulus_len - hLen - 1;
+
+ /* valid packet */
+ *res = 1;
+
+ err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+ zeromem(DB, modulus_len);
+ zeromem(seed, hLen);
+ zeromem(mask, modulus_len);
+#endif
+
+ XFREE(seed);
+ XFREE(mask);
+ XFREE(DB);
+
+ return err;
+}
+
+#endif /* LTC_PKCS_1 */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_decode.c,v $ */
+/* $Revision: 1.13 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_decode.c b/dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_decode.c
new file mode 100644
index 00000000000..c3a7211ef9c
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_decode.c
@@ -0,0 +1,177 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file pkcs_1_pss_decode.c
+ LTC_PKCS #1 PSS Signature Padding, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/**
+ LTC_PKCS #1 v2.00 PSS decode
+ @param msghash The hash to verify
+ @param msghashlen The length of the hash (octets)
+ @param sig The signature data (encoded data)
+ @param siglen The length of the signature data (octets)
+ @param saltlen The length of the salt used (octets)
+ @param hash_idx The index of the hash desired
+ @param modulus_bitlen The bit length of the RSA modulus
+ @param res [out] The result of the comparison, 1==valid, 0==invalid
+ @return CRYPT_OK if successful (even if the comparison failed)
+*/
+int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
+ const unsigned char *sig, unsigned long siglen,
+ unsigned long saltlen, int hash_idx,
+ unsigned long modulus_bitlen, int *res)
+{
+ unsigned char *DB, *mask, *salt, *hash;
+ unsigned long x, y, hLen, modulus_len;
+ int err;
+ hash_state md;
+
+ LTC_ARGCHK(msghash != NULL);
+ LTC_ARGCHK(res != NULL);
+
+ /* default to invalid */
+ *res = 0;
+
+ /* ensure hash is valid */
+ if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+ return err;
+ }
+
+ hLen = hash_descriptor[hash_idx].hashsize;
+ modulus_len = (modulus_bitlen>>3) + (modulus_bitlen & 7 ? 1 : 0);
+
+ /* check sizes */
+ if ((saltlen > modulus_len) ||
+ (modulus_len < hLen + saltlen + 2) || (siglen != modulus_len)) {
+ return CRYPT_PK_INVALID_SIZE;
+ }
+
+ /* allocate ram for DB/mask/salt/hash of size modulus_len */
+ DB = XMALLOC(modulus_len);
+ mask = XMALLOC(modulus_len);
+ salt = XMALLOC(modulus_len);
+ hash = XMALLOC(modulus_len);
+ if (DB == NULL || mask == NULL || salt == NULL || hash == NULL) {
+ if (DB != NULL) {
+ XFREE(DB);
+ }
+ if (mask != NULL) {
+ XFREE(mask);
+ }
+ if (salt != NULL) {
+ XFREE(salt);
+ }
+ if (hash != NULL) {
+ XFREE(hash);
+ }
+ return CRYPT_MEM;
+ }
+
+ /* ensure the 0xBC byte */
+ if (sig[siglen-1] != 0xBC) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+
+ /* copy out the DB */
+ x = 0;
+ XMEMCPY(DB, sig + x, modulus_len - hLen - 1);
+ x += modulus_len - hLen - 1;
+
+ /* copy out the hash */
+ XMEMCPY(hash, sig + x, hLen);
+ x += hLen;
+
+ /* check the MSB */
+ if ((sig[0] & ~(0xFF >> ((modulus_len<<3) - (modulus_bitlen-1)))) != 0) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+
+ /* generate mask of length modulus_len - hLen - 1 from hash */
+ if ((err = pkcs_1_mgf1(hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* xor against DB */
+ for (y = 0; y < (modulus_len - hLen - 1); y++) {
+ DB[y] ^= mask[y];
+ }
+
+ /* now clear the first byte [make sure smaller than modulus] */
+ DB[0] &= 0xFF >> ((modulus_len<<3) - (modulus_bitlen-1));
+
+ /* DB = PS || 0x01 || salt, PS == modulus_len - saltlen - hLen - 2 zero bytes */
+
+ /* check for zeroes and 0x01 */
+ for (x = 0; x < modulus_len - saltlen - hLen - 2; x++) {
+ if (DB[x] != 0x00) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+ }
+
+ /* check for the 0x01 */
+ if (DB[x++] != 0x01) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+
+ /* M = (eight) 0x00 || msghash || salt, mask = H(M) */
+ if ((err = hash_descriptor[hash_idx].init(&md)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ zeromem(mask, 8);
+ if ((err = hash_descriptor[hash_idx].process(&md, mask, 8)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ if ((err = hash_descriptor[hash_idx].process(&md, msghash, msghashlen)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ if ((err = hash_descriptor[hash_idx].process(&md, DB+x, saltlen)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ if ((err = hash_descriptor[hash_idx].done(&md, mask)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* mask == hash means valid signature */
+ if (XMEMCMP(mask, hash, hLen) == 0) {
+ *res = 1;
+ }
+
+ err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+ zeromem(DB, modulus_len);
+ zeromem(mask, modulus_len);
+ zeromem(salt, modulus_len);
+ zeromem(hash, modulus_len);
+#endif
+
+ XFREE(hash);
+ XFREE(salt);
+ XFREE(mask);
+ XFREE(DB);
+
+ return err;
+}
+
+#endif /* LTC_PKCS_1 */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_decode.c,v $ */
+/* $Revision: 1.11 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_decode.c b/dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_decode.c
new file mode 100644
index 00000000000..7c3711c17c9
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_decode.c
@@ -0,0 +1,110 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/** @file pkcs_1_v1_5_decode.c
+ *
+ * LTC_PKCS #1 v1.5 Padding. (Andreas Lange)
+ */
+
+#ifdef LTC_PKCS_1
+
+/** @brief LTC_PKCS #1 v1.5 decode.
+ *
+ * @param msg The encoded data to decode
+ * @param msglen The length of the encoded data (octets)
+ * @param block_type Block type to use in padding (\sa ltc_pkcs_1_v1_5_blocks)
+ * @param modulus_bitlen The bit length of the RSA modulus
+ * @param out [out] Destination of decoding
+ * @param outlen [in/out] The max size and resulting size of the decoding
+ * @param is_valid [out] Boolean whether the padding was valid
+ *
+ * @return CRYPT_OK if successful (even if invalid)
+ */
+int pkcs_1_v1_5_decode(const unsigned char *msg,
+ unsigned long msglen,
+ int block_type,
+ unsigned long modulus_bitlen,
+ unsigned char *out,
+ unsigned long *outlen,
+ int *is_valid)
+{
+ unsigned long modulus_len, ps_len, i;
+ int result;
+
+ /* default to invalid packet */
+ *is_valid = 0;
+
+ modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
+
+ /* test message size */
+
+ if ((msglen > modulus_len) || (modulus_len < 11)) {
+ return CRYPT_PK_INVALID_SIZE;
+ }
+
+ /* separate encoded message */
+
+ if ((msg[0] != 0x00) || (msg[1] != (unsigned char)block_type)) {
+ result = CRYPT_INVALID_PACKET;
+ goto bail;
+ }
+
+ if (block_type == LTC_LTC_PKCS_1_EME) {
+ for (i = 2; i < modulus_len; i++) {
+ /* separator */
+ if (msg[i] == 0x00) { break; }
+ }
+ ps_len = i++ - 2;
+
+ if ((i >= modulus_len) || (ps_len < 8)) {
+ /* There was no octet with hexadecimal value 0x00 to separate ps from m,
+ * or the length of ps is less than 8 octets.
+ */
+ result = CRYPT_INVALID_PACKET;
+ goto bail;
+ }
+ } else {
+ for (i = 2; i < modulus_len - 1; i++) {
+ if (msg[i] != 0xFF) { break; }
+ }
+
+ /* separator check */
+ if (msg[i] != 0) {
+ /* There was no octet with hexadecimal value 0x00 to separate ps from m. */
+ result = CRYPT_INVALID_PACKET;
+ goto bail;
+ }
+
+ ps_len = i - 2;
+ }
+
+ if (*outlen < (msglen - (2 + ps_len + 1))) {
+ *outlen = msglen - (2 + ps_len + 1);
+ result = CRYPT_BUFFER_OVERFLOW;
+ goto bail;
+ }
+
+ *outlen = (msglen - (2 + ps_len + 1));
+ XMEMCPY(out, &msg[2 + ps_len + 1], *outlen);
+
+ /* valid packet */
+ *is_valid = 1;
+ result = CRYPT_OK;
+bail:
+ return result;
+} /* pkcs_1_v1_5_decode */
+
+#endif /* #ifdef LTC_PKCS_1 */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_decode.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_exptmod.c b/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_exptmod.c
new file mode 100644
index 00000000000..ba44106f2b7
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_exptmod.c
@@ -0,0 +1,113 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file rsa_exptmod.c
+ RSA LTC_PKCS exptmod, Tom St Denis
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ Compute an RSA modular exponentiation
+ @param in The input data to send into RSA
+ @param inlen The length of the input (octets)
+ @param out [out] The destination
+ @param outlen [in/out] The max size and resulting size of the output
+ @param which Which exponent to use, e.g. PK_PRIVATE or PK_PUBLIC
+ @param key The RSA key to use
+ @return CRYPT_OK if successful
+*/
+int rsa_exptmod(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen, int which,
+ rsa_key *key)
+{
+ void *tmp, *tmpa, *tmpb;
+ unsigned long x;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ /* is the key of the right type for the operation? */
+ if (which == PK_PRIVATE && (key->type != PK_PRIVATE)) {
+ return CRYPT_PK_NOT_PRIVATE;
+ }
+
+ /* must be a private or public operation */
+ if (which != PK_PRIVATE && which != PK_PUBLIC) {
+ return CRYPT_PK_INVALID_TYPE;
+ }
+
+ /* init and copy into tmp */
+ if ((err = mp_init_multi(&tmp, &tmpa, &tmpb, NULL)) != CRYPT_OK) { return err; }
+ if ((err = mp_read_unsigned_bin(tmp, (unsigned char *)in, (int)inlen)) != CRYPT_OK) { goto error; }
+
+ /* sanity check on the input */
+ if (mp_cmp(key->N, tmp) == LTC_MP_LT) {
+ err = CRYPT_PK_INVALID_SIZE;
+ goto error;
+ }
+
+ /* are we using the private exponent and is the key optimized? */
+ if (which == PK_PRIVATE) {
+ /* tmpa = tmp^dP mod p */
+ if ((err = mp_exptmod(tmp, key->dP, key->p, tmpa)) != CRYPT_OK) { goto error; }
+
+ /* tmpb = tmp^dQ mod q */
+ if ((err = mp_exptmod(tmp, key->dQ, key->q, tmpb)) != CRYPT_OK) { goto error; }
+
+ /* tmp = (tmpa - tmpb) * qInv (mod p) */
+ if ((err = mp_sub(tmpa, tmpb, tmp)) != CRYPT_OK) { goto error; }
+ if ((err = mp_mulmod(tmp, key->qP, key->p, tmp)) != CRYPT_OK) { goto error; }
+
+ /* tmp = tmpb + q * tmp */
+ if ((err = mp_mul(tmp, key->q, tmp)) != CRYPT_OK) { goto error; }
+ if ((err = mp_add(tmp, tmpb, tmp)) != CRYPT_OK) { goto error; }
+ } else {
+ /* exptmod it */
+ if ((err = mp_exptmod(tmp, key->e, key->N, tmp)) != CRYPT_OK) { goto error; }
+ }
+
+ /* read it back */
+ x = (unsigned long)mp_unsigned_bin_size(key->N);
+ if (x > *outlen) {
+ *outlen = x;
+ err = CRYPT_BUFFER_OVERFLOW;
+ goto error;
+ }
+
+ /* this should never happen ... */
+ if (mp_unsigned_bin_size(tmp) > mp_unsigned_bin_size(key->N)) {
+ err = CRYPT_ERROR;
+ goto error;
+ }
+ *outlen = x;
+
+ /* convert it */
+ zeromem(out, x);
+ if ((err = mp_to_unsigned_bin(tmp, out+(x-mp_unsigned_bin_size(tmp)))) != CRYPT_OK) { goto error; }
+
+ /* clean up and return */
+ err = CRYPT_OK;
+error:
+ mp_clear_multi(tmp, tmpa, tmpb, NULL);
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_exptmod.c,v $ */
+/* $Revision: 1.18 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_free.c b/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_free.c
new file mode 100644
index 00000000000..a10ed5928ce
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_free.c
@@ -0,0 +1,34 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file rsa_free.c
+ Free an RSA key, Tom St Denis
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ Free an RSA key from memory
+ @param key The RSA key to free
+*/
+void rsa_free(rsa_key *key)
+{
+ LTC_ARGCHKVD(key != NULL);
+ mp_clear_multi(key->e, key->d, key->N, key->dQ, key->dP, key->qP, key->p, key->q, NULL);
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_free.c,v $ */
+/* $Revision: 1.10 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_import.c b/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_import.c
new file mode 100644
index 00000000000..6254fd7ff86
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_import.c
@@ -0,0 +1,143 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file rsa_import.c
+ Import a LTC_PKCS RSA key, Tom St Denis
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ Import an RSAPublicKey or RSAPrivateKey [two-prime only, only support >= 1024-bit keys, defined in LTC_PKCS #1 v2.1]
+ @param in The packet to import from
+ @param inlen It's length (octets)
+ @param key [out] Destination for newly imported key
+ @return CRYPT_OK if successful, upon error allocated memory is freed
+*/
+int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key)
+{
+ int err;
+ void *zero;
+ unsigned char *tmpbuf;
+ unsigned long t, x, y, z, tmpoid[16];
+ ltc_asn1_list ssl_pubkey_hashoid[2];
+ ltc_asn1_list ssl_pubkey[2];
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(key != NULL);
+ LTC_ARGCHK(ltc_mp.name != NULL);
+
+ /* init key */
+ if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ,
+ &key->dP, &key->qP, &key->p, &key->q, NULL)) != CRYPT_OK) {
+ return err;
+ }
+
+ /* see if the OpenSSL DER format RSA public key will work */
+ tmpbuf = XCALLOC(1, MAX_RSA_SIZE*8);
+ if (tmpbuf == NULL) {
+ err = CRYPT_MEM;
+ goto LBL_ERR;
+ }
+
+ /* this includes the internal hash ID and optional params (NULL in this case) */
+ LTC_SET_ASN1(ssl_pubkey_hashoid, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, sizeof(tmpoid)/sizeof(tmpoid[0]));
+ LTC_SET_ASN1(ssl_pubkey_hashoid, 1, LTC_ASN1_NULL, NULL, 0);
+
+ /* the actual format of the SSL DER key is odd, it stores a RSAPublicKey in a **BIT** string ... so we have to extract it
+ then proceed to convert bit to octet
+ */
+ LTC_SET_ASN1(ssl_pubkey, 0, LTC_ASN1_SEQUENCE, &ssl_pubkey_hashoid, 2);
+ LTC_SET_ASN1(ssl_pubkey, 1, LTC_ASN1_BIT_STRING, tmpbuf, MAX_RSA_SIZE*8);
+
+ if (der_decode_sequence(in, inlen,
+ ssl_pubkey, 2UL) == CRYPT_OK) {
+
+ /* ok now we have to reassemble the BIT STRING to an OCTET STRING. Thanks OpenSSL... */
+ for (t = y = z = x = 0; x < ssl_pubkey[1].size; x++) {
+ y = (y << 1) | tmpbuf[x];
+ if (++z == 8) {
+ tmpbuf[t++] = (unsigned char)y;
+ y = 0;
+ z = 0;
+ }
+ }
+
+ /* now it should be SEQUENCE { INTEGER, INTEGER } */
+ if ((err = der_decode_sequence_multi(tmpbuf, t,
+ LTC_ASN1_INTEGER, 1UL, key->N,
+ LTC_ASN1_INTEGER, 1UL, key->e,
+ LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
+ XFREE(tmpbuf);
+ goto LBL_ERR;
+ }
+ XFREE(tmpbuf);
+ key->type = PK_PUBLIC;
+ return CRYPT_OK;
+ }
+ XFREE(tmpbuf);
+
+ /* not SSL public key, try to match against LTC_PKCS #1 standards */
+ if ((err = der_decode_sequence_multi(in, inlen,
+ LTC_ASN1_INTEGER, 1UL, key->N,
+ LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ if (mp_cmp_d(key->N, 0) == LTC_MP_EQ) {
+ if ((err = mp_init(&zero)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ /* it's a private key */
+ if ((err = der_decode_sequence_multi(in, inlen,
+ LTC_ASN1_INTEGER, 1UL, zero,
+ LTC_ASN1_INTEGER, 1UL, key->N,
+ LTC_ASN1_INTEGER, 1UL, key->e,
+ LTC_ASN1_INTEGER, 1UL, key->d,
+ LTC_ASN1_INTEGER, 1UL, key->p,
+ LTC_ASN1_INTEGER, 1UL, key->q,
+ LTC_ASN1_INTEGER, 1UL, key->dP,
+ LTC_ASN1_INTEGER, 1UL, key->dQ,
+ LTC_ASN1_INTEGER, 1UL, key->qP,
+ LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
+ mp_clear(zero);
+ goto LBL_ERR;
+ }
+ mp_clear(zero);
+ key->type = PK_PRIVATE;
+ } else if (mp_cmp_d(key->N, 1) == LTC_MP_EQ) {
+ /* we don't support multi-prime RSA */
+ err = CRYPT_PK_INVALID_TYPE;
+ goto LBL_ERR;
+ } else {
+ /* it's a public key and we lack e */
+ if ((err = der_decode_sequence_multi(in, inlen,
+ LTC_ASN1_INTEGER, 1UL, key->N,
+ LTC_ASN1_INTEGER, 1UL, key->e,
+ LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ key->type = PK_PUBLIC;
+ }
+ return CRYPT_OK;
+LBL_ERR:
+ mp_clear_multi(key->d, key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, NULL);
+ return err;
+}
+
+#endif /* LTC_MRSA */
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_import.c,v $ */
+/* $Revision: 1.23 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_make_key.c b/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_make_key.c
new file mode 100644
index 00000000000..bd37b4ae1cb
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_make_key.c
@@ -0,0 +1,112 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file rsa_make_key.c
+ RSA key generation, Tom St Denis
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ Create an RSA key
+ @param prng An active PRNG state
+ @param wprng The index of the PRNG desired
+ @param size The size of the modulus (key size) desired (octets)
+ @param e The "e" value (public key). e==65537 is a good choice
+ @param key [out] Destination of a newly created private key pair
+ @return CRYPT_OK if successful, upon error all allocated ram is freed
+*/
+int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key)
+{
+ void *p, *q, *tmp1, *tmp2, *tmp3;
+ int err;
+
+ LTC_ARGCHK(ltc_mp.name != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if ((size < (MIN_RSA_SIZE/8)) || (size > (MAX_RSA_SIZE/8))) {
+ return CRYPT_INVALID_KEYSIZE;
+ }
+
+ if ((e < 3) || ((e & 1) == 0)) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+ return err;
+ }
+
+ if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != CRYPT_OK) {
+ return err;
+ }
+
+ /* make primes p and q (optimization provided by Wayne Scott) */
+ if ((err = mp_set_int(tmp3, e)) != CRYPT_OK) { goto errkey; } /* tmp3 = e */
+
+ /* make prime "p" */
+ do {
+ if ((err = rand_prime( p, size/2, prng, wprng)) != CRYPT_OK) { goto errkey; }
+ if ((err = mp_sub_d( p, 1, tmp1)) != CRYPT_OK) { goto errkey; } /* tmp1 = p-1 */
+ if ((err = mp_gcd( tmp1, tmp3, tmp2)) != CRYPT_OK) { goto errkey; } /* tmp2 = gcd(p-1, e) */
+ } while (mp_cmp_d( tmp2, 1) != 0); /* while e divides p-1 */
+
+ /* make prime "q" */
+ do {
+ if ((err = rand_prime( q, size/2, prng, wprng)) != CRYPT_OK) { goto errkey; }
+ if ((err = mp_sub_d( q, 1, tmp1)) != CRYPT_OK) { goto errkey; } /* tmp1 = q-1 */
+ if ((err = mp_gcd( tmp1, tmp3, tmp2)) != CRYPT_OK) { goto errkey; } /* tmp2 = gcd(q-1, e) */
+ } while (mp_cmp_d( tmp2, 1) != 0); /* while e divides q-1 */
+
+ /* tmp1 = lcm(p-1, q-1) */
+ if ((err = mp_sub_d( p, 1, tmp2)) != CRYPT_OK) { goto errkey; } /* tmp2 = p-1 */
+ /* tmp1 = q-1 (previous do/while loop) */
+ if ((err = mp_lcm( tmp1, tmp2, tmp1)) != CRYPT_OK) { goto errkey; } /* tmp1 = lcm(p-1, q-1) */
+
+ /* make key */
+ if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL)) != CRYPT_OK) {
+ goto errkey;
+ }
+
+ if ((err = mp_set_int( key->e, e)) != CRYPT_OK) { goto errkey; } /* key->e = e */
+ if ((err = mp_invmod( key->e, tmp1, key->d)) != CRYPT_OK) { goto errkey; } /* key->d = 1/e mod lcm(p-1,q-1) */
+ if ((err = mp_mul( p, q, key->N)) != CRYPT_OK) { goto errkey; } /* key->N = pq */
+
+ /* optimize for CRT now */
+ /* find d mod q-1 and d mod p-1 */
+ if ((err = mp_sub_d( p, 1, tmp1)) != CRYPT_OK) { goto errkey; } /* tmp1 = q-1 */
+ if ((err = mp_sub_d( q, 1, tmp2)) != CRYPT_OK) { goto errkey; } /* tmp2 = p-1 */
+ if ((err = mp_mod( key->d, tmp1, key->dP)) != CRYPT_OK) { goto errkey; } /* dP = d mod p-1 */
+ if ((err = mp_mod( key->d, tmp2, key->dQ)) != CRYPT_OK) { goto errkey; } /* dQ = d mod q-1 */
+ if ((err = mp_invmod( q, p, key->qP)) != CRYPT_OK) { goto errkey; } /* qP = 1/q mod p */
+
+ if ((err = mp_copy( p, key->p)) != CRYPT_OK) { goto errkey; }
+ if ((err = mp_copy( q, key->q)) != CRYPT_OK) { goto errkey; }
+
+ /* set key type (in this case it's CRT optimized) */
+ key->type = PK_PRIVATE;
+
+ /* return ok and free temps */
+ err = CRYPT_OK;
+ goto cleanup;
+errkey:
+ mp_clear_multi(key->d, key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, NULL);
+cleanup:
+ mp_clear_multi(tmp3, tmp2, tmp1, p, q, NULL);
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_make_key.c,v $ */
+/* $Revision: 1.16 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_verify_hash.c b/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_verify_hash.c
new file mode 100644
index 00000000000..103ae2f5303
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_verify_hash.c
@@ -0,0 +1,167 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file rsa_verify_hash.c
+ RSA LTC_PKCS #1 v1.5 or v2 PSS signature verification, Tom St Denis and Andreas Lange
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ LTC_PKCS #1 de-sign then v1.5 or PSS depad
+ @param sig The signature data
+ @param siglen The length of the signature data (octets)
+ @param hash The hash of the message that was signed
+ @param hashlen The length of the hash of the message that was signed (octets)
+ @param padding Type of padding (LTC_LTC_PKCS_1_PSS or LTC_LTC_PKCS_1_V1_5)
+ @param hash_idx The index of the desired hash
+ @param saltlen The length of the salt used during signature
+ @param stat [out] The result of the signature comparison, 1==valid, 0==invalid
+ @param key The public RSA key corresponding to the key that performed the signature
+ @return CRYPT_OK on success (even if the signature is invalid)
+*/
+int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int padding,
+ int hash_idx, unsigned long saltlen,
+ int *stat, rsa_key *key)
+{
+ unsigned long modulus_bitlen, modulus_bytelen, x;
+ int err;
+ unsigned char *tmpbuf;
+
+ LTC_ARGCHK(hash != NULL);
+ LTC_ARGCHK(sig != NULL);
+ LTC_ARGCHK(stat != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ /* default to invalid */
+ *stat = 0;
+
+ /* valid padding? */
+
+ if ((padding != LTC_LTC_PKCS_1_V1_5) &&
+ (padding != LTC_LTC_PKCS_1_PSS)) {
+ return CRYPT_PK_INVALID_PADDING;
+ }
+
+ if (padding == LTC_LTC_PKCS_1_PSS) {
+ /* valid hash ? */
+ if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+ return err;
+ }
+ }
+
+ /* get modulus len in bits */
+ modulus_bitlen = mp_count_bits( (key->N));
+
+ /* outlen must be at least the size of the modulus */
+ modulus_bytelen = mp_unsigned_bin_size( (key->N));
+ if (modulus_bytelen != siglen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* allocate temp buffer for decoded sig */
+ tmpbuf = XMALLOC(siglen);
+ if (tmpbuf == NULL) {
+ return CRYPT_MEM;
+ }
+
+ /* RSA decode it */
+ x = siglen;
+ if ((err = ltc_mp.rsa_me(sig, siglen, tmpbuf, &x, PK_PUBLIC, key)) != CRYPT_OK) {
+ XFREE(tmpbuf);
+ return err;
+ }
+
+ /* make sure the output is the right size */
+ if (x != siglen) {
+ XFREE(tmpbuf);
+ return CRYPT_INVALID_PACKET;
+ }
+
+ if (padding == LTC_LTC_PKCS_1_PSS) {
+ /* PSS decode and verify it */
+ err = pkcs_1_pss_decode(hash, hashlen, tmpbuf, x, saltlen, hash_idx, modulus_bitlen, stat);
+ } else {
+ /* LTC_PKCS #1 v1.5 decode it */
+ unsigned char *out;
+ unsigned long outlen, loid[16];
+ int decoded;
+ ltc_asn1_list digestinfo[2], siginfo[2];
+
+ /* not all hashes have OIDs... so sad */
+ if (hash_descriptor[hash_idx].OIDlen == 0) {
+ err = CRYPT_INVALID_ARG;
+ goto bail_2;
+ }
+
+ /* allocate temp buffer for decoded hash */
+ outlen = ((modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0)) - 3;
+ out = XMALLOC(outlen);
+ if (out == NULL) {
+ err = CRYPT_MEM;
+ goto bail_2;
+ }
+
+ if ((err = pkcs_1_v1_5_decode(tmpbuf, x, LTC_LTC_PKCS_1_EMSA, modulus_bitlen, out, &outlen, &decoded)) != CRYPT_OK) {
+ XFREE(out);
+ goto bail_2;
+ }
+
+ /* now we must decode out[0...outlen-1] using ASN.1, test the OID and then test the hash */
+ /* construct the SEQUENCE
+ SEQUENCE {
+ SEQUENCE {hashoid OID
+ blah NULL
+ }
+ hash OCTET STRING
+ }
+ */
+ LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, loid, sizeof(loid)/sizeof(loid[0]));
+ LTC_SET_ASN1(digestinfo, 1, LTC_ASN1_NULL, NULL, 0);
+ LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE, digestinfo, 2);
+ LTC_SET_ASN1(siginfo, 1, LTC_ASN1_OCTET_STRING, tmpbuf, siglen);
+
+ if ((err = der_decode_sequence(out, outlen, siginfo, 2)) != CRYPT_OK) {
+ XFREE(out);
+ goto bail_2;
+ }
+
+ /* test OID */
+ if ((digestinfo[0].size == hash_descriptor[hash_idx].OIDlen) &&
+ (XMEMCMP(digestinfo[0].data, hash_descriptor[hash_idx].OID, sizeof(unsigned long) * hash_descriptor[hash_idx].OIDlen) == 0) &&
+ (siginfo[1].size == hashlen) &&
+ (XMEMCMP(siginfo[1].data, hash, hashlen) == 0)) {
+ *stat = 1;
+ }
+
+#ifdef LTC_CLEAN_STACK
+ zeromem(out, outlen);
+#endif
+ XFREE(out);
+ }
+
+bail_2:
+#ifdef LTC_CLEAN_STACK
+ zeromem(tmpbuf, siglen);
+#endif
+ XFREE(tmpbuf);
+ return err;
+}
+
+#endif /* LTC_MRSA */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_verify_hash.c,v $ */
+/* $Revision: 1.13 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_verify_simple.c b/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_verify_simple.c
new file mode 100644
index 00000000000..6d8888c858d
--- /dev/null
+++ b/dep/StormLib/src/libtomcrypt/src/pk/rsa/rsa_verify_simple.c
@@ -0,0 +1,87 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "../../headers/tomcrypt.h"
+
+/**
+ @file rsa_verify_simple.c
+ Created by Ladislav Zezula (zezula@volny.cz) as modification
+ for Blizzard strong signature verification
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ Simple RSA decryption
+ @param sig The signature data
+ @param siglen The length of the signature data (octets)
+ @param hash The hash of the message that was signed
+ @param hashlen The length of the hash of the message that was signed (octets)
+ @param stat [out] The result of the signature comparison, 1==valid, 0==invalid
+ @param key The public RSA key corresponding
+ @return Error code
+*/
+int rsa_verify_simple(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int *stat,
+ rsa_key *key)
+{
+ unsigned long modulus_bitlen, modulus_bytelen, x;
+ unsigned char *tmpbuf;
+ int err;
+
+ LTC_ARGCHK(sig != NULL);
+ LTC_ARGCHK(hash != NULL);
+ LTC_ARGCHK(stat != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ /* default to invalid */
+ *stat = 0;
+
+ /* get modulus len in bits */
+ modulus_bitlen = mp_count_bits( (key->N));
+
+ /* outlen must be at least the size of the modulus */
+ modulus_bytelen = mp_unsigned_bin_size( (key->N));
+ if (modulus_bytelen != siglen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* allocate temp buffer for decoded sig */
+ tmpbuf = XMALLOC(siglen);
+ if (tmpbuf == NULL) {
+ return CRYPT_MEM;
+ }
+
+ /* RSA decode it */
+ x = siglen;
+ if ((err = ltc_mp.rsa_me(sig, siglen, tmpbuf, &x, PK_PUBLIC, key)) != CRYPT_OK) {
+ XFREE(tmpbuf);
+ return err;
+ }
+
+ /* make sure the output is the right size */
+ if (x != siglen) {
+ XFREE(tmpbuf);
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* compare the decrypted signature with the given hash */
+ if(x == hashlen && XMEMCMP(tmpbuf, hash, hashlen) == 0)
+ *stat = 1;
+
+#ifdef LTC_CLEAN_STACK
+ zeromem(tmpbuf, siglen);
+#endif
+ XFREE(tmpbuf);
+ return CRYPT_OK;
+}
+
+#endif /* LTC_MRSA */
diff --git a/dep/StormLib/src/libtommath/bn_fast_mp_invmod.c b/dep/StormLib/src/libtommath/bn_fast_mp_invmod.c
new file mode 100644
index 00000000000..597d7a9b5fa
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_fast_mp_invmod.c
@@ -0,0 +1,148 @@
+#include "tommath.h"
+#ifdef BN_FAST_MP_INVMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes the modular inverse via binary extended euclidean algorithm,
+ * that is c = 1/a mod b
+ *
+ * Based on slow invmod except this is optimized for the case where b is
+ * odd as per HAC Note 14.64 on pp. 610
+ */
+int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int x, y, u, v, B, D;
+ int res, neg;
+
+ /* 2. [modified] b must be odd */
+ if (mp_iseven (b) == 1) {
+ return MP_VAL;
+ }
+
+ /* init all our temps */
+ if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) {
+ return res;
+ }
+
+ /* x == modulus, y == value to invert */
+ if ((res = mp_copy (b, &x)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* we need y = |a| */
+ if ((res = mp_mod (a, b, &y)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+ if ((res = mp_copy (&x, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_copy (&y, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ mp_set (&D, 1);
+
+top:
+ /* 4. while u is even do */
+ while (mp_iseven (&u) == 1) {
+ /* 4.1 u = u/2 */
+ if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* 4.2 if B is odd then */
+ if (mp_isodd (&B) == 1) {
+ if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* B = B/2 */
+ if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* 5. while v is even do */
+ while (mp_iseven (&v) == 1) {
+ /* 5.1 v = v/2 */
+ if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* 5.2 if D is odd then */
+ if (mp_isodd (&D) == 1) {
+ /* D = (D-x)/2 */
+ if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* D = D/2 */
+ if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* 6. if u >= v then */
+ if (mp_cmp (&u, &v) != MP_LT) {
+ /* u = u - v, B = B - D */
+ if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ } else {
+ /* v - v - u, D = D - B */
+ if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* if not zero goto step 4 */
+ if (mp_iszero (&u) == 0) {
+ goto top;
+ }
+
+ /* now a = C, b = D, gcd == g*v */
+
+ /* if v != 1 then there is no inverse */
+ if (mp_cmp_d (&v, 1) != MP_EQ) {
+ res = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* b is now the inverse */
+ neg = a->sign;
+ while (D.sign == MP_NEG) {
+ if ((res = mp_add (&D, b, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ mp_exch (&D, c);
+ c->sign = neg;
+ res = MP_OKAY;
+
+LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &B, &D, NULL);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_fast_mp_invmod.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_fast_mp_montgomery_reduce.c b/dep/StormLib/src/libtommath/bn_fast_mp_montgomery_reduce.c
new file mode 100644
index 00000000000..65eed7da1fe
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_fast_mp_montgomery_reduce.c
@@ -0,0 +1,172 @@
+#include "tommath.h"
+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes xR**-1 == x (mod N) via Montgomery Reduction
+ *
+ * This is an optimized implementation of montgomery_reduce
+ * which uses the comba method to quickly calculate the columns of the
+ * reduction.
+ *
+ * Based on Algorithm 14.32 on pp.601 of HAC.
+*/
+int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+{
+ int ix, res, olduse;
+ mp_word W[MP_WARRAY];
+
+ /* get old used count */
+ olduse = x->used;
+
+ /* grow a as required */
+ if (x->alloc < n->used + 1) {
+ if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* first we have to get the digits of the input into
+ * an array of double precision words W[...]
+ */
+ {
+ register mp_word *_W;
+ register mp_digit *tmpx;
+
+ /* alias for the W[] array */
+ _W = W;
+
+ /* alias for the digits of x*/
+ tmpx = x->dp;
+
+ /* copy the digits of a into W[0..a->used-1] */
+ for (ix = 0; ix < x->used; ix++) {
+ *_W++ = *tmpx++;
+ }
+
+ /* zero the high words of W[a->used..m->used*2] */
+ for (; ix < n->used * 2 + 1; ix++) {
+ *_W++ = 0;
+ }
+ }
+
+ /* now we proceed to zero successive digits
+ * from the least significant upwards
+ */
+ for (ix = 0; ix < n->used; ix++) {
+ /* mu = ai * m' mod b
+ *
+ * We avoid a double precision multiplication (which isn't required)
+ * by casting the value down to a mp_digit. Note this requires
+ * that W[ix-1] have the carry cleared (see after the inner loop)
+ */
+ register mp_digit mu;
+ mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
+
+ /* a = a + mu * m * b**i
+ *
+ * This is computed in place and on the fly. The multiplication
+ * by b**i is handled by offseting which columns the results
+ * are added to.
+ *
+ * Note the comba method normally doesn't handle carries in the
+ * inner loop In this case we fix the carry from the previous
+ * column since the Montgomery reduction requires digits of the
+ * result (so far) [see above] to work. This is
+ * handled by fixing up one carry after the inner loop. The
+ * carry fixups are done in order so after these loops the
+ * first m->used words of W[] have the carries fixed
+ */
+ {
+ register int iy;
+ register mp_digit *tmpn;
+ register mp_word *_W;
+
+ /* alias for the digits of the modulus */
+ tmpn = n->dp;
+
+ /* Alias for the columns set by an offset of ix */
+ _W = W + ix;
+
+ /* inner loop */
+ for (iy = 0; iy < n->used; iy++) {
+ *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
+ }
+ }
+
+ /* now fix carry for next digit, W[ix+1] */
+ W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
+ }
+
+ /* now we have to propagate the carries and
+ * shift the words downward [all those least
+ * significant digits we zeroed].
+ */
+ {
+ register mp_digit *tmpx;
+ register mp_word *_W, *_W1;
+
+ /* nox fix rest of carries */
+
+ /* alias for current word */
+ _W1 = W + ix;
+
+ /* alias for next word, where the carry goes */
+ _W = W + ++ix;
+
+ for (; ix <= n->used * 2 + 1; ix++) {
+ *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
+ }
+
+ /* copy out, A = A/b**n
+ *
+ * The result is A/b**n but instead of converting from an
+ * array of mp_word to mp_digit than calling mp_rshd
+ * we just copy them in the right order
+ */
+
+ /* alias for destination word */
+ tmpx = x->dp;
+
+ /* alias for shifted double precision result */
+ _W = W + n->used;
+
+ for (ix = 0; ix < n->used + 1; ix++) {
+ *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
+ }
+
+ /* zero oldused digits, if the input a was larger than
+ * m->used+1 we'll have to clear the digits
+ */
+ for (; ix < olduse; ix++) {
+ *tmpx++ = 0;
+ }
+ }
+
+ /* set the max used and clamp */
+ x->used = n->used + 1;
+ mp_clamp (x);
+
+ /* if A >= m then A = A - m */
+ if (mp_cmp_mag (x, n) != MP_LT) {
+ return s_mp_sub (x, n, x);
+ }
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_fast_mp_montgomery_reduce.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_fast_s_mp_mul_digs.c b/dep/StormLib/src/libtommath/bn_fast_s_mp_mul_digs.c
new file mode 100644
index 00000000000..df83f89ecab
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_fast_s_mp_mul_digs.c
@@ -0,0 +1,107 @@
+#include "tommath.h"
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Fast (comba) multiplier
+ *
+ * This is the fast column-array [comba] multiplier. It is
+ * designed to compute the columns of the product first
+ * then handle the carries afterwards. This has the effect
+ * of making the nested loops that compute the columns very
+ * simple and schedulable on super-scalar processors.
+ *
+ * This has been modified to produce a variable number of
+ * digits of output so if say only a half-product is required
+ * you don't have to compute the upper half (a feature
+ * required for fast Barrett reduction).
+ *
+ * Based on Algorithm 14.12 on pp.595 of HAC.
+ *
+ */
+int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+ int olduse, res, pa, ix, iz;
+ mp_digit W[MP_WARRAY];
+ register mp_word _W;
+
+ /* grow the destination as required */
+ if (c->alloc < digs) {
+ if ((res = mp_grow (c, digs)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* number of output digits to produce */
+ pa = MIN(digs, a->used + b->used);
+
+ /* clear the carry */
+ _W = 0;
+ for (ix = 0; ix < pa; ix++) {
+ int tx, ty;
+ int iy;
+ mp_digit *tmpx, *tmpy;
+
+ /* get offsets into the two bignums */
+ ty = MIN(b->used-1, ix);
+ tx = ix - ty;
+
+ /* setup temp aliases */
+ tmpx = a->dp + tx;
+ tmpy = b->dp + ty;
+
+ /* this is the number of times the loop will iterrate, essentially
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MIN(a->used-tx, ty+1);
+
+ /* execute loop */
+ for (iz = 0; iz < iy; ++iz) {
+ _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+
+ }
+
+ /* store term */
+ W[ix] = ((mp_digit)_W) & MP_MASK;
+
+ /* make next carry */
+ _W = _W >> ((mp_word)DIGIT_BIT);
+ }
+
+ /* setup dest */
+ olduse = c->used;
+ c->used = pa;
+
+ {
+ register mp_digit *tmpc;
+ tmpc = c->dp;
+ for (ix = 0; ix < pa+1; ix++) {
+ /* now extract the previous digit [below the carry] */
+ *tmpc++ = W[ix];
+ }
+
+ /* clear unused digits [that existed in the old copy of c] */
+ for (; ix < olduse; ix++) {
+ *tmpc++ = 0;
+ }
+ }
+ mp_clamp (c);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_fast_s_mp_mul_digs.c,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_fast_s_mp_mul_high_digs.c b/dep/StormLib/src/libtommath/bn_fast_s_mp_mul_high_digs.c
new file mode 100644
index 00000000000..6866aab7529
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_fast_s_mp_mul_high_digs.c
@@ -0,0 +1,98 @@
+#include "tommath.h"
+#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* this is a modified version of fast_s_mul_digs that only produces
+ * output digits *above* digs. See the comments for fast_s_mul_digs
+ * to see how it works.
+ *
+ * This is used in the Barrett reduction since for one of the multiplications
+ * only the higher digits were needed. This essentially halves the work.
+ *
+ * Based on Algorithm 14.12 on pp.595 of HAC.
+ */
+int fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+ int olduse, res, pa, ix, iz;
+ mp_digit W[MP_WARRAY];
+ mp_word _W;
+
+ /* grow the destination as required */
+ pa = a->used + b->used;
+ if (c->alloc < pa) {
+ if ((res = mp_grow (c, pa)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* number of output digits to produce */
+ pa = a->used + b->used;
+ _W = 0;
+ for (ix = digs; ix < pa; ix++) {
+ int tx, ty, iy;
+ mp_digit *tmpx, *tmpy;
+
+ /* get offsets into the two bignums */
+ ty = MIN(b->used-1, ix);
+ tx = ix - ty;
+
+ /* setup temp aliases */
+ tmpx = a->dp + tx;
+ tmpy = b->dp + ty;
+
+ /* this is the number of times the loop will iterrate, essentially its
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MIN(a->used-tx, ty+1);
+
+ /* execute loop */
+ for (iz = 0; iz < iy; iz++) {
+ _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+ }
+
+ /* store term */
+ W[ix] = ((mp_digit)_W) & MP_MASK;
+
+ /* make next carry */
+ _W = _W >> ((mp_word)DIGIT_BIT);
+ }
+
+ /* setup dest */
+ olduse = c->used;
+ c->used = pa;
+
+ {
+ register mp_digit *tmpc;
+
+ tmpc = c->dp + digs;
+ for (ix = digs; ix < pa; ix++) {
+ /* now extract the previous digit [below the carry] */
+ *tmpc++ = W[ix];
+ }
+
+ /* clear unused digits [that existed in the old copy of c] */
+ for (; ix < olduse; ix++) {
+ *tmpc++ = 0;
+ }
+ }
+ mp_clamp (c);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_fast_s_mp_mul_high_digs.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_fast_s_mp_sqr.c b/dep/StormLib/src/libtommath/bn_fast_s_mp_sqr.c
new file mode 100644
index 00000000000..5f9d58cac62
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_fast_s_mp_sqr.c
@@ -0,0 +1,114 @@
+#include "tommath.h"
+#ifdef BN_FAST_S_MP_SQR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* the jist of squaring...
+ * you do like mult except the offset of the tmpx [one that
+ * starts closer to zero] can't equal the offset of tmpy.
+ * So basically you set up iy like before then you min it with
+ * (ty-tx) so that it never happens. You double all those
+ * you add in the inner loop
+
+After that loop you do the squares and add them in.
+*/
+
+int fast_s_mp_sqr (mp_int * a, mp_int * b)
+{
+ int olduse, res, pa, ix, iz;
+ mp_digit W[MP_WARRAY], *tmpx;
+ mp_word W1;
+
+ /* grow the destination as required */
+ pa = a->used + a->used;
+ if (b->alloc < pa) {
+ if ((res = mp_grow (b, pa)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* number of output digits to produce */
+ W1 = 0;
+ for (ix = 0; ix < pa; ix++) {
+ int tx, ty, iy;
+ mp_word _W;
+ mp_digit *tmpy;
+
+ /* clear counter */
+ _W = 0;
+
+ /* get offsets into the two bignums */
+ ty = MIN(a->used-1, ix);
+ tx = ix - ty;
+
+ /* setup temp aliases */
+ tmpx = a->dp + tx;
+ tmpy = a->dp + ty;
+
+ /* this is the number of times the loop will iterrate, essentially
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MIN(a->used-tx, ty+1);
+
+ /* now for squaring tx can never equal ty
+ * we halve the distance since they approach at a rate of 2x
+ * and we have to round because odd cases need to be executed
+ */
+ iy = MIN(iy, (ty-tx+1)>>1);
+
+ /* execute loop */
+ for (iz = 0; iz < iy; iz++) {
+ _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+ }
+
+ /* double the inner product and add carry */
+ _W = _W + _W + W1;
+
+ /* even columns have the square term in them */
+ if ((ix&1) == 0) {
+ _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
+ }
+
+ /* store it */
+ W[ix] = (mp_digit)(_W & MP_MASK);
+
+ /* make next carry */
+ W1 = _W >> ((mp_word)DIGIT_BIT);
+ }
+
+ /* setup dest */
+ olduse = b->used;
+ b->used = a->used+a->used;
+
+ {
+ mp_digit *tmpb;
+ tmpb = b->dp;
+ for (ix = 0; ix < pa; ix++) {
+ *tmpb++ = W[ix] & MP_MASK;
+ }
+
+ /* clear unused digits [that existed in the old copy of c] */
+ for (; ix < olduse; ix++) {
+ *tmpb++ = 0;
+ }
+ }
+ mp_clamp (b);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_fast_s_mp_sqr.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_2expt.c b/dep/StormLib/src/libtommath/bn_mp_2expt.c
new file mode 100644
index 00000000000..f899eaee43e
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_2expt.c
@@ -0,0 +1,48 @@
+#include "tommath.h"
+#ifdef BN_MP_2EXPT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes a = 2**b
+ *
+ * Simple algorithm which zeroes the int, grows it then just sets one bit
+ * as required.
+ */
+int
+mp_2expt (mp_int * a, int b)
+{
+ int res;
+
+ /* zero a as per default */
+ mp_zero (a);
+
+ /* grow a to accomodate the single bit */
+ if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
+ return res;
+ }
+
+ /* set the used count of where the bit will go */
+ a->used = b / DIGIT_BIT + 1;
+
+ /* put the single bit in its place */
+ a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_2expt.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_abs.c b/dep/StormLib/src/libtommath/bn_mp_abs.c
new file mode 100644
index 00000000000..14f3a7e074d
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_abs.c
@@ -0,0 +1,43 @@
+#include "tommath.h"
+#ifdef BN_MP_ABS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* b = |a|
+ *
+ * Simple function copies the input and fixes the sign to positive
+ */
+int
+mp_abs (mp_int * a, mp_int * b)
+{
+ int res;
+
+ /* copy a to b */
+ if (a != b) {
+ if ((res = mp_copy (a, b)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* force the sign of b to positive */
+ b->sign = MP_ZPOS;
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_abs.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_add.c b/dep/StormLib/src/libtommath/bn_mp_add.c
new file mode 100644
index 00000000000..b368b21c7cb
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_add.c
@@ -0,0 +1,53 @@
+#include "tommath.h"
+#ifdef BN_MP_ADD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* high level addition (handles signs) */
+int mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+ int sa, sb, res;
+
+ /* get sign of both inputs */
+ sa = a->sign;
+ sb = b->sign;
+
+ /* handle two cases, not four */
+ if (sa == sb) {
+ /* both positive or both negative */
+ /* add their magnitudes, copy the sign */
+ c->sign = sa;
+ res = s_mp_add (a, b, c);
+ } else {
+ /* one positive, the other negative */
+ /* subtract the one with the greater magnitude from */
+ /* the one of the lesser magnitude. The result gets */
+ /* the sign of the one with the greater magnitude. */
+ if (mp_cmp_mag (a, b) == MP_LT) {
+ c->sign = sb;
+ res = s_mp_sub (b, a, c);
+ } else {
+ c->sign = sa;
+ res = s_mp_sub (a, b, c);
+ }
+ }
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_add.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_add_d.c b/dep/StormLib/src/libtommath/bn_mp_add_d.c
new file mode 100644
index 00000000000..c147554bdb8
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_add_d.c
@@ -0,0 +1,112 @@
+#include "tommath.h"
+#ifdef BN_MP_ADD_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* single digit addition */
+int
+mp_add_d (mp_int * a, mp_digit b, mp_int * c)
+{
+ int res, ix, oldused;
+ mp_digit *tmpa, *tmpc, mu;
+
+ /* grow c as required */
+ if (c->alloc < a->used + 1) {
+ if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* if a is negative and |a| >= b, call c = |a| - b */
+ if (a->sign == MP_NEG && (a->used > 1 || a->dp[0] >= b)) {
+ /* temporarily fix sign of a */
+ a->sign = MP_ZPOS;
+
+ /* c = |a| - b */
+ res = mp_sub_d(a, b, c);
+
+ /* fix sign */
+ a->sign = c->sign = MP_NEG;
+
+ /* clamp */
+ mp_clamp(c);
+
+ return res;
+ }
+
+ /* old number of used digits in c */
+ oldused = c->used;
+
+ /* sign always positive */
+ c->sign = MP_ZPOS;
+
+ /* source alias */
+ tmpa = a->dp;
+
+ /* destination alias */
+ tmpc = c->dp;
+
+ /* if a is positive */
+ if (a->sign == MP_ZPOS) {
+ /* add digit, after this we're propagating
+ * the carry.
+ */
+ *tmpc = *tmpa++ + b;
+ mu = *tmpc >> DIGIT_BIT;
+ *tmpc++ &= MP_MASK;
+
+ /* now handle rest of the digits */
+ for (ix = 1; ix < a->used; ix++) {
+ *tmpc = *tmpa++ + mu;
+ mu = *tmpc >> DIGIT_BIT;
+ *tmpc++ &= MP_MASK;
+ }
+ /* set final carry */
+ ix++;
+ *tmpc++ = mu;
+
+ /* setup size */
+ c->used = a->used + 1;
+ } else {
+ /* a was negative and |a| < b */
+ c->used = 1;
+
+ /* the result is a single digit */
+ if (a->used == 1) {
+ *tmpc++ = b - a->dp[0];
+ } else {
+ *tmpc++ = b;
+ }
+
+ /* setup count so the clearing of oldused
+ * can fall through correctly
+ */
+ ix = 1;
+ }
+
+ /* now zero to oldused */
+ while (ix++ < oldused) {
+ *tmpc++ = 0;
+ }
+ mp_clamp(c);
+
+ return MP_OKAY;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_add_d.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_addmod.c b/dep/StormLib/src/libtommath/bn_mp_addmod.c
new file mode 100644
index 00000000000..0a21f62e9a6
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_addmod.c
@@ -0,0 +1,41 @@
+#include "tommath.h"
+#ifdef BN_MP_ADDMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* d = a + b (mod c) */
+int
+mp_addmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ int res;
+ mp_int t;
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_add (a, b, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ res = mp_mod (&t, c, d);
+ mp_clear (&t);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_addmod.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_and.c b/dep/StormLib/src/libtommath/bn_mp_and.c
new file mode 100644
index 00000000000..6b7afc104a8
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_and.c
@@ -0,0 +1,57 @@
+#include "tommath.h"
+#ifdef BN_MP_AND_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* AND two ints together */
+int
+mp_and (mp_int * a, mp_int * b, mp_int * c)
+{
+ int res, ix, px;
+ mp_int t, *x;
+
+ if (a->used > b->used) {
+ if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
+ return res;
+ }
+ px = b->used;
+ x = b;
+ } else {
+ if ((res = mp_init_copy (&t, b)) != MP_OKAY) {
+ return res;
+ }
+ px = a->used;
+ x = a;
+ }
+
+ for (ix = 0; ix < px; ix++) {
+ t.dp[ix] &= x->dp[ix];
+ }
+
+ /* zero digits above the last from the smallest mp_int */
+ for (; ix < t.used; ix++) {
+ t.dp[ix] = 0;
+ }
+
+ mp_clamp (&t);
+ mp_exch (c, &t);
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_and.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_clamp.c b/dep/StormLib/src/libtommath/bn_mp_clamp.c
new file mode 100644
index 00000000000..d3cc21c3eff
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_clamp.c
@@ -0,0 +1,44 @@
+#include "tommath.h"
+#ifdef BN_MP_CLAMP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* trim unused digits
+ *
+ * This is used to ensure that leading zero digits are
+ * trimed and the leading "used" digit will be non-zero
+ * Typically very fast. Also fixes the sign if there
+ * are no more leading digits
+ */
+void
+mp_clamp (mp_int * a)
+{
+ /* decrease used while the most significant digit is
+ * zero.
+ */
+ while (a->used > 0 && a->dp[a->used - 1] == 0) {
+ --(a->used);
+ }
+
+ /* reset the sign flag if used == 0 */
+ if (a->used == 0) {
+ a->sign = MP_ZPOS;
+ }
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_clamp.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_clear.c b/dep/StormLib/src/libtommath/bn_mp_clear.c
new file mode 100644
index 00000000000..7644c382512
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_clear.c
@@ -0,0 +1,44 @@
+#include "tommath.h"
+#ifdef BN_MP_CLEAR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* clear one (frees) */
+void
+mp_clear (mp_int * a)
+{
+ int i;
+
+ /* only do anything if a hasn't been freed previously */
+ if (a->dp != NULL) {
+ /* first zero the digits */
+ for (i = 0; i < a->used; i++) {
+ a->dp[i] = 0;
+ }
+
+ /* free ram */
+ XFREE(a->dp);
+
+ /* reset members to make debugging easier */
+ a->dp = NULL;
+ a->alloc = a->used = 0;
+ a->sign = MP_ZPOS;
+ }
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_clear.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_clear_multi.c b/dep/StormLib/src/libtommath/bn_mp_clear_multi.c
new file mode 100644
index 00000000000..a1076243675
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_clear_multi.c
@@ -0,0 +1,34 @@
+#include "tommath.h"
+#ifdef BN_MP_CLEAR_MULTI_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include <stdarg.h>
+
+void mp_clear_multi(mp_int *mp, ...)
+{
+ mp_int* next_mp = mp;
+ va_list args;
+ va_start(args, mp);
+ while (next_mp != NULL) {
+ mp_clear(next_mp);
+ next_mp = va_arg(args, mp_int*);
+ }
+ va_end(args);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_clear_multi.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_cmp.c b/dep/StormLib/src/libtommath/bn_mp_cmp.c
new file mode 100644
index 00000000000..761d2b0dc75
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_cmp.c
@@ -0,0 +1,43 @@
+#include "tommath.h"
+#ifdef BN_MP_CMP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* compare two ints (signed)*/
+int
+mp_cmp (mp_int * a, mp_int * b)
+{
+ /* compare based on sign */
+ if (a->sign != b->sign) {
+ if (a->sign == MP_NEG) {
+ return MP_LT;
+ } else {
+ return MP_GT;
+ }
+ }
+
+ /* compare digits */
+ if (a->sign == MP_NEG) {
+ /* if negative compare opposite direction */
+ return mp_cmp_mag(b, a);
+ } else {
+ return mp_cmp_mag(a, b);
+ }
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_cmp.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_cmp_d.c b/dep/StormLib/src/libtommath/bn_mp_cmp_d.c
new file mode 100644
index 00000000000..420dfd31aa1
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_cmp_d.c
@@ -0,0 +1,44 @@
+#include "tommath.h"
+#ifdef BN_MP_CMP_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* compare a digit */
+int mp_cmp_d(mp_int * a, mp_digit b)
+{
+ /* compare based on sign */
+ if (a->sign == MP_NEG) {
+ return MP_LT;
+ }
+
+ /* compare based on magnitude */
+ if (a->used > 1) {
+ return MP_GT;
+ }
+
+ /* compare the only digit of a to b */
+ if (a->dp[0] > b) {
+ return MP_GT;
+ } else if (a->dp[0] < b) {
+ return MP_LT;
+ } else {
+ return MP_EQ;
+ }
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_cmp_d.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_cmp_mag.c b/dep/StormLib/src/libtommath/bn_mp_cmp_mag.c
new file mode 100644
index 00000000000..92565a3b896
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_cmp_mag.c
@@ -0,0 +1,55 @@
+#include "tommath.h"
+#ifdef BN_MP_CMP_MAG_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* compare maginitude of two ints (unsigned) */
+int mp_cmp_mag (mp_int * a, mp_int * b)
+{
+ int n;
+ mp_digit *tmpa, *tmpb;
+
+ /* compare based on # of non-zero digits */
+ if (a->used > b->used) {
+ return MP_GT;
+ }
+
+ if (a->used < b->used) {
+ return MP_LT;
+ }
+
+ /* alias for a */
+ tmpa = a->dp + (a->used - 1);
+
+ /* alias for b */
+ tmpb = b->dp + (a->used - 1);
+
+ /* compare based on digits */
+ for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
+ if (*tmpa > *tmpb) {
+ return MP_GT;
+ }
+
+ if (*tmpa < *tmpb) {
+ return MP_LT;
+ }
+ }
+ return MP_EQ;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_cmp_mag.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_cnt_lsb.c b/dep/StormLib/src/libtommath/bn_mp_cnt_lsb.c
new file mode 100644
index 00000000000..60406610ed6
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_cnt_lsb.c
@@ -0,0 +1,53 @@
+#include "tommath.h"
+#ifdef BN_MP_CNT_LSB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+static const int lnz[16] = {
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+};
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int mp_cnt_lsb(mp_int *a)
+{
+ int x;
+ mp_digit q, qq;
+
+ /* easy out */
+ if (mp_iszero(a) == 1) {
+ return 0;
+ }
+
+ /* scan lower digits until non-zero */
+ for (x = 0; x < a->used && a->dp[x] == 0; x++);
+ q = a->dp[x];
+ x *= DIGIT_BIT;
+
+ /* now scan this digit until a 1 is found */
+ if ((q & 1) == 0) {
+ do {
+ qq = q & 15;
+ x += lnz[qq];
+ q >>= 4;
+ } while (qq == 0);
+ }
+ return x;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_cnt_lsb.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_copy.c b/dep/StormLib/src/libtommath/bn_mp_copy.c
new file mode 100644
index 00000000000..7828592da5d
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_copy.c
@@ -0,0 +1,68 @@
+#include "tommath.h"
+#ifdef BN_MP_COPY_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* copy, b = a */
+int
+mp_copy (mp_int * a, mp_int * b)
+{
+ int res, n;
+
+ /* if dst == src do nothing */
+ if (a == b) {
+ return MP_OKAY;
+ }
+
+ /* grow dest */
+ if (b->alloc < a->used) {
+ if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* zero b and copy the parameters over */
+ {
+ register mp_digit *tmpa, *tmpb;
+
+ /* pointer aliases */
+
+ /* source */
+ tmpa = a->dp;
+
+ /* destination */
+ tmpb = b->dp;
+
+ /* copy all the digits */
+ for (n = 0; n < a->used; n++) {
+ *tmpb++ = *tmpa++;
+ }
+
+ /* clear high digits */
+ for (; n < b->used; n++) {
+ *tmpb++ = 0;
+ }
+ }
+
+ /* copy used count and sign */
+ b->used = a->used;
+ b->sign = a->sign;
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_copy.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_count_bits.c b/dep/StormLib/src/libtommath/bn_mp_count_bits.c
new file mode 100644
index 00000000000..9d8640fdfce
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_count_bits.c
@@ -0,0 +1,45 @@
+#include "tommath.h"
+#ifdef BN_MP_COUNT_BITS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* returns the number of bits in an int */
+int
+mp_count_bits (mp_int * a)
+{
+ int r;
+ mp_digit q;
+
+ /* shortcut */
+ if (a->used == 0) {
+ return 0;
+ }
+
+ /* get number of digits and add that */
+ r = (a->used - 1) * DIGIT_BIT;
+
+ /* take the last digit and count the bits in it */
+ q = a->dp[a->used - 1];
+ while (q > ((mp_digit) 0)) {
+ ++r;
+ q >>= ((mp_digit) 1);
+ }
+ return r;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_count_bits.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_div.c b/dep/StormLib/src/libtommath/bn_mp_div.c
new file mode 100644
index 00000000000..3004a3ea016
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_div.c
@@ -0,0 +1,292 @@
+#include "tommath.h"
+#ifdef BN_MP_DIV_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+#ifdef BN_MP_DIV_SMALL
+
+/* slower bit-bang division... also smaller */
+int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ mp_int ta, tb, tq, q;
+ int res, n, n2;
+
+ /* is divisor zero ? */
+ if (mp_iszero (b) == 1) {
+ return MP_VAL;
+ }
+
+ /* if a < b then q=0, r = a */
+ if (mp_cmp_mag (a, b) == MP_LT) {
+ if (d != NULL) {
+ res = mp_copy (a, d);
+ } else {
+ res = MP_OKAY;
+ }
+ if (c != NULL) {
+ mp_zero (c);
+ }
+ return res;
+ }
+
+ /* init our temps */
+ if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) {
+ return res;
+ }
+
+
+ mp_set(&tq, 1);
+ n = mp_count_bits(a) - mp_count_bits(b);
+ if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
+ ((res = mp_abs(b, &tb)) != MP_OKAY) ||
+ ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
+ ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
+ goto LBL_ERR;
+ }
+
+ while (n-- >= 0) {
+ if (mp_cmp(&tb, &ta) != MP_GT) {
+ if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
+ ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
+ goto LBL_ERR;
+ }
+ }
+ if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
+ ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* now q == quotient and ta == remainder */
+ n = a->sign;
+ n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
+ if (c != NULL) {
+ mp_exch(c, &q);
+ c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
+ }
+ if (d != NULL) {
+ mp_exch(d, &ta);
+ d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
+ }
+LBL_ERR:
+ mp_clear_multi(&ta, &tb, &tq, &q, NULL);
+ return res;
+}
+
+#else
+
+/* integer signed division.
+ * c*b + d == a [e.g. a/b, c=quotient, d=remainder]
+ * HAC pp.598 Algorithm 14.20
+ *
+ * Note that the description in HAC is horribly
+ * incomplete. For example, it doesn't consider
+ * the case where digits are removed from 'x' in
+ * the inner loop. It also doesn't consider the
+ * case that y has fewer than three digits, etc..
+ *
+ * The overall algorithm is as described as
+ * 14.20 from HAC but fixed to treat these cases.
+*/
+int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ mp_int q, x, y, t1, t2;
+ int res, n, t, i, norm, neg;
+
+ /* is divisor zero ? */
+ if (mp_iszero (b) == 1) {
+ return MP_VAL;
+ }
+
+ /* if a < b then q=0, r = a */
+ if (mp_cmp_mag (a, b) == MP_LT) {
+ if (d != NULL) {
+ res = mp_copy (a, d);
+ } else {
+ res = MP_OKAY;
+ }
+ if (c != NULL) {
+ mp_zero (c);
+ }
+ return res;
+ }
+
+ if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) {
+ return res;
+ }
+ q.used = a->used + 2;
+
+ if ((res = mp_init (&t1)) != MP_OKAY) {
+ goto LBL_Q;
+ }
+
+ if ((res = mp_init (&t2)) != MP_OKAY) {
+ goto LBL_T1;
+ }
+
+ if ((res = mp_init_copy (&x, a)) != MP_OKAY) {
+ goto LBL_T2;
+ }
+
+ if ((res = mp_init_copy (&y, b)) != MP_OKAY) {
+ goto LBL_X;
+ }
+
+ /* fix the sign */
+ neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+ x.sign = y.sign = MP_ZPOS;
+
+ /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
+ norm = mp_count_bits(&y) % DIGIT_BIT;
+ if (norm < (int)(DIGIT_BIT-1)) {
+ norm = (DIGIT_BIT-1) - norm;
+ if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ } else {
+ norm = 0;
+ }
+
+ /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
+ n = x.used - 1;
+ t = y.used - 1;
+
+ /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
+ if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */
+ goto LBL_Y;
+ }
+
+ while (mp_cmp (&x, &y) != MP_LT) {
+ ++(q.dp[n - t]);
+ if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ }
+
+ /* reset y by shifting it back down */
+ mp_rshd (&y, n - t);
+
+ /* step 3. for i from n down to (t + 1) */
+ for (i = n; i >= (t + 1); i--) {
+ if (i > x.used) {
+ continue;
+ }
+
+ /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
+ * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
+ if (x.dp[i] == y.dp[t]) {
+ q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
+ } else {
+ mp_word tmp;
+ tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT);
+ tmp |= ((mp_word) x.dp[i - 1]);
+ tmp /= ((mp_word) y.dp[t]);
+ if (tmp > (mp_word) MP_MASK)
+ tmp = MP_MASK;
+ q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
+ }
+
+ /* while (q{i-t-1} * (yt * b + y{t-1})) >
+ xi * b**2 + xi-1 * b + xi-2
+
+ do q{i-t-1} -= 1;
+ */
+ q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
+ do {
+ q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK;
+
+ /* find left hand */
+ mp_zero (&t1);
+ t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
+ t1.dp[1] = y.dp[t];
+ t1.used = 2;
+ if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ /* find right hand */
+ t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
+ t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
+ t2.dp[2] = x.dp[i];
+ t2.used = 3;
+ } while (mp_cmp_mag(&t1, &t2) == MP_GT);
+
+ /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
+ if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
+ if (x.sign == MP_NEG) {
+ if ((res = mp_copy (&y, &t1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK;
+ }
+ }
+
+ /* now q is the quotient and x is the remainder
+ * [which we have to normalize]
+ */
+
+ /* get sign before writing to c */
+ x.sign = x.used == 0 ? MP_ZPOS : a->sign;
+
+ if (c != NULL) {
+ mp_clamp (&q);
+ mp_exch (&q, c);
+ c->sign = neg;
+ }
+
+ if (d != NULL) {
+ mp_div_2d (&x, norm, &x, NULL);
+ mp_exch (&x, d);
+ }
+
+ res = MP_OKAY;
+
+LBL_Y:mp_clear (&y);
+LBL_X:mp_clear (&x);
+LBL_T2:mp_clear (&t2);
+LBL_T1:mp_clear (&t1);
+LBL_Q:mp_clear (&q);
+ return res;
+}
+
+#endif
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_div.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_div_2.c b/dep/StormLib/src/libtommath/bn_mp_div_2.c
new file mode 100644
index 00000000000..f3b9d16fa37
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_div_2.c
@@ -0,0 +1,68 @@
+#include "tommath.h"
+#ifdef BN_MP_DIV_2_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* b = a/2 */
+int mp_div_2(mp_int * a, mp_int * b)
+{
+ int x, res, oldused;
+
+ /* copy */
+ if (b->alloc < a->used) {
+ if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ oldused = b->used;
+ b->used = a->used;
+ {
+ register mp_digit r, rr, *tmpa, *tmpb;
+
+ /* source alias */
+ tmpa = a->dp + b->used - 1;
+
+ /* dest alias */
+ tmpb = b->dp + b->used - 1;
+
+ /* carry */
+ r = 0;
+ for (x = b->used - 1; x >= 0; x--) {
+ /* get the carry for the next iteration */
+ rr = *tmpa & 1;
+
+ /* shift the current digit, add in carry and store */
+ *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
+
+ /* forward carry to next iteration */
+ r = rr;
+ }
+
+ /* zero excess digits */
+ tmpb = b->dp + b->used;
+ for (x = b->used; x < oldused; x++) {
+ *tmpb++ = 0;
+ }
+ }
+ b->sign = a->sign;
+ mp_clamp (b);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_div_2.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_div_2d.c b/dep/StormLib/src/libtommath/bn_mp_div_2d.c
new file mode 100644
index 00000000000..861ea23a31a
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_div_2d.c
@@ -0,0 +1,97 @@
+#include "tommath.h"
+#ifdef BN_MP_DIV_2D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* shift right by a certain bit count (store quotient in c, optional remainder in d) */
+int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
+{
+ mp_digit D, r, rr;
+ int x, res;
+ mp_int t;
+
+
+ /* if the shift count is <= 0 then we do no work */
+ if (b <= 0) {
+ res = mp_copy (a, c);
+ if (d != NULL) {
+ mp_zero (d);
+ }
+ return res;
+ }
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ /* get the remainder */
+ if (d != NULL) {
+ if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ }
+
+ /* copy */
+ if ((res = mp_copy (a, c)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+
+ /* shift by as many digits in the bit count */
+ if (b >= (int)DIGIT_BIT) {
+ mp_rshd (c, b / DIGIT_BIT);
+ }
+
+ /* shift any bit count < DIGIT_BIT */
+ D = (mp_digit) (b % DIGIT_BIT);
+ if (D != 0) {
+ register mp_digit *tmpc, mask, shift;
+
+ /* mask */
+ mask = (((mp_digit)1) << D) - 1;
+
+ /* shift for lsb */
+ shift = DIGIT_BIT - D;
+
+ /* alias */
+ tmpc = c->dp + (c->used - 1);
+
+ /* carry */
+ r = 0;
+ for (x = c->used - 1; x >= 0; x--) {
+ /* get the lower bits of this word in a temp */
+ rr = *tmpc & mask;
+
+ /* shift the current word and mix in the carry bits from the previous word */
+ *tmpc = (*tmpc >> D) | (r << shift);
+ --tmpc;
+
+ /* set the carry to the carry bits of the current word found above */
+ r = rr;
+ }
+ }
+ mp_clamp (c);
+ if (d != NULL) {
+ mp_exch (&t, d);
+ }
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_div_2d.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_div_3.c b/dep/StormLib/src/libtommath/bn_mp_div_3.c
new file mode 100644
index 00000000000..4fc08fc4da4
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_div_3.c
@@ -0,0 +1,79 @@
+#include "tommath.h"
+#ifdef BN_MP_DIV_3_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* divide by three (based on routine from MPI and the GMP manual) */
+int
+mp_div_3 (mp_int * a, mp_int *c, mp_digit * d)
+{
+ mp_int q;
+ mp_word w, t;
+ mp_digit b;
+ int res, ix;
+
+ /* b = 2**DIGIT_BIT / 3 */
+ b = (((mp_word)1) << ((mp_word)DIGIT_BIT)) / ((mp_word)3);
+
+ if ((res = mp_init_size(&q, a->used)) != MP_OKAY) {
+ return res;
+ }
+
+ q.used = a->used;
+ q.sign = a->sign;
+ w = 0;
+ for (ix = a->used - 1; ix >= 0; ix--) {
+ w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]);
+
+ if (w >= 3) {
+ /* multiply w by [1/3] */
+ t = (w * ((mp_word)b)) >> ((mp_word)DIGIT_BIT);
+
+ /* now subtract 3 * [w/3] from w, to get the remainder */
+ w -= t+t+t;
+
+ /* fixup the remainder as required since
+ * the optimization is not exact.
+ */
+ while (w >= 3) {
+ t += 1;
+ w -= 3;
+ }
+ } else {
+ t = 0;
+ }
+ q.dp[ix] = (mp_digit)t;
+ }
+
+ /* [optional] store the remainder */
+ if (d != NULL) {
+ *d = (mp_digit)w;
+ }
+
+ /* [optional] store the quotient */
+ if (c != NULL) {
+ mp_clamp(&q);
+ mp_exch(&q, c);
+ }
+ mp_clear(&q);
+
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_div_3.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_div_d.c b/dep/StormLib/src/libtommath/bn_mp_div_d.c
new file mode 100644
index 00000000000..c0318a4a1be
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_div_d.c
@@ -0,0 +1,115 @@
+#include "tommath.h"
+#ifdef BN_MP_DIV_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+static int s_is_power_of_two(mp_digit b, int *p)
+{
+ int x;
+
+ /* fast return if no power of two */
+ if ((b==0) || (b & (b-1))) {
+ return 0;
+ }
+
+ for (x = 0; x < DIGIT_BIT; x++) {
+ if (b == (((mp_digit)1)<<x)) {
+ *p = x;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* single digit division (based on routine from MPI) */
+int mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d)
+{
+ mp_int q;
+ mp_word w;
+ mp_digit t;
+ int res, ix;
+
+ /* cannot divide by zero */
+ if (b == 0) {
+ return MP_VAL;
+ }
+
+ /* quick outs */
+ if (b == 1 || mp_iszero(a) == 1) {
+ if (d != NULL) {
+ *d = 0;
+ }
+ if (c != NULL) {
+ return mp_copy(a, c);
+ }
+ return MP_OKAY;
+ }
+
+ /* power of two ? */
+ if (s_is_power_of_two(b, &ix) == 1) {
+ if (d != NULL) {
+ *d = a->dp[0] & ((((mp_digit)1)<<ix) - 1);
+ }
+ if (c != NULL) {
+ return mp_div_2d(a, ix, c, NULL);
+ }
+ return MP_OKAY;
+ }
+
+#ifdef BN_MP_DIV_3_C
+ /* three? */
+ if (b == 3) {
+ return mp_div_3(a, c, d);
+ }
+#endif
+
+ /* no easy answer [c'est la vie]. Just division */
+ if ((res = mp_init_size(&q, a->used)) != MP_OKAY) {
+ return res;
+ }
+
+ q.used = a->used;
+ q.sign = a->sign;
+ w = 0;
+ for (ix = a->used - 1; ix >= 0; ix--) {
+ w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]);
+
+ if (w >= b) {
+ t = (mp_digit)(w / b);
+ w -= ((mp_word)t) * ((mp_word)b);
+ } else {
+ t = 0;
+ }
+ q.dp[ix] = (mp_digit)t;
+ }
+
+ if (d != NULL) {
+ *d = (mp_digit)w;
+ }
+
+ if (c != NULL) {
+ mp_clamp(&q);
+ mp_exch(&q, c);
+ }
+ mp_clear(&q);
+
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_div_d.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2007/01/09 04:44:32 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_dr_is_modulus.c b/dep/StormLib/src/libtommath/bn_mp_dr_is_modulus.c
new file mode 100644
index 00000000000..22ba5df3d0a
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_dr_is_modulus.c
@@ -0,0 +1,43 @@
+#include "tommath.h"
+#ifdef BN_MP_DR_IS_MODULUS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* determines if a number is a valid DR modulus */
+int mp_dr_is_modulus(mp_int *a)
+{
+ int ix;
+
+ /* must be at least two digits */
+ if (a->used < 2) {
+ return 0;
+ }
+
+ /* must be of the form b**k - a [a <= b] so all
+ * but the first digit must be equal to -1 (mod b).
+ */
+ for (ix = 1; ix < a->used; ix++) {
+ if (a->dp[ix] != MP_MASK) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_dr_is_modulus.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_dr_reduce.c b/dep/StormLib/src/libtommath/bn_mp_dr_reduce.c
new file mode 100644
index 00000000000..0afac941fca
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_dr_reduce.c
@@ -0,0 +1,94 @@
+#include "tommath.h"
+#ifdef BN_MP_DR_REDUCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* reduce "x" in place modulo "n" using the Diminished Radix algorithm.
+ *
+ * Based on algorithm from the paper
+ *
+ * "Generating Efficient Primes for Discrete Log Cryptosystems"
+ * Chae Hoon Lim, Pil Joong Lee,
+ * POSTECH Information Research Laboratories
+ *
+ * The modulus must be of a special format [see manual]
+ *
+ * Has been modified to use algorithm 7.10 from the LTM book instead
+ *
+ * Input x must be in the range 0 <= x <= (n-1)**2
+ */
+int
+mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k)
+{
+ int err, i, m;
+ mp_word r;
+ mp_digit mu, *tmpx1, *tmpx2;
+
+ /* m = digits in modulus */
+ m = n->used;
+
+ /* ensure that "x" has at least 2m digits */
+ if (x->alloc < m + m) {
+ if ((err = mp_grow (x, m + m)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+/* top of loop, this is where the code resumes if
+ * another reduction pass is required.
+ */
+top:
+ /* aliases for digits */
+ /* alias for lower half of x */
+ tmpx1 = x->dp;
+
+ /* alias for upper half of x, or x/B**m */
+ tmpx2 = x->dp + m;
+
+ /* set carry to zero */
+ mu = 0;
+
+ /* compute (x mod B**m) + k * [x/B**m] inline and inplace */
+ for (i = 0; i < m; i++) {
+ r = ((mp_word)*tmpx2++) * ((mp_word)k) + *tmpx1 + mu;
+ *tmpx1++ = (mp_digit)(r & MP_MASK);
+ mu = (mp_digit)(r >> ((mp_word)DIGIT_BIT));
+ }
+
+ /* set final carry */
+ *tmpx1++ = mu;
+
+ /* zero words above m */
+ for (i = m + 1; i < x->used; i++) {
+ *tmpx1++ = 0;
+ }
+
+ /* clamp, sub and return */
+ mp_clamp (x);
+
+ /* if x >= n then subtract and reduce again
+ * Each successive "recursion" makes the input smaller and smaller.
+ */
+ if (mp_cmp_mag (x, n) != MP_LT) {
+ s_mp_sub(x, n, x);
+ goto top;
+ }
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_dr_reduce.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_dr_setup.c b/dep/StormLib/src/libtommath/bn_mp_dr_setup.c
new file mode 100644
index 00000000000..a5152f713bd
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_dr_setup.c
@@ -0,0 +1,32 @@
+#include "tommath.h"
+#ifdef BN_MP_DR_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* determines the setup value */
+void mp_dr_setup(mp_int *a, mp_digit *d)
+{
+ /* the casts are required if DIGIT_BIT is one less than
+ * the number of bits in a mp_digit [e.g. DIGIT_BIT==31]
+ */
+ *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) -
+ ((mp_word)a->dp[0]));
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_dr_setup.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_exch.c b/dep/StormLib/src/libtommath/bn_mp_exch.c
new file mode 100644
index 00000000000..e5ec7f57730
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_exch.c
@@ -0,0 +1,34 @@
+#include "tommath.h"
+#ifdef BN_MP_EXCH_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* swap the elements of two integers, for cases where you can't simply swap the
+ * mp_int pointers around
+ */
+void
+mp_exch (mp_int * a, mp_int * b)
+{
+ mp_int t;
+
+ t = *a;
+ *a = *b;
+ *b = t;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_exch.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_expt_d.c b/dep/StormLib/src/libtommath/bn_mp_expt_d.c
new file mode 100644
index 00000000000..7bf371ce6ae
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_expt_d.c
@@ -0,0 +1,57 @@
+#include "tommath.h"
+#ifdef BN_MP_EXPT_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* calculate c = a**b using a square-multiply algorithm */
+int mp_expt_d (mp_int * a, mp_digit b, mp_int * c)
+{
+ int res, x;
+ mp_int g;
+
+ if ((res = mp_init_copy (&g, a)) != MP_OKAY) {
+ return res;
+ }
+
+ /* set initial result */
+ mp_set (c, 1);
+
+ for (x = 0; x < (int) DIGIT_BIT; x++) {
+ /* square */
+ if ((res = mp_sqr (c, c)) != MP_OKAY) {
+ mp_clear (&g);
+ return res;
+ }
+
+ /* if the bit is set multiply */
+ if ((b & (mp_digit) (((mp_digit)1) << (DIGIT_BIT - 1))) != 0) {
+ if ((res = mp_mul (c, &g, c)) != MP_OKAY) {
+ mp_clear (&g);
+ return res;
+ }
+ }
+
+ /* shift to next bit */
+ b <<= 1;
+ }
+
+ mp_clear (&g);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_expt_d.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_exptmod.c b/dep/StormLib/src/libtommath/bn_mp_exptmod.c
new file mode 100644
index 00000000000..27c46ea0ab2
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_exptmod.c
@@ -0,0 +1,112 @@
+#include "tommath.h"
+#ifdef BN_MP_EXPTMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+
+/* this is a shell function that calls either the normal or Montgomery
+ * exptmod functions. Originally the call to the montgomery code was
+ * embedded in the normal function but that wasted alot of stack space
+ * for nothing (since 99% of the time the Montgomery code would be called)
+ */
+int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
+{
+ int dr;
+
+ /* modulus P must be positive */
+ if (P->sign == MP_NEG) {
+ return MP_VAL;
+ }
+
+ /* if exponent X is negative we have to recurse */
+ if (X->sign == MP_NEG) {
+#ifdef BN_MP_INVMOD_C
+ mp_int tmpG, tmpX;
+ int err;
+
+ /* first compute 1/G mod P */
+ if ((err = mp_init(&tmpG)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
+ mp_clear(&tmpG);
+ return err;
+ }
+
+ /* now get |X| */
+ if ((err = mp_init(&tmpX)) != MP_OKAY) {
+ mp_clear(&tmpG);
+ return err;
+ }
+ if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
+ mp_clear_multi(&tmpG, &tmpX, NULL);
+ return err;
+ }
+
+ /* and now compute (1/G)**|X| instead of G**X [X < 0] */
+ err = mp_exptmod(&tmpG, &tmpX, P, Y);
+ mp_clear_multi(&tmpG, &tmpX, NULL);
+ return err;
+#else
+ /* no invmod */
+ return MP_VAL;
+#endif
+ }
+
+/* modified diminished radix reduction */
+#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C)
+ if (mp_reduce_is_2k_l(P) == MP_YES) {
+ return s_mp_exptmod(G, X, P, Y, 1);
+ }
+#endif
+
+#ifdef BN_MP_DR_IS_MODULUS_C
+ /* is it a DR modulus? */
+ dr = mp_dr_is_modulus(P);
+#else
+ /* default to no */
+ dr = 0;
+#endif
+
+#ifdef BN_MP_REDUCE_IS_2K_C
+ /* if not, is it a unrestricted DR modulus? */
+ if (dr == 0) {
+ dr = mp_reduce_is_2k(P) << 1;
+ }
+#endif
+
+ /* if the modulus is odd or dr != 0 use the montgomery method */
+#ifdef BN_MP_EXPTMOD_FAST_C
+ if (mp_isodd (P) == 1 || dr != 0) {
+ return mp_exptmod_fast (G, X, P, Y, dr);
+ } else {
+#endif
+#ifdef BN_S_MP_EXPTMOD_C
+ /* otherwise use the generic Barrett reduction technique */
+ return s_mp_exptmod (G, X, P, Y, 0);
+#else
+ /* no exptmod for evens */
+ return MP_VAL;
+#endif
+#ifdef BN_MP_EXPTMOD_FAST_C
+ }
+#endif
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_exptmod.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_exptmod_fast.c b/dep/StormLib/src/libtommath/bn_mp_exptmod_fast.c
new file mode 100644
index 00000000000..31205d4e20c
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_exptmod_fast.c
@@ -0,0 +1,321 @@
+#include "tommath.h"
+#ifdef BN_MP_EXPTMOD_FAST_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
+ *
+ * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
+ * The value of k changes based on the size of the exponent.
+ *
+ * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
+ */
+
+#ifdef MP_LOW_MEM
+ #define TAB_SIZE 32
+#else
+ #define TAB_SIZE 256
+#endif
+
+int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
+{
+ mp_int M[TAB_SIZE], res;
+ mp_digit buf, mp;
+ int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+
+ /* use a pointer to the reduction algorithm. This allows us to use
+ * one of many reduction algorithms without modding the guts of
+ * the code with if statements everywhere.
+ */
+ int (*redux)(mp_int*,mp_int*,mp_digit);
+
+ /* find window size */
+ x = mp_count_bits (X);
+ if (x <= 7) {
+ winsize = 2;
+ } else if (x <= 36) {
+ winsize = 3;
+ } else if (x <= 140) {
+ winsize = 4;
+ } else if (x <= 450) {
+ winsize = 5;
+ } else if (x <= 1303) {
+ winsize = 6;
+ } else if (x <= 3529) {
+ winsize = 7;
+ } else {
+ winsize = 8;
+ }
+
+#ifdef MP_LOW_MEM
+ if (winsize > 5) {
+ winsize = 5;
+ }
+#endif
+
+ /* init M array */
+ /* init first cell */
+ if ((err = mp_init(&M[1])) != MP_OKAY) {
+ return err;
+ }
+
+ /* now init the second half of the array */
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ if ((err = mp_init(&M[x])) != MP_OKAY) {
+ for (y = 1<<(winsize-1); y < x; y++) {
+ mp_clear (&M[y]);
+ }
+ mp_clear(&M[1]);
+ return err;
+ }
+ }
+
+ /* determine and setup reduction code */
+ if (redmode == 0) {
+#ifdef BN_MP_MONTGOMERY_SETUP_C
+ /* now setup montgomery */
+ if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
+ goto LBL_M;
+ }
+#else
+ err = MP_VAL;
+ goto LBL_M;
+#endif
+
+ /* automatically pick the comba one if available (saves quite a few calls/ifs) */
+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
+ if (((P->used * 2 + 1) < MP_WARRAY) &&
+ P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ redux = fast_mp_montgomery_reduce;
+ } else
+#endif
+ {
+#ifdef BN_MP_MONTGOMERY_REDUCE_C
+ /* use slower baseline Montgomery method */
+ redux = mp_montgomery_reduce;
+#else
+ err = MP_VAL;
+ goto LBL_M;
+#endif
+ }
+ } else if (redmode == 1) {
+#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
+ /* setup DR reduction for moduli of the form B**k - b */
+ mp_dr_setup(P, &mp);
+ redux = mp_dr_reduce;
+#else
+ err = MP_VAL;
+ goto LBL_M;
+#endif
+ } else {
+#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
+ /* setup DR reduction for moduli of the form 2**k - b */
+ if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
+ goto LBL_M;
+ }
+ redux = mp_reduce_2k;
+#else
+ err = MP_VAL;
+ goto LBL_M;
+#endif
+ }
+
+ /* setup result */
+ if ((err = mp_init (&res)) != MP_OKAY) {
+ goto LBL_M;
+ }
+
+ /* create M table
+ *
+
+ *
+ * The first half of the table is not computed though accept for M[0] and M[1]
+ */
+
+ if (redmode == 0) {
+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+ /* now we need R mod m */
+ if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+#else
+ err = MP_VAL;
+ goto LBL_RES;
+#endif
+
+ /* now set M[1] to G * R mod m */
+ if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ } else {
+ mp_set(&res, 1);
+ if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
+ if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ for (x = 0; x < (winsize - 1); x++) {
+ if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* create upper table */
+ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+ if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* set initial mode and bit cnt */
+ mode = 0;
+ bitcnt = 1;
+ buf = 0;
+ digidx = X->used - 1;
+ bitcpy = 0;
+ bitbuf = 0;
+
+ for (;;) {
+ /* grab next digit as required */
+ if (--bitcnt == 0) {
+ /* if digidx == -1 we are out of digits so break */
+ if (digidx == -1) {
+ break;
+ }
+ /* read next digit and reset bitcnt */
+ buf = X->dp[digidx--];
+ bitcnt = (int)DIGIT_BIT;
+ }
+
+ /* grab the next msb from the exponent */
+ y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
+ buf <<= (mp_digit)1;
+
+ /* if the bit is zero and mode == 0 then we ignore it
+ * These represent the leading zero bits before the first 1 bit
+ * in the exponent. Technically this opt is not required but it
+ * does lower the # of trivial squaring/reductions used
+ */
+ if (mode == 0 && y == 0) {
+ continue;
+ }
+
+ /* if the bit is zero and mode == 1 then we square */
+ if (mode == 1 && y == 0) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ continue;
+ }
+
+ /* else we add it to the window */
+ bitbuf |= (y << (winsize - ++bitcpy));
+ mode = 2;
+
+ if (bitcpy == winsize) {
+ /* ok window is filled so square as required and multiply */
+ /* square first */
+ for (x = 0; x < winsize; x++) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* then multiply */
+ if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ /* empty window and reset */
+ bitcpy = 0;
+ bitbuf = 0;
+ mode = 1;
+ }
+ }
+
+ /* if bits remain then square/multiply */
+ if (mode == 2 && bitcpy > 0) {
+ /* square then multiply if the bit is set */
+ for (x = 0; x < bitcpy; x++) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ /* get next bit of the window */
+ bitbuf <<= 1;
+ if ((bitbuf & (1 << winsize)) != 0) {
+ /* then multiply */
+ if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+ }
+ }
+
+ if (redmode == 0) {
+ /* fixup result if Montgomery reduction is used
+ * recall that any value in a Montgomery system is
+ * actually multiplied by R mod n. So we have
+ * to reduce one more time to cancel out the factor
+ * of R.
+ */
+ if ((err = redux(&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* swap res with Y */
+ mp_exch (&res, Y);
+ err = MP_OKAY;
+LBL_RES:mp_clear (&res);
+LBL_M:
+ mp_clear(&M[1]);
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ mp_clear (&M[x]);
+ }
+ return err;
+}
+#endif
+
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_exptmod_fast.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_exteuclid.c b/dep/StormLib/src/libtommath/bn_mp_exteuclid.c
new file mode 100644
index 00000000000..9881d6edc80
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_exteuclid.c
@@ -0,0 +1,82 @@
+#include "tommath.h"
+#ifdef BN_MP_EXTEUCLID_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Extended euclidean algorithm of (a, b) produces
+ a*u1 + b*u2 = u3
+ */
+int mp_exteuclid(mp_int *a, mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3)
+{
+ mp_int u1,u2,u3,v1,v2,v3,t1,t2,t3,q,tmp;
+ int err;
+
+ if ((err = mp_init_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* initialize, (u1,u2,u3) = (1,0,a) */
+ mp_set(&u1, 1);
+ if ((err = mp_copy(a, &u3)) != MP_OKAY) { goto _ERR; }
+
+ /* initialize, (v1,v2,v3) = (0,1,b) */
+ mp_set(&v2, 1);
+ if ((err = mp_copy(b, &v3)) != MP_OKAY) { goto _ERR; }
+
+ /* loop while v3 != 0 */
+ while (mp_iszero(&v3) == MP_NO) {
+ /* q = u3/v3 */
+ if ((err = mp_div(&u3, &v3, &q, NULL)) != MP_OKAY) { goto _ERR; }
+
+ /* (t1,t2,t3) = (u1,u2,u3) - (v1,v2,v3)q */
+ if ((err = mp_mul(&v1, &q, &tmp)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_sub(&u1, &tmp, &t1)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_mul(&v2, &q, &tmp)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_sub(&u2, &tmp, &t2)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_mul(&v3, &q, &tmp)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_sub(&u3, &tmp, &t3)) != MP_OKAY) { goto _ERR; }
+
+ /* (u1,u2,u3) = (v1,v2,v3) */
+ if ((err = mp_copy(&v1, &u1)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_copy(&v2, &u2)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_copy(&v3, &u3)) != MP_OKAY) { goto _ERR; }
+
+ /* (v1,v2,v3) = (t1,t2,t3) */
+ if ((err = mp_copy(&t1, &v1)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_copy(&t2, &v2)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_copy(&t3, &v3)) != MP_OKAY) { goto _ERR; }
+ }
+
+ /* make sure U3 >= 0 */
+ if (u3.sign == MP_NEG) {
+ mp_neg(&u1, &u1);
+ mp_neg(&u2, &u2);
+ mp_neg(&u3, &u3);
+ }
+
+ /* copy result out */
+ if (U1 != NULL) { mp_exch(U1, &u1); }
+ if (U2 != NULL) { mp_exch(U2, &u2); }
+ if (U3 != NULL) { mp_exch(U3, &u3); }
+
+ err = MP_OKAY;
+_ERR: mp_clear_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL);
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_exteuclid.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_fread.c b/dep/StormLib/src/libtommath/bn_mp_fread.c
new file mode 100644
index 00000000000..2976b30aa68
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_fread.c
@@ -0,0 +1,67 @@
+#include "tommath.h"
+#ifdef BN_MP_FREAD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* read a bigint from a file stream in ASCII */
+int mp_fread(mp_int *a, int radix, FILE *stream)
+{
+ int err, ch, neg, y;
+
+ /* clear a */
+ mp_zero(a);
+
+ /* if first digit is - then set negative */
+ ch = fgetc(stream);
+ if (ch == '-') {
+ neg = MP_NEG;
+ ch = fgetc(stream);
+ } else {
+ neg = MP_ZPOS;
+ }
+
+ for (;;) {
+ /* find y in the radix map */
+ for (y = 0; y < radix; y++) {
+ if (mp_s_rmap[y] == ch) {
+ break;
+ }
+ }
+ if (y == radix) {
+ break;
+ }
+
+ /* shift up and add */
+ if ((err = mp_mul_d(a, radix, a)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_add_d(a, y, a)) != MP_OKAY) {
+ return err;
+ }
+
+ ch = fgetc(stream);
+ }
+ if (mp_cmp_d(a, 0) != MP_EQ) {
+ a->sign = neg;
+ }
+
+ return MP_OKAY;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_fread.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_fwrite.c b/dep/StormLib/src/libtommath/bn_mp_fwrite.c
new file mode 100644
index 00000000000..6782b2e19f7
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_fwrite.c
@@ -0,0 +1,52 @@
+#include "tommath.h"
+#ifdef BN_MP_FWRITE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+int mp_fwrite(mp_int *a, int radix, FILE *stream)
+{
+ char *buf;
+ int err, len, x;
+
+ if ((err = mp_radix_size(a, radix, &len)) != MP_OKAY) {
+ return err;
+ }
+
+ buf = OPT_CAST(char) XMALLOC (len);
+ if (buf == NULL) {
+ return MP_MEM;
+ }
+
+ if ((err = mp_toradix(a, buf, radix)) != MP_OKAY) {
+ XFREE (buf);
+ return err;
+ }
+
+ for (x = 0; x < len; x++) {
+ if (fputc(buf[x], stream) == EOF) {
+ XFREE (buf);
+ return MP_VAL;
+ }
+ }
+
+ XFREE (buf);
+ return MP_OKAY;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_fwrite.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_gcd.c b/dep/StormLib/src/libtommath/bn_mp_gcd.c
new file mode 100644
index 00000000000..ce980eb6bb0
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_gcd.c
@@ -0,0 +1,105 @@
+#include "tommath.h"
+#ifdef BN_MP_GCD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Greatest Common Divisor using the binary method */
+int mp_gcd (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int u, v;
+ int k, u_lsb, v_lsb, res;
+
+ /* either zero than gcd is the largest */
+ if (mp_iszero (a) == MP_YES) {
+ return mp_abs (b, c);
+ }
+ if (mp_iszero (b) == MP_YES) {
+ return mp_abs (a, c);
+ }
+
+ /* get copies of a and b we can modify */
+ if ((res = mp_init_copy (&u, a)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_init_copy (&v, b)) != MP_OKAY) {
+ goto LBL_U;
+ }
+
+ /* must be positive for the remainder of the algorithm */
+ u.sign = v.sign = MP_ZPOS;
+
+ /* B1. Find the common power of two for u and v */
+ u_lsb = mp_cnt_lsb(&u);
+ v_lsb = mp_cnt_lsb(&v);
+ k = MIN(u_lsb, v_lsb);
+
+ if (k > 0) {
+ /* divide the power of two out */
+ if ((res = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+
+ if ((res = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ /* divide any remaining factors of two out */
+ if (u_lsb != k) {
+ if ((res = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ if (v_lsb != k) {
+ if ((res = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ while (mp_iszero(&v) == 0) {
+ /* make sure v is the largest */
+ if (mp_cmp_mag(&u, &v) == MP_GT) {
+ /* swap u and v to make sure v is >= u */
+ mp_exch(&u, &v);
+ }
+
+ /* subtract smallest from largest */
+ if ((res = s_mp_sub(&v, &u, &v)) != MP_OKAY) {
+ goto LBL_V;
+ }
+
+ /* Divide out all factors of two */
+ if ((res = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ /* multiply by 2**k which we divided out at the beginning */
+ if ((res = mp_mul_2d (&u, k, c)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ c->sign = MP_ZPOS;
+ res = MP_OKAY;
+LBL_V:mp_clear (&u);
+LBL_U:mp_clear (&v);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_gcd.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_get_int.c b/dep/StormLib/src/libtommath/bn_mp_get_int.c
new file mode 100644
index 00000000000..d9c76d0d15c
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_get_int.c
@@ -0,0 +1,45 @@
+#include "tommath.h"
+#ifdef BN_MP_GET_INT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* get the lower 32-bits of an mp_int */
+unsigned long mp_get_int(mp_int * a)
+{
+ int i;
+ unsigned long res;
+
+ if (a->used == 0) {
+ return 0;
+ }
+
+ /* get number of digits of the lsb we have to read */
+ i = MIN(a->used,(int)((sizeof(unsigned long)*CHAR_BIT+DIGIT_BIT-1)/DIGIT_BIT))-1;
+
+ /* get most significant digit of result */
+ res = DIGIT(a,i);
+
+ while (--i >= 0) {
+ res = (res << DIGIT_BIT) | DIGIT(a,i);
+ }
+
+ /* force result to 32-bits always so it is consistent on non 32-bit platforms */
+ return res & 0xFFFFFFFFUL;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_get_int.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_grow.c b/dep/StormLib/src/libtommath/bn_mp_grow.c
new file mode 100644
index 00000000000..a05dad73bc1
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_grow.c
@@ -0,0 +1,57 @@
+#include "tommath.h"
+#ifdef BN_MP_GROW_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* grow as required */
+int mp_grow (mp_int * a, int size)
+{
+ int i;
+ mp_digit *tmp;
+
+ /* if the alloc size is smaller alloc more ram */
+ if (a->alloc < size) {
+ /* ensure there are always at least MP_PREC digits extra on top */
+ size += (MP_PREC * 2) - (size % MP_PREC);
+
+ /* reallocate the array a->dp
+ *
+ * We store the return in a temporary variable
+ * in case the operation failed we don't want
+ * to overwrite the dp member of a.
+ */
+ tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size);
+ if (tmp == NULL) {
+ /* reallocation failed but "a" is still valid [can be freed] */
+ return MP_MEM;
+ }
+
+ /* reallocation succeeded so set a->dp */
+ a->dp = tmp;
+
+ /* zero excess digits */
+ i = a->alloc;
+ a->alloc = size;
+ for (; i < a->alloc; i++) {
+ a->dp[i] = 0;
+ }
+ }
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_grow.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_init.c b/dep/StormLib/src/libtommath/bn_mp_init.c
new file mode 100644
index 00000000000..107d98be6e8
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_init.c
@@ -0,0 +1,46 @@
+#include "tommath.h"
+#ifdef BN_MP_INIT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* init a new mp_int */
+int mp_init (mp_int * a)
+{
+ int i;
+
+ /* allocate memory required and clear it */
+ a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC);
+ if (a->dp == NULL) {
+ return MP_MEM;
+ }
+
+ /* set the digits to zero */
+ for (i = 0; i < MP_PREC; i++) {
+ a->dp[i] = 0;
+ }
+
+ /* set the used to zero, allocated digits to the default precision
+ * and sign to positive */
+ a->used = 0;
+ a->alloc = MP_PREC;
+ a->sign = MP_ZPOS;
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_init.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_init_copy.c b/dep/StormLib/src/libtommath/bn_mp_init_copy.c
new file mode 100644
index 00000000000..3ca1186ce1d
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_init_copy.c
@@ -0,0 +1,32 @@
+#include "tommath.h"
+#ifdef BN_MP_INIT_COPY_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* creates "a" then copies b into it */
+int mp_init_copy (mp_int * a, mp_int * b)
+{
+ int res;
+
+ if ((res = mp_init (a)) != MP_OKAY) {
+ return res;
+ }
+ return mp_copy (b, a);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_init_copy.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_init_multi.c b/dep/StormLib/src/libtommath/bn_mp_init_multi.c
new file mode 100644
index 00000000000..4f6f367ffd5
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_init_multi.c
@@ -0,0 +1,59 @@
+#include "tommath.h"
+#ifdef BN_MP_INIT_MULTI_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include <stdarg.h>
+
+int mp_init_multi(mp_int *mp, ...)
+{
+ mp_err res = MP_OKAY; /* Assume ok until proven otherwise */
+ int n = 0; /* Number of ok inits */
+ mp_int* cur_arg = mp;
+ va_list args;
+
+ va_start(args, mp); /* init args to next argument from caller */
+ while (cur_arg != NULL) {
+ if (mp_init(cur_arg) != MP_OKAY) {
+ /* Oops - error! Back-track and mp_clear what we already
+ succeeded in init-ing, then return error.
+ */
+ va_list clean_args;
+
+ /* end the current list */
+ va_end(args);
+
+ /* now start cleaning up */
+ cur_arg = mp;
+ va_start(clean_args, mp);
+ while (n--) {
+ mp_clear(cur_arg);
+ cur_arg = va_arg(clean_args, mp_int*);
+ }
+ va_end(clean_args);
+ res = MP_MEM;
+ break;
+ }
+ n++;
+ cur_arg = va_arg(args, mp_int*);
+ }
+ va_end(args);
+ return res; /* Assumed ok, if error flagged above. */
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_init_multi.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_init_set.c b/dep/StormLib/src/libtommath/bn_mp_init_set.c
new file mode 100644
index 00000000000..853323f3aaa
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_init_set.c
@@ -0,0 +1,32 @@
+#include "tommath.h"
+#ifdef BN_MP_INIT_SET_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* initialize and set a digit */
+int mp_init_set (mp_int * a, mp_digit b)
+{
+ int err;
+ if ((err = mp_init(a)) != MP_OKAY) {
+ return err;
+ }
+ mp_set(a, b);
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_init_set.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_init_set_int.c b/dep/StormLib/src/libtommath/bn_mp_init_set_int.c
new file mode 100644
index 00000000000..b2f8727e336
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_init_set_int.c
@@ -0,0 +1,31 @@
+#include "tommath.h"
+#ifdef BN_MP_INIT_SET_INT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* initialize and set a digit */
+int mp_init_set_int (mp_int * a, unsigned long b)
+{
+ int err;
+ if ((err = mp_init(a)) != MP_OKAY) {
+ return err;
+ }
+ return mp_set_int(a, b);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_init_set_int.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_init_size.c b/dep/StormLib/src/libtommath/bn_mp_init_size.c
new file mode 100644
index 00000000000..17b8d9fceb0
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_init_size.c
@@ -0,0 +1,48 @@
+#include "tommath.h"
+#ifdef BN_MP_INIT_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* init an mp_init for a given size */
+int mp_init_size (mp_int * a, int size)
+{
+ int x;
+
+ /* pad size so there are always extra digits */
+ size += (MP_PREC * 2) - (size % MP_PREC);
+
+ /* alloc mem */
+ a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size);
+ if (a->dp == NULL) {
+ return MP_MEM;
+ }
+
+ /* set the members */
+ a->used = 0;
+ a->alloc = size;
+ a->sign = MP_ZPOS;
+
+ /* zero the digits */
+ for (x = 0; x < size; x++) {
+ a->dp[x] = 0;
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_init_size.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_invmod.c b/dep/StormLib/src/libtommath/bn_mp_invmod.c
new file mode 100644
index 00000000000..038e584a25c
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_invmod.c
@@ -0,0 +1,43 @@
+#include "tommath.h"
+#ifdef BN_MP_INVMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* hac 14.61, pp608 */
+int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
+{
+ /* b cannot be negative */
+ if (b->sign == MP_NEG || mp_iszero(b) == 1) {
+ return MP_VAL;
+ }
+
+#ifdef BN_FAST_MP_INVMOD_C
+ /* if the modulus is odd we can use a faster routine instead */
+ if (mp_isodd (b) == 1) {
+ return fast_mp_invmod (a, b, c);
+ }
+#endif
+
+#ifdef BN_MP_INVMOD_SLOW_C
+ return mp_invmod_slow(a, b, c);
+#endif
+
+ return MP_VAL;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_invmod.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_invmod_slow.c b/dep/StormLib/src/libtommath/bn_mp_invmod_slow.c
new file mode 100644
index 00000000000..3792a4c2333
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_invmod_slow.c
@@ -0,0 +1,175 @@
+#include "tommath.h"
+#ifdef BN_MP_INVMOD_SLOW_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* hac 14.61, pp608 */
+int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int x, y, u, v, A, B, C, D;
+ int res;
+
+ /* b cannot be negative */
+ if (b->sign == MP_NEG || mp_iszero(b) == 1) {
+ return MP_VAL;
+ }
+
+ /* init temps */
+ if ((res = mp_init_multi(&x, &y, &u, &v,
+ &A, &B, &C, &D, NULL)) != MP_OKAY) {
+ return res;
+ }
+
+ /* x = a, y = b */
+ if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_copy (b, &y)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* 2. [modified] if x,y are both even then return an error! */
+ if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) {
+ res = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+ if ((res = mp_copy (&x, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_copy (&y, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ mp_set (&A, 1);
+ mp_set (&D, 1);
+
+top:
+ /* 4. while u is even do */
+ while (mp_iseven (&u) == 1) {
+ /* 4.1 u = u/2 */
+ if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* 4.2 if A or B is odd then */
+ if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
+ /* A = (A+y)/2, B = (B-x)/2 */
+ if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* A = A/2, B = B/2 */
+ if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* 5. while v is even do */
+ while (mp_iseven (&v) == 1) {
+ /* 5.1 v = v/2 */
+ if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* 5.2 if C or D is odd then */
+ if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) {
+ /* C = (C+y)/2, D = (D-x)/2 */
+ if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* C = C/2, D = D/2 */
+ if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* 6. if u >= v then */
+ if (mp_cmp (&u, &v) != MP_LT) {
+ /* u = u - v, A = A - C, B = B - D */
+ if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ } else {
+ /* v - v - u, C = C - A, D = D - B */
+ if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* if not zero goto step 4 */
+ if (mp_iszero (&u) == 0)
+ goto top;
+
+ /* now a = C, b = D, gcd == g*v */
+
+ /* if v != 1 then there is no inverse */
+ if (mp_cmp_d (&v, 1) != MP_EQ) {
+ res = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* if its too low */
+ while (mp_cmp_d(&C, 0) == MP_LT) {
+ if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* too big */
+ while (mp_cmp_mag(&C, b) != MP_LT) {
+ if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* C is now the inverse */
+ mp_exch (&C, c);
+ res = MP_OKAY;
+LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_invmod_slow.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_is_square.c b/dep/StormLib/src/libtommath/bn_mp_is_square.c
new file mode 100644
index 00000000000..5d2fa072ce9
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_is_square.c
@@ -0,0 +1,109 @@
+#include "tommath.h"
+#ifdef BN_MP_IS_SQUARE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Check if remainders are possible squares - fast exclude non-squares */
+static const char rem_128[128] = {
+ 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1
+};
+
+static const char rem_105[105] = {
+ 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1,
+ 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1
+};
+
+/* Store non-zero to ret if arg is square, and zero if not */
+int mp_is_square(mp_int *arg,int *ret)
+{
+ int res;
+ mp_digit c;
+ mp_int t;
+ unsigned long r;
+
+ /* Default to Non-square :) */
+ *ret = MP_NO;
+
+ if (arg->sign == MP_NEG) {
+ return MP_VAL;
+ }
+
+ /* digits used? (TSD) */
+ if (arg->used == 0) {
+ return MP_OKAY;
+ }
+
+ /* First check mod 128 (suppose that DIGIT_BIT is at least 7) */
+ if (rem_128[127 & DIGIT(arg,0)] == 1) {
+ return MP_OKAY;
+ }
+
+ /* Next check mod 105 (3*5*7) */
+ if ((res = mp_mod_d(arg,105,&c)) != MP_OKAY) {
+ return res;
+ }
+ if (rem_105[c] == 1) {
+ return MP_OKAY;
+ }
+
+
+ if ((res = mp_init_set_int(&t,11L*13L*17L*19L*23L*29L*31L)) != MP_OKAY) {
+ return res;
+ }
+ if ((res = mp_mod(arg,&t,&t)) != MP_OKAY) {
+ goto ERR;
+ }
+ r = mp_get_int(&t);
+ /* Check for other prime modules, note it's not an ERROR but we must
+ * free "t" so the easiest way is to goto ERR. We know that res
+ * is already equal to MP_OKAY from the mp_mod call
+ */
+ if ( (1L<<(r%11)) & 0x5C4L ) goto ERR;
+ if ( (1L<<(r%13)) & 0x9E4L ) goto ERR;
+ if ( (1L<<(r%17)) & 0x5CE8L ) goto ERR;
+ if ( (1L<<(r%19)) & 0x4F50CL ) goto ERR;
+ if ( (1L<<(r%23)) & 0x7ACCA0L ) goto ERR;
+ if ( (1L<<(r%29)) & 0xC2EDD0CL ) goto ERR;
+ if ( (1L<<(r%31)) & 0x6DE2B848L ) goto ERR;
+
+ /* Final check - is sqr(sqrt(arg)) == arg ? */
+ if ((res = mp_sqrt(arg,&t)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sqr(&t,&t)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ *ret = (mp_cmp_mag(&t,arg) == MP_EQ) ? MP_YES : MP_NO;
+ERR:mp_clear(&t);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_is_square.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_jacobi.c b/dep/StormLib/src/libtommath/bn_mp_jacobi.c
new file mode 100644
index 00000000000..c70b946f316
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_jacobi.c
@@ -0,0 +1,105 @@
+#include "tommath.h"
+#ifdef BN_MP_JACOBI_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes the jacobi c = (a | n) (or Legendre if n is prime)
+ * HAC pp. 73 Algorithm 2.149
+ */
+int mp_jacobi (mp_int * a, mp_int * p, int *c)
+{
+ mp_int a1, p1;
+ int k, s, r, res;
+ mp_digit residue;
+
+ /* if p <= 0 return MP_VAL */
+ if (mp_cmp_d(p, 0) != MP_GT) {
+ return MP_VAL;
+ }
+
+ /* step 1. if a == 0, return 0 */
+ if (mp_iszero (a) == 1) {
+ *c = 0;
+ return MP_OKAY;
+ }
+
+ /* step 2. if a == 1, return 1 */
+ if (mp_cmp_d (a, 1) == MP_EQ) {
+ *c = 1;
+ return MP_OKAY;
+ }
+
+ /* default */
+ s = 0;
+
+ /* step 3. write a = a1 * 2**k */
+ if ((res = mp_init_copy (&a1, a)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_init (&p1)) != MP_OKAY) {
+ goto LBL_A1;
+ }
+
+ /* divide out larger power of two */
+ k = mp_cnt_lsb(&a1);
+ if ((res = mp_div_2d(&a1, k, &a1, NULL)) != MP_OKAY) {
+ goto LBL_P1;
+ }
+
+ /* step 4. if e is even set s=1 */
+ if ((k & 1) == 0) {
+ s = 1;
+ } else {
+ /* else set s=1 if p = 1/7 (mod 8) or s=-1 if p = 3/5 (mod 8) */
+ residue = p->dp[0] & 7;
+
+ if (residue == 1 || residue == 7) {
+ s = 1;
+ } else if (residue == 3 || residue == 5) {
+ s = -1;
+ }
+ }
+
+ /* step 5. if p == 3 (mod 4) *and* a1 == 3 (mod 4) then s = -s */
+ if ( ((p->dp[0] & 3) == 3) && ((a1.dp[0] & 3) == 3)) {
+ s = -s;
+ }
+
+ /* if a1 == 1 we're done */
+ if (mp_cmp_d (&a1, 1) == MP_EQ) {
+ *c = s;
+ } else {
+ /* n1 = n mod a1 */
+ if ((res = mp_mod (p, &a1, &p1)) != MP_OKAY) {
+ goto LBL_P1;
+ }
+ if ((res = mp_jacobi (&p1, &a1, &r)) != MP_OKAY) {
+ goto LBL_P1;
+ }
+ *c = s * r;
+ }
+
+ /* done */
+ res = MP_OKAY;
+LBL_P1:mp_clear (&p1);
+LBL_A1:mp_clear (&a1);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_jacobi.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_karatsuba_mul.c b/dep/StormLib/src/libtommath/bn_mp_karatsuba_mul.c
new file mode 100644
index 00000000000..b15ec24966b
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_karatsuba_mul.c
@@ -0,0 +1,167 @@
+#include "tommath.h"
+#ifdef BN_MP_KARATSUBA_MUL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* c = |a| * |b| using Karatsuba Multiplication using
+ * three half size multiplications
+ *
+ * Let B represent the radix [e.g. 2**DIGIT_BIT] and
+ * let n represent half of the number of digits in
+ * the min(a,b)
+ *
+ * a = a1 * B**n + a0
+ * b = b1 * B**n + b0
+ *
+ * Then, a * b =>
+ a1b1 * B**2n + ((a1 + a0)(b1 + b0) - (a0b0 + a1b1)) * B + a0b0
+ *
+ * Note that a1b1 and a0b0 are used twice and only need to be
+ * computed once. So in total three half size (half # of
+ * digit) multiplications are performed, a0b0, a1b1 and
+ * (a1+b1)(a0+b0)
+ *
+ * Note that a multiplication of half the digits requires
+ * 1/4th the number of single precision multiplications so in
+ * total after one call 25% of the single precision multiplications
+ * are saved. Note also that the call to mp_mul can end up back
+ * in this function if the a0, a1, b0, or b1 are above the threshold.
+ * This is known as divide-and-conquer and leads to the famous
+ * O(N**lg(3)) or O(N**1.584) work which is asymptopically lower than
+ * the standard O(N**2) that the baseline/comba methods use.
+ * Generally though the overhead of this method doesn't pay off
+ * until a certain size (N ~ 80) is reached.
+ */
+int mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int x0, x1, y0, y1, t1, x0y0, x1y1;
+ int B, err;
+
+ /* default the return code to an error */
+ err = MP_MEM;
+
+ /* min # of digits */
+ B = MIN (a->used, b->used);
+
+ /* now divide in two */
+ B = B >> 1;
+
+ /* init copy all the temps */
+ if (mp_init_size (&x0, B) != MP_OKAY)
+ goto ERR;
+ if (mp_init_size (&x1, a->used - B) != MP_OKAY)
+ goto X0;
+ if (mp_init_size (&y0, B) != MP_OKAY)
+ goto X1;
+ if (mp_init_size (&y1, b->used - B) != MP_OKAY)
+ goto Y0;
+
+ /* init temps */
+ if (mp_init_size (&t1, B * 2) != MP_OKAY)
+ goto Y1;
+ if (mp_init_size (&x0y0, B * 2) != MP_OKAY)
+ goto T1;
+ if (mp_init_size (&x1y1, B * 2) != MP_OKAY)
+ goto X0Y0;
+
+ /* now shift the digits */
+ x0.used = y0.used = B;
+ x1.used = a->used - B;
+ y1.used = b->used - B;
+
+ {
+ register int x;
+ register mp_digit *tmpa, *tmpb, *tmpx, *tmpy;
+
+ /* we copy the digits directly instead of using higher level functions
+ * since we also need to shift the digits
+ */
+ tmpa = a->dp;
+ tmpb = b->dp;
+
+ tmpx = x0.dp;
+ tmpy = y0.dp;
+ for (x = 0; x < B; x++) {
+ *tmpx++ = *tmpa++;
+ *tmpy++ = *tmpb++;
+ }
+
+ tmpx = x1.dp;
+ for (x = B; x < a->used; x++) {
+ *tmpx++ = *tmpa++;
+ }
+
+ tmpy = y1.dp;
+ for (x = B; x < b->used; x++) {
+ *tmpy++ = *tmpb++;
+ }
+ }
+
+ /* only need to clamp the lower words since by definition the
+ * upper words x1/y1 must have a known number of digits
+ */
+ mp_clamp (&x0);
+ mp_clamp (&y0);
+
+ /* now calc the products x0y0 and x1y1 */
+ /* after this x0 is no longer required, free temp [x0==t2]! */
+ if (mp_mul (&x0, &y0, &x0y0) != MP_OKAY)
+ goto X1Y1; /* x0y0 = x0*y0 */
+ if (mp_mul (&x1, &y1, &x1y1) != MP_OKAY)
+ goto X1Y1; /* x1y1 = x1*y1 */
+
+ /* now calc x1+x0 and y1+y0 */
+ if (s_mp_add (&x1, &x0, &t1) != MP_OKAY)
+ goto X1Y1; /* t1 = x1 - x0 */
+ if (s_mp_add (&y1, &y0, &x0) != MP_OKAY)
+ goto X1Y1; /* t2 = y1 - y0 */
+ if (mp_mul (&t1, &x0, &t1) != MP_OKAY)
+ goto X1Y1; /* t1 = (x1 + x0) * (y1 + y0) */
+
+ /* add x0y0 */
+ if (mp_add (&x0y0, &x1y1, &x0) != MP_OKAY)
+ goto X1Y1; /* t2 = x0y0 + x1y1 */
+ if (s_mp_sub (&t1, &x0, &t1) != MP_OKAY)
+ goto X1Y1; /* t1 = (x1+x0)*(y1+y0) - (x1y1 + x0y0) */
+
+ /* shift by B */
+ if (mp_lshd (&t1, B) != MP_OKAY)
+ goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<<B */
+ if (mp_lshd (&x1y1, B * 2) != MP_OKAY)
+ goto X1Y1; /* x1y1 = x1y1 << 2*B */
+
+ if (mp_add (&x0y0, &t1, &t1) != MP_OKAY)
+ goto X1Y1; /* t1 = x0y0 + t1 */
+ if (mp_add (&t1, &x1y1, c) != MP_OKAY)
+ goto X1Y1; /* t1 = x0y0 + t1 + x1y1 */
+
+ /* Algorithm succeeded set the return code to MP_OKAY */
+ err = MP_OKAY;
+
+X1Y1:mp_clear (&x1y1);
+X0Y0:mp_clear (&x0y0);
+T1:mp_clear (&t1);
+Y1:mp_clear (&y1);
+Y0:mp_clear (&y0);
+X1:mp_clear (&x1);
+X0:mp_clear (&x0);
+ERR:
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_karatsuba_mul.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_karatsuba_sqr.c b/dep/StormLib/src/libtommath/bn_mp_karatsuba_sqr.c
new file mode 100644
index 00000000000..b3a45abf70e
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_karatsuba_sqr.c
@@ -0,0 +1,121 @@
+#include "tommath.h"
+#ifdef BN_MP_KARATSUBA_SQR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Karatsuba squaring, computes b = a*a using three
+ * half size squarings
+ *
+ * See comments of karatsuba_mul for details. It
+ * is essentially the same algorithm but merely
+ * tuned to perform recursive squarings.
+ */
+int mp_karatsuba_sqr (mp_int * a, mp_int * b)
+{
+ mp_int x0, x1, t1, t2, x0x0, x1x1;
+ int B, err;
+
+ err = MP_MEM;
+
+ /* min # of digits */
+ B = a->used;
+
+ /* now divide in two */
+ B = B >> 1;
+
+ /* init copy all the temps */
+ if (mp_init_size (&x0, B) != MP_OKAY)
+ goto ERR;
+ if (mp_init_size (&x1, a->used - B) != MP_OKAY)
+ goto X0;
+
+ /* init temps */
+ if (mp_init_size (&t1, a->used * 2) != MP_OKAY)
+ goto X1;
+ if (mp_init_size (&t2, a->used * 2) != MP_OKAY)
+ goto T1;
+ if (mp_init_size (&x0x0, B * 2) != MP_OKAY)
+ goto T2;
+ if (mp_init_size (&x1x1, (a->used - B) * 2) != MP_OKAY)
+ goto X0X0;
+
+ {
+ register int x;
+ register mp_digit *dst, *src;
+
+ src = a->dp;
+
+ /* now shift the digits */
+ dst = x0.dp;
+ for (x = 0; x < B; x++) {
+ *dst++ = *src++;
+ }
+
+ dst = x1.dp;
+ for (x = B; x < a->used; x++) {
+ *dst++ = *src++;
+ }
+ }
+
+ x0.used = B;
+ x1.used = a->used - B;
+
+ mp_clamp (&x0);
+
+ /* now calc the products x0*x0 and x1*x1 */
+ if (mp_sqr (&x0, &x0x0) != MP_OKAY)
+ goto X1X1; /* x0x0 = x0*x0 */
+ if (mp_sqr (&x1, &x1x1) != MP_OKAY)
+ goto X1X1; /* x1x1 = x1*x1 */
+
+ /* now calc (x1+x0)**2 */
+ if (s_mp_add (&x1, &x0, &t1) != MP_OKAY)
+ goto X1X1; /* t1 = x1 - x0 */
+ if (mp_sqr (&t1, &t1) != MP_OKAY)
+ goto X1X1; /* t1 = (x1 - x0) * (x1 - x0) */
+
+ /* add x0y0 */
+ if (s_mp_add (&x0x0, &x1x1, &t2) != MP_OKAY)
+ goto X1X1; /* t2 = x0x0 + x1x1 */
+ if (s_mp_sub (&t1, &t2, &t1) != MP_OKAY)
+ goto X1X1; /* t1 = (x1+x0)**2 - (x0x0 + x1x1) */
+
+ /* shift by B */
+ if (mp_lshd (&t1, B) != MP_OKAY)
+ goto X1X1; /* t1 = (x0x0 + x1x1 - (x1-x0)*(x1-x0))<<B */
+ if (mp_lshd (&x1x1, B * 2) != MP_OKAY)
+ goto X1X1; /* x1x1 = x1x1 << 2*B */
+
+ if (mp_add (&x0x0, &t1, &t1) != MP_OKAY)
+ goto X1X1; /* t1 = x0x0 + t1 */
+ if (mp_add (&t1, &x1x1, b) != MP_OKAY)
+ goto X1X1; /* t1 = x0x0 + t1 + x1x1 */
+
+ err = MP_OKAY;
+
+X1X1:mp_clear (&x1x1);
+X0X0:mp_clear (&x0x0);
+T2:mp_clear (&t2);
+T1:mp_clear (&t1);
+X1:mp_clear (&x1);
+X0:mp_clear (&x0);
+ERR:
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_karatsuba_sqr.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_lcm.c b/dep/StormLib/src/libtommath/bn_mp_lcm.c
new file mode 100644
index 00000000000..af7ae23729e
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_lcm.c
@@ -0,0 +1,60 @@
+#include "tommath.h"
+#ifdef BN_MP_LCM_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes least common multiple as |a*b|/(a, b) */
+int mp_lcm (mp_int * a, mp_int * b, mp_int * c)
+{
+ int res;
+ mp_int t1, t2;
+
+
+ if ((res = mp_init_multi (&t1, &t2, NULL)) != MP_OKAY) {
+ return res;
+ }
+
+ /* t1 = get the GCD of the two inputs */
+ if ((res = mp_gcd (a, b, &t1)) != MP_OKAY) {
+ goto LBL_T;
+ }
+
+ /* divide the smallest by the GCD */
+ if (mp_cmp_mag(a, b) == MP_LT) {
+ /* store quotient in t2 such that t2 * b is the LCM */
+ if ((res = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) {
+ goto LBL_T;
+ }
+ res = mp_mul(b, &t2, c);
+ } else {
+ /* store quotient in t2 such that t2 * a is the LCM */
+ if ((res = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) {
+ goto LBL_T;
+ }
+ res = mp_mul(a, &t2, c);
+ }
+
+ /* fix the sign to positive */
+ c->sign = MP_ZPOS;
+
+LBL_T:
+ mp_clear_multi (&t1, &t2, NULL);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_lcm.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_lshd.c b/dep/StormLib/src/libtommath/bn_mp_lshd.c
new file mode 100644
index 00000000000..ffb0defd06b
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_lshd.c
@@ -0,0 +1,67 @@
+#include "tommath.h"
+#ifdef BN_MP_LSHD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* shift left a certain amount of digits */
+int mp_lshd (mp_int * a, int b)
+{
+ int x, res;
+
+ /* if its less than zero return */
+ if (b <= 0) {
+ return MP_OKAY;
+ }
+
+ /* grow to fit the new digits */
+ if (a->alloc < a->used + b) {
+ if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ {
+ register mp_digit *top, *bottom;
+
+ /* increment the used by the shift amount then copy upwards */
+ a->used += b;
+
+ /* top */
+ top = a->dp + a->used - 1;
+
+ /* base */
+ bottom = a->dp + a->used - 1 - b;
+
+ /* much like mp_rshd this is implemented using a sliding window
+ * except the window goes the otherway around. Copying from
+ * the bottom to the top. see bn_mp_rshd.c for more info.
+ */
+ for (x = a->used - 1; x >= b; x--) {
+ *top-- = *bottom--;
+ }
+
+ /* zero the lower digits */
+ top = a->dp;
+ for (x = 0; x < b; x++) {
+ *top++ = 0;
+ }
+ }
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_lshd.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_mod.c b/dep/StormLib/src/libtommath/bn_mp_mod.c
new file mode 100644
index 00000000000..b24c71f9d95
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_mod.c
@@ -0,0 +1,48 @@
+#include "tommath.h"
+#ifdef BN_MP_MOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* c = a mod b, 0 <= c < b */
+int
+mp_mod (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int t;
+ int res;
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+
+ if (t.sign != b->sign) {
+ res = mp_add (b, &t, c);
+ } else {
+ res = MP_OKAY;
+ mp_exch (&t, c);
+ }
+
+ mp_clear (&t);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mod.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_mod_2d.c b/dep/StormLib/src/libtommath/bn_mp_mod_2d.c
new file mode 100644
index 00000000000..a54a0242644
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_mod_2d.c
@@ -0,0 +1,55 @@
+#include "tommath.h"
+#ifdef BN_MP_MOD_2D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* calc a value mod 2**b */
+int
+mp_mod_2d (mp_int * a, int b, mp_int * c)
+{
+ int x, res;
+
+ /* if b is <= 0 then zero the int */
+ if (b <= 0) {
+ mp_zero (c);
+ return MP_OKAY;
+ }
+
+ /* if the modulus is larger than the value than return */
+ if (b >= (int) (a->used * DIGIT_BIT)) {
+ res = mp_copy (a, c);
+ return res;
+ }
+
+ /* copy */
+ if ((res = mp_copy (a, c)) != MP_OKAY) {
+ return res;
+ }
+
+ /* zero digits above the last digit of the modulus */
+ for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
+ c->dp[x] = 0;
+ }
+ /* clear the digit that is not completely outside/inside the modulus */
+ c->dp[b / DIGIT_BIT] &=
+ (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
+ mp_clamp (c);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mod_2d.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_mod_d.c b/dep/StormLib/src/libtommath/bn_mp_mod_d.c
new file mode 100644
index 00000000000..59886e7734a
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_mod_d.c
@@ -0,0 +1,27 @@
+#include "tommath.h"
+#ifdef BN_MP_MOD_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+int
+mp_mod_d (mp_int * a, mp_digit b, mp_digit * c)
+{
+ return mp_div_d(a, b, NULL, c);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mod_d.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_montgomery_calc_normalization.c b/dep/StormLib/src/libtommath/bn_mp_montgomery_calc_normalization.c
new file mode 100644
index 00000000000..fdefcbd99d2
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_montgomery_calc_normalization.c
@@ -0,0 +1,59 @@
+#include "tommath.h"
+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/*
+ * shifts with subtractions when the result is greater than b.
+ *
+ * The method is slightly modified to shift B unconditionally upto just under
+ * the leading bit of b. This saves alot of multiple precision shifting.
+ */
+int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
+{
+ int x, bits, res;
+
+ /* how many bits of last digit does b use */
+ bits = mp_count_bits (b) % DIGIT_BIT;
+
+ if (b->used > 1) {
+ if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
+ return res;
+ }
+ } else {
+ mp_set(a, 1);
+ bits = 1;
+ }
+
+
+ /* now compute C = A * B mod b */
+ for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
+ if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
+ return res;
+ }
+ if (mp_cmp_mag (a, b) != MP_LT) {
+ if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
+ return res;
+ }
+ }
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_montgomery_calc_normalization.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_montgomery_reduce.c b/dep/StormLib/src/libtommath/bn_mp_montgomery_reduce.c
new file mode 100644
index 00000000000..173848e0ac8
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_montgomery_reduce.c
@@ -0,0 +1,118 @@
+#include "tommath.h"
+#ifdef BN_MP_MONTGOMERY_REDUCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes xR**-1 == x (mod N) via Montgomery Reduction */
+int
+mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+{
+ int ix, res, digs;
+ mp_digit mu;
+
+ /* can the fast reduction [comba] method be used?
+ *
+ * Note that unlike in mul you're safely allowed *less*
+ * than the available columns [255 per default] since carries
+ * are fixed up in the inner loop.
+ */
+ digs = n->used * 2 + 1;
+ if ((digs < MP_WARRAY) &&
+ n->used <
+ (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ return fast_mp_montgomery_reduce (x, n, rho);
+ }
+
+ /* grow the input as required */
+ if (x->alloc < digs) {
+ if ((res = mp_grow (x, digs)) != MP_OKAY) {
+ return res;
+ }
+ }
+ x->used = digs;
+
+ for (ix = 0; ix < n->used; ix++) {
+ /* mu = ai * rho mod b
+ *
+ * The value of rho must be precalculated via
+ * montgomery_setup() such that
+ * it equals -1/n0 mod b this allows the
+ * following inner loop to reduce the
+ * input one digit at a time
+ */
+ mu = (mp_digit) (((mp_word)x->dp[ix]) * ((mp_word)rho) & MP_MASK);
+
+ /* a = a + mu * m * b**i */
+ {
+ register int iy;
+ register mp_digit *tmpn, *tmpx, u;
+ register mp_word r;
+
+ /* alias for digits of the modulus */
+ tmpn = n->dp;
+
+ /* alias for the digits of x [the input] */
+ tmpx = x->dp + ix;
+
+ /* set the carry to zero */
+ u = 0;
+
+ /* Multiply and add in place */
+ for (iy = 0; iy < n->used; iy++) {
+ /* compute product and sum */
+ r = ((mp_word)mu) * ((mp_word)*tmpn++) +
+ ((mp_word) u) + ((mp_word) * tmpx);
+
+ /* get carry */
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+
+ /* fix digit */
+ *tmpx++ = (mp_digit)(r & ((mp_word) MP_MASK));
+ }
+ /* At this point the ix'th digit of x should be zero */
+
+
+ /* propagate carries upwards as required*/
+ while (u) {
+ *tmpx += u;
+ u = *tmpx >> DIGIT_BIT;
+ *tmpx++ &= MP_MASK;
+ }
+ }
+ }
+
+ /* at this point the n.used'th least
+ * significant digits of x are all zero
+ * which means we can shift x to the
+ * right by n.used digits and the
+ * residue is unchanged.
+ */
+
+ /* x = x/b**n.used */
+ mp_clamp(x);
+ mp_rshd (x, n->used);
+
+ /* if x >= n then x = x - n */
+ if (mp_cmp_mag (x, n) != MP_LT) {
+ return s_mp_sub (x, n, x);
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_montgomery_reduce.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_montgomery_setup.c b/dep/StormLib/src/libtommath/bn_mp_montgomery_setup.c
new file mode 100644
index 00000000000..6f277320eb7
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_montgomery_setup.c
@@ -0,0 +1,59 @@
+#include "tommath.h"
+#ifdef BN_MP_MONTGOMERY_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* setups the montgomery reduction stuff */
+int
+mp_montgomery_setup (mp_int * n, mp_digit * rho)
+{
+ mp_digit x, b;
+
+/* fast inversion mod 2**k
+ *
+ * Based on the fact that
+ *
+ * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n)
+ * => 2*X*A - X*X*A*A = 1
+ * => 2*(1) - (1) = 1
+ */
+ b = n->dp[0];
+
+ if ((b & 1) == 0) {
+ return MP_VAL;
+ }
+
+ x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
+ x *= 2 - b * x; /* here x*a==1 mod 2**8 */
+#if !defined(MP_8BIT)
+ x *= 2 - b * x; /* here x*a==1 mod 2**16 */
+#endif
+#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
+ x *= 2 - b * x; /* here x*a==1 mod 2**32 */
+#endif
+#ifdef MP_64BIT
+ x *= 2 - b * x; /* here x*a==1 mod 2**64 */
+#endif
+
+ /* rho = -1/m mod b */
+ *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK;
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_montgomery_setup.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_mul.c b/dep/StormLib/src/libtommath/bn_mp_mul.c
new file mode 100644
index 00000000000..a1315dac30c
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_mul.c
@@ -0,0 +1,66 @@
+#include "tommath.h"
+#ifdef BN_MP_MUL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* high level multiplication (handles sign) */
+int mp_mul (mp_int * a, mp_int * b, mp_int * c)
+{
+ int res, neg;
+ neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+
+ /* use Toom-Cook? */
+#ifdef BN_MP_TOOM_MUL_C
+ if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) {
+ res = mp_toom_mul(a, b, c);
+ } else
+#endif
+#ifdef BN_MP_KARATSUBA_MUL_C
+ /* use Karatsuba? */
+ if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) {
+ res = mp_karatsuba_mul (a, b, c);
+ } else
+#endif
+ {
+ /* can we use the fast multiplier?
+ *
+ * The fast multiplier can be used if the output will
+ * have less than MP_WARRAY digits and the number of
+ * digits won't affect carry propagation
+ */
+ int digs = a->used + b->used + 1;
+
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
+ if ((digs < MP_WARRAY) &&
+ MIN(a->used, b->used) <=
+ (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ res = fast_s_mp_mul_digs (a, b, c, digs);
+ } else
+#endif
+#ifdef BN_S_MP_MUL_DIGS_C
+ res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
+#else
+ res = MP_VAL;
+#endif
+
+ }
+ c->sign = (c->used > 0) ? neg : MP_ZPOS;
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mul.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_mul_2.c b/dep/StormLib/src/libtommath/bn_mp_mul_2.c
new file mode 100644
index 00000000000..3315744f1ec
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_mul_2.c
@@ -0,0 +1,82 @@
+#include "tommath.h"
+#ifdef BN_MP_MUL_2_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* b = a*2 */
+int mp_mul_2(mp_int * a, mp_int * b)
+{
+ int x, res, oldused;
+
+ /* grow to accomodate result */
+ if (b->alloc < a->used + 1) {
+ if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ oldused = b->used;
+ b->used = a->used;
+
+ {
+ register mp_digit r, rr, *tmpa, *tmpb;
+
+ /* alias for source */
+ tmpa = a->dp;
+
+ /* alias for dest */
+ tmpb = b->dp;
+
+ /* carry */
+ r = 0;
+ for (x = 0; x < a->used; x++) {
+
+ /* get what will be the *next* carry bit from the
+ * MSB of the current digit
+ */
+ rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
+
+ /* now shift up this digit, add in the carry [from the previous] */
+ *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
+
+ /* copy the carry that would be from the source
+ * digit into the next iteration
+ */
+ r = rr;
+ }
+
+ /* new leading digit? */
+ if (r != 0) {
+ /* add a MSB which is always 1 at this point */
+ *tmpb = 1;
+ ++(b->used);
+ }
+
+ /* now zero any excess digits on the destination
+ * that we didn't write to
+ */
+ tmpb = b->dp + b->used;
+ for (x = b->used; x < oldused; x++) {
+ *tmpb++ = 0;
+ }
+ }
+ b->sign = a->sign;
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mul_2.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_mul_2d.c b/dep/StormLib/src/libtommath/bn_mp_mul_2d.c
new file mode 100644
index 00000000000..c636c179884
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_mul_2d.c
@@ -0,0 +1,85 @@
+#include "tommath.h"
+#ifdef BN_MP_MUL_2D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* shift left by a certain bit count */
+int mp_mul_2d (mp_int * a, int b, mp_int * c)
+{
+ mp_digit d;
+ int res;
+
+ /* copy */
+ if (a != c) {
+ if ((res = mp_copy (a, c)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
+ if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* shift by as many digits in the bit count */
+ if (b >= (int)DIGIT_BIT) {
+ if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* shift any bit count < DIGIT_BIT */
+ d = (mp_digit) (b % DIGIT_BIT);
+ if (d != 0) {
+ register mp_digit *tmpc, shift, mask, r, rr;
+ register int x;
+
+ /* bitmask for carries */
+ mask = (((mp_digit)1) << d) - 1;
+
+ /* shift for msbs */
+ shift = DIGIT_BIT - d;
+
+ /* alias */
+ tmpc = c->dp;
+
+ /* carry */
+ r = 0;
+ for (x = 0; x < c->used; x++) {
+ /* get the higher bits of the current word */
+ rr = (*tmpc >> shift) & mask;
+
+ /* shift the current word and OR in the carry */
+ *tmpc = ((*tmpc << d) | r) & MP_MASK;
+ ++tmpc;
+
+ /* set the carry to the carry bits of the current word */
+ r = rr;
+ }
+
+ /* set final carry */
+ if (r != 0) {
+ c->dp[(c->used)++] = r;
+ }
+ }
+ mp_clamp (c);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mul_2d.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_mul_d.c b/dep/StormLib/src/libtommath/bn_mp_mul_d.c
new file mode 100644
index 00000000000..a36a76bbacf
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_mul_d.c
@@ -0,0 +1,79 @@
+#include "tommath.h"
+#ifdef BN_MP_MUL_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* multiply by a digit */
+int
+mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
+{
+ mp_digit u, *tmpa, *tmpc;
+ mp_word r;
+ int ix, res, olduse;
+
+ /* make sure c is big enough to hold a*b */
+ if (c->alloc < a->used + 1) {
+ if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* get the original destinations used count */
+ olduse = c->used;
+
+ /* set the sign */
+ c->sign = a->sign;
+
+ /* alias for a->dp [source] */
+ tmpa = a->dp;
+
+ /* alias for c->dp [dest] */
+ tmpc = c->dp;
+
+ /* zero carry */
+ u = 0;
+
+ /* compute columns */
+ for (ix = 0; ix < a->used; ix++) {
+ /* compute product and carry sum for this term */
+ r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
+
+ /* mask off higher bits to get a single digit */
+ *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* send carry into next iteration */
+ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+ }
+
+ /* store final carry [if any] and increment ix offset */
+ *tmpc++ = u;
+ ++ix;
+
+ /* now zero digits above the top */
+ while (ix++ < olduse) {
+ *tmpc++ = 0;
+ }
+
+ /* set used count */
+ c->used = a->used + 1;
+ mp_clamp(c);
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mul_d.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_mulmod.c b/dep/StormLib/src/libtommath/bn_mp_mulmod.c
new file mode 100644
index 00000000000..8ec98bbddb2
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_mulmod.c
@@ -0,0 +1,40 @@
+#include "tommath.h"
+#ifdef BN_MP_MULMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* d = a * b (mod c) */
+int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ int res;
+ mp_int t;
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_mul (a, b, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ res = mp_mod (&t, c, d);
+ mp_clear (&t);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mulmod.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_n_root.c b/dep/StormLib/src/libtommath/bn_mp_n_root.c
new file mode 100644
index 00000000000..f188f5255b3
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_n_root.c
@@ -0,0 +1,132 @@
+#include "tommath.h"
+#ifdef BN_MP_N_ROOT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* find the n'th root of an integer
+ *
+ * Result found such that (c)**b <= a and (c+1)**b > a
+ *
+ * This algorithm uses Newton's approximation
+ * x[i+1] = x[i] - f(x[i])/f'(x[i])
+ * which will find the root in log(N) time where
+ * each step involves a fair bit. This is not meant to
+ * find huge roots [square and cube, etc].
+ */
+int mp_n_root (mp_int * a, mp_digit b, mp_int * c)
+{
+ mp_int t1, t2, t3;
+ int res, neg;
+
+ /* input must be positive if b is even */
+ if ((b & 1) == 0 && a->sign == MP_NEG) {
+ return MP_VAL;
+ }
+
+ if ((res = mp_init (&t1)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_init (&t2)) != MP_OKAY) {
+ goto LBL_T1;
+ }
+
+ if ((res = mp_init (&t3)) != MP_OKAY) {
+ goto LBL_T2;
+ }
+
+ /* if a is negative fudge the sign but keep track */
+ neg = a->sign;
+ a->sign = MP_ZPOS;
+
+ /* t2 = 2 */
+ mp_set (&t2, 2);
+
+ do {
+ /* t1 = t2 */
+ if ((res = mp_copy (&t2, &t1)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+
+ /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */
+
+ /* t3 = t1**(b-1) */
+ if ((res = mp_expt_d (&t1, b - 1, &t3)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+
+ /* numerator */
+ /* t2 = t1**b */
+ if ((res = mp_mul (&t3, &t1, &t2)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+
+ /* t2 = t1**b - a */
+ if ((res = mp_sub (&t2, a, &t2)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+
+ /* denominator */
+ /* t3 = t1**(b-1) * b */
+ if ((res = mp_mul_d (&t3, b, &t3)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+
+ /* t3 = (t1**b - a)/(b * t1**(b-1)) */
+ if ((res = mp_div (&t2, &t3, &t3, NULL)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+
+ if ((res = mp_sub (&t1, &t3, &t2)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+ } while (mp_cmp (&t1, &t2) != MP_EQ);
+
+ /* result can be off by a few so check */
+ for (;;) {
+ if ((res = mp_expt_d (&t1, b, &t2)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+
+ if (mp_cmp (&t2, a) == MP_GT) {
+ if ((res = mp_sub_d (&t1, 1, &t1)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+ } else {
+ break;
+ }
+ }
+
+ /* reset the sign of a first */
+ a->sign = neg;
+
+ /* set the result */
+ mp_exch (&t1, c);
+
+ /* set the sign of the result */
+ c->sign = neg;
+
+ res = MP_OKAY;
+
+LBL_T3:mp_clear (&t3);
+LBL_T2:mp_clear (&t2);
+LBL_T1:mp_clear (&t1);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_n_root.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_neg.c b/dep/StormLib/src/libtommath/bn_mp_neg.c
new file mode 100644
index 00000000000..87a8b500449
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_neg.c
@@ -0,0 +1,40 @@
+#include "tommath.h"
+#ifdef BN_MP_NEG_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* b = -a */
+int mp_neg (mp_int * a, mp_int * b)
+{
+ int res;
+ if (a != b) {
+ if ((res = mp_copy (a, b)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ if (mp_iszero(b) != MP_YES) {
+ b->sign = (a->sign == MP_ZPOS) ? MP_NEG : MP_ZPOS;
+ } else {
+ b->sign = MP_ZPOS;
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_neg.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_or.c b/dep/StormLib/src/libtommath/bn_mp_or.c
new file mode 100644
index 00000000000..12601eaf78e
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_or.c
@@ -0,0 +1,50 @@
+#include "tommath.h"
+#ifdef BN_MP_OR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* OR two ints together */
+int mp_or (mp_int * a, mp_int * b, mp_int * c)
+{
+ int res, ix, px;
+ mp_int t, *x;
+
+ if (a->used > b->used) {
+ if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
+ return res;
+ }
+ px = b->used;
+ x = b;
+ } else {
+ if ((res = mp_init_copy (&t, b)) != MP_OKAY) {
+ return res;
+ }
+ px = a->used;
+ x = a;
+ }
+
+ for (ix = 0; ix < px; ix++) {
+ t.dp[ix] |= x->dp[ix];
+ }
+ mp_clamp (&t);
+ mp_exch (c, &t);
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_or.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_prime_fermat.c b/dep/StormLib/src/libtommath/bn_mp_prime_fermat.c
new file mode 100644
index 00000000000..297e13c7960
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_prime_fermat.c
@@ -0,0 +1,62 @@
+#include "tommath.h"
+#ifdef BN_MP_PRIME_FERMAT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* performs one Fermat test.
+ *
+ * If "a" were prime then b**a == b (mod a) since the order of
+ * the multiplicative sub-group would be phi(a) = a-1. That means
+ * it would be the same as b**(a mod (a-1)) == b**1 == b (mod a).
+ *
+ * Sets result to 1 if the congruence holds, or zero otherwise.
+ */
+int mp_prime_fermat (mp_int * a, mp_int * b, int *result)
+{
+ mp_int t;
+ int err;
+
+ /* default to composite */
+ *result = MP_NO;
+
+ /* ensure b > 1 */
+ if (mp_cmp_d(b, 1) != MP_GT) {
+ return MP_VAL;
+ }
+
+ /* init t */
+ if ((err = mp_init (&t)) != MP_OKAY) {
+ return err;
+ }
+
+ /* compute t = b**a mod a */
+ if ((err = mp_exptmod (b, a, a, &t)) != MP_OKAY) {
+ goto LBL_T;
+ }
+
+ /* is it equal to b? */
+ if (mp_cmp (&t, b) == MP_EQ) {
+ *result = MP_YES;
+ }
+
+ err = MP_OKAY;
+LBL_T:mp_clear (&t);
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_prime_fermat.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_prime_is_divisible.c b/dep/StormLib/src/libtommath/bn_mp_prime_is_divisible.c
new file mode 100644
index 00000000000..0ae64983512
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_prime_is_divisible.c
@@ -0,0 +1,50 @@
+#include "tommath.h"
+#ifdef BN_MP_PRIME_IS_DIVISIBLE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* determines if an integers is divisible by one
+ * of the first PRIME_SIZE primes or not
+ *
+ * sets result to 0 if not, 1 if yes
+ */
+int mp_prime_is_divisible (mp_int * a, int *result)
+{
+ int err, ix;
+ mp_digit res;
+
+ /* default to not */
+ *result = MP_NO;
+
+ for (ix = 0; ix < PRIME_SIZE; ix++) {
+ /* what is a mod LBL_prime_tab[ix] */
+ if ((err = mp_mod_d (a, ltm_prime_tab[ix], &res)) != MP_OKAY) {
+ return err;
+ }
+
+ /* is the residue zero? */
+ if (res == 0) {
+ *result = MP_YES;
+ return MP_OKAY;
+ }
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_prime_is_divisible.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_prime_is_prime.c b/dep/StormLib/src/libtommath/bn_mp_prime_is_prime.c
new file mode 100644
index 00000000000..0e1e94bad5b
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_prime_is_prime.c
@@ -0,0 +1,83 @@
+#include "tommath.h"
+#ifdef BN_MP_PRIME_IS_PRIME_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* performs a variable number of rounds of Miller-Rabin
+ *
+ * Probability of error after t rounds is no more than
+
+ *
+ * Sets result to 1 if probably prime, 0 otherwise
+ */
+int mp_prime_is_prime (mp_int * a, int t, int *result)
+{
+ mp_int b;
+ int ix, err, res;
+
+ /* default to no */
+ *result = MP_NO;
+
+ /* valid value of t? */
+ if (t <= 0 || t > PRIME_SIZE) {
+ return MP_VAL;
+ }
+
+ /* is the input equal to one of the primes in the table? */
+ for (ix = 0; ix < PRIME_SIZE; ix++) {
+ if (mp_cmp_d(a, ltm_prime_tab[ix]) == MP_EQ) {
+ *result = 1;
+ return MP_OKAY;
+ }
+ }
+
+ /* first perform trial division */
+ if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) {
+ return err;
+ }
+
+ /* return if it was trivially divisible */
+ if (res == MP_YES) {
+ return MP_OKAY;
+ }
+
+ /* now perform the miller-rabin rounds */
+ if ((err = mp_init (&b)) != MP_OKAY) {
+ return err;
+ }
+
+ for (ix = 0; ix < t; ix++) {
+ /* set the prime */
+ mp_set (&b, ltm_prime_tab[ix]);
+
+ if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) {
+ goto LBL_B;
+ }
+
+ if (res == MP_NO) {
+ goto LBL_B;
+ }
+ }
+
+ /* passed the test */
+ *result = MP_YES;
+LBL_B:mp_clear (&b);
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_prime_is_prime.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_prime_miller_rabin.c b/dep/StormLib/src/libtommath/bn_mp_prime_miller_rabin.c
new file mode 100644
index 00000000000..47385bc815c
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_prime_miller_rabin.c
@@ -0,0 +1,103 @@
+#include "tommath.h"
+#ifdef BN_MP_PRIME_MILLER_RABIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Miller-Rabin test of "a" to the base of "b" as described in
+ * HAC pp. 139 Algorithm 4.24
+ *
+ * Sets result to 0 if definitely composite or 1 if probably prime.
+ * Randomly the chance of error is no more than 1/4 and often
+ * very much lower.
+ */
+int mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result)
+{
+ mp_int n1, y, r;
+ int s, j, err;
+
+ /* default */
+ *result = MP_NO;
+
+ /* ensure b > 1 */
+ if (mp_cmp_d(b, 1) != MP_GT) {
+ return MP_VAL;
+ }
+
+ /* get n1 = a - 1 */
+ if ((err = mp_init_copy (&n1, a)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_sub_d (&n1, 1, &n1)) != MP_OKAY) {
+ goto LBL_N1;
+ }
+
+ /* set 2**s * r = n1 */
+ if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) {
+ goto LBL_N1;
+ }
+
+ /* count the number of least significant bits
+ * which are zero
+ */
+ s = mp_cnt_lsb(&r);
+
+ /* now divide n - 1 by 2**s */
+ if ((err = mp_div_2d (&r, s, &r, NULL)) != MP_OKAY) {
+ goto LBL_R;
+ }
+
+ /* compute y = b**r mod a */
+ if ((err = mp_init (&y)) != MP_OKAY) {
+ goto LBL_R;
+ }
+ if ((err = mp_exptmod (b, &r, a, &y)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ /* if y != 1 and y != n1 do */
+ if (mp_cmp_d (&y, 1) != MP_EQ && mp_cmp (&y, &n1) != MP_EQ) {
+ j = 1;
+ /* while j <= s-1 and y != n1 */
+ while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) {
+ if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ /* if y == 1 then composite */
+ if (mp_cmp_d (&y, 1) == MP_EQ) {
+ goto LBL_Y;
+ }
+
+ ++j;
+ }
+
+ /* if y != n1 then composite */
+ if (mp_cmp (&y, &n1) != MP_EQ) {
+ goto LBL_Y;
+ }
+ }
+
+ /* probably prime now */
+ *result = MP_YES;
+LBL_Y:mp_clear (&y);
+LBL_R:mp_clear (&r);
+LBL_N1:mp_clear (&n1);
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_prime_miller_rabin.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_prime_next_prime.c b/dep/StormLib/src/libtommath/bn_mp_prime_next_prime.c
new file mode 100644
index 00000000000..833992bac48
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_prime_next_prime.c
@@ -0,0 +1,170 @@
+#include "tommath.h"
+#ifdef BN_MP_PRIME_NEXT_PRIME_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* finds the next prime after the number "a" using "t" trials
+ * of Miller-Rabin.
+ *
+ * bbs_style = 1 means the prime must be congruent to 3 mod 4
+ */
+int mp_prime_next_prime(mp_int *a, int t, int bbs_style)
+{
+ int err, res, x, y;
+ mp_digit res_tab[PRIME_SIZE], step, kstep;
+ mp_int b;
+
+ /* ensure t is valid */
+ if (t <= 0 || t > PRIME_SIZE) {
+ return MP_VAL;
+ }
+
+ /* force positive */
+ a->sign = MP_ZPOS;
+
+ /* simple algo if a is less than the largest prime in the table */
+ if (mp_cmp_d(a, ltm_prime_tab[PRIME_SIZE-1]) == MP_LT) {
+ /* find which prime it is bigger than */
+ for (x = PRIME_SIZE - 2; x >= 0; x--) {
+ if (mp_cmp_d(a, ltm_prime_tab[x]) != MP_LT) {
+ if (bbs_style == 1) {
+ /* ok we found a prime smaller or
+ * equal [so the next is larger]
+ *
+ * however, the prime must be
+ * congruent to 3 mod 4
+ */
+ if ((ltm_prime_tab[x + 1] & 3) != 3) {
+ /* scan upwards for a prime congruent to 3 mod 4 */
+ for (y = x + 1; y < PRIME_SIZE; y++) {
+ if ((ltm_prime_tab[y] & 3) == 3) {
+ mp_set(a, ltm_prime_tab[y]);
+ return MP_OKAY;
+ }
+ }
+ }
+ } else {
+ mp_set(a, ltm_prime_tab[x + 1]);
+ return MP_OKAY;
+ }
+ }
+ }
+ /* at this point a maybe 1 */
+ if (mp_cmp_d(a, 1) == MP_EQ) {
+ mp_set(a, 2);
+ return MP_OKAY;
+ }
+ /* fall through to the sieve */
+ }
+
+ /* generate a prime congruent to 3 mod 4 or 1/3 mod 4? */
+ if (bbs_style == 1) {
+ kstep = 4;
+ } else {
+ kstep = 2;
+ }
+
+ /* at this point we will use a combination of a sieve and Miller-Rabin */
+
+ if (bbs_style == 1) {
+ /* if a mod 4 != 3 subtract the correct value to make it so */
+ if ((a->dp[0] & 3) != 3) {
+ if ((err = mp_sub_d(a, (a->dp[0] & 3) + 1, a)) != MP_OKAY) { return err; };
+ }
+ } else {
+ if (mp_iseven(a) == 1) {
+ /* force odd */
+ if ((err = mp_sub_d(a, 1, a)) != MP_OKAY) {
+ return err;
+ }
+ }
+ }
+
+ /* generate the restable */
+ for (x = 1; x < PRIME_SIZE; x++) {
+ if ((err = mp_mod_d(a, ltm_prime_tab[x], res_tab + x)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* init temp used for Miller-Rabin Testing */
+ if ((err = mp_init(&b)) != MP_OKAY) {
+ return err;
+ }
+
+ for (;;) {
+ /* skip to the next non-trivially divisible candidate */
+ step = 0;
+ do {
+ /* y == 1 if any residue was zero [e.g. cannot be prime] */
+ y = 0;
+
+ /* increase step to next candidate */
+ step += kstep;
+
+ /* compute the new residue without using division */
+ for (x = 1; x < PRIME_SIZE; x++) {
+ /* add the step to each residue */
+ res_tab[x] += kstep;
+
+ /* subtract the modulus [instead of using division] */
+ if (res_tab[x] >= ltm_prime_tab[x]) {
+ res_tab[x] -= ltm_prime_tab[x];
+ }
+
+ /* set flag if zero */
+ if (res_tab[x] == 0) {
+ y = 1;
+ }
+ }
+ } while (y == 1 && step < ((((mp_digit)1)<<DIGIT_BIT) - kstep));
+
+ /* add the step */
+ if ((err = mp_add_d(a, step, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* if didn't pass sieve and step == MAX then skip test */
+ if (y == 1 && step >= ((((mp_digit)1)<<DIGIT_BIT) - kstep)) {
+ continue;
+ }
+
+ /* is this prime? */
+ for (x = 0; x < t; x++) {
+ mp_set(&b, ltm_prime_tab[t]);
+ if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (res == MP_NO) {
+ break;
+ }
+ }
+
+ if (res == MP_YES) {
+ break;
+ }
+ }
+
+ err = MP_OKAY;
+LBL_ERR:
+ mp_clear(&b);
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_prime_next_prime.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_prime_rabin_miller_trials.c b/dep/StormLib/src/libtommath/bn_mp_prime_rabin_miller_trials.c
new file mode 100644
index 00000000000..3f7608aa7f3
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_prime_rabin_miller_trials.c
@@ -0,0 +1,52 @@
+#include "tommath.h"
+#ifdef BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+
+static const struct {
+ int k, t;
+} sizes[] = {
+{ 128, 28 },
+{ 256, 16 },
+{ 384, 10 },
+{ 512, 7 },
+{ 640, 6 },
+{ 768, 5 },
+{ 896, 4 },
+{ 1024, 4 }
+};
+
+/* returns # of RM trials required for a given bit size */
+int mp_prime_rabin_miller_trials(int size)
+{
+ int x;
+
+ for (x = 0; x < (int)(sizeof(sizes)/(sizeof(sizes[0]))); x++) {
+ if (sizes[x].k == size) {
+ return sizes[x].t;
+ } else if (sizes[x].k > size) {
+ return (x == 0) ? sizes[0].t : sizes[x - 1].t;
+ }
+ }
+ return sizes[x-1].t + 1;
+}
+
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_prime_rabin_miller_trials.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_prime_random_ex.c b/dep/StormLib/src/libtommath/bn_mp_prime_random_ex.c
new file mode 100644
index 00000000000..4eec3f69e3e
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_prime_random_ex.c
@@ -0,0 +1,125 @@
+#include "tommath.h"
+#ifdef BN_MP_PRIME_RANDOM_EX_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* makes a truly random prime of a given size (bits),
+ *
+ * Flags are as follows:
+ *
+ * LTM_PRIME_BBS - make prime congruent to 3 mod 4
+ * LTM_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies LTM_PRIME_BBS)
+ * LTM_PRIME_2MSB_OFF - make the 2nd highest bit zero
+ * LTM_PRIME_2MSB_ON - make the 2nd highest bit one
+ *
+ * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
+ * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
+ * so it can be NULL
+ *
+ */
+
+/* This is possibly the mother of all prime generation functions, muahahahahaha! */
+int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat)
+{
+ unsigned char *tmp, maskAND, maskOR_msb, maskOR_lsb;
+ int res, err, bsize, maskOR_msb_offset;
+
+ /* sanity check the input */
+ if (size <= 1 || t <= 0) {
+ return MP_VAL;
+ }
+
+ /* LTM_PRIME_SAFE implies LTM_PRIME_BBS */
+ if (flags & LTM_PRIME_SAFE) {
+ flags |= LTM_PRIME_BBS;
+ }
+
+ /* calc the byte size */
+ bsize = (size>>3) + ((size&7)?1:0);
+
+ /* we need a buffer of bsize bytes */
+ tmp = OPT_CAST(unsigned char) XMALLOC(bsize);
+ if (tmp == NULL) {
+ return MP_MEM;
+ }
+
+ /* calc the maskAND value for the MSbyte*/
+ maskAND = ((size&7) == 0) ? 0xFF : (0xFF >> (8 - (size & 7)));
+
+ /* calc the maskOR_msb */
+ maskOR_msb = 0;
+ maskOR_msb_offset = ((size & 7) == 1) ? 1 : 0;
+ if (flags & LTM_PRIME_2MSB_ON) {
+ maskOR_msb |= 0x80 >> ((9 - size) & 7);
+ }
+
+ /* get the maskOR_lsb */
+ maskOR_lsb = 1;
+ if (flags & LTM_PRIME_BBS) {
+ maskOR_lsb |= 3;
+ }
+
+ do {
+ /* read the bytes */
+ if (cb(tmp, bsize, dat) != bsize) {
+ err = MP_VAL;
+ goto error;
+ }
+
+ /* work over the MSbyte */
+ tmp[0] &= maskAND;
+ tmp[0] |= 1 << ((size - 1) & 7);
+
+ /* mix in the maskORs */
+ tmp[maskOR_msb_offset] |= maskOR_msb;
+ tmp[bsize-1] |= maskOR_lsb;
+
+ /* read it in */
+ if ((err = mp_read_unsigned_bin(a, tmp, bsize)) != MP_OKAY) { goto error; }
+
+ /* is it prime? */
+ if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { goto error; }
+ if (res == MP_NO) {
+ continue;
+ }
+
+ if (flags & LTM_PRIME_SAFE) {
+ /* see if (a-1)/2 is prime */
+ if ((err = mp_sub_d(a, 1, a)) != MP_OKAY) { goto error; }
+ if ((err = mp_div_2(a, a)) != MP_OKAY) { goto error; }
+
+ /* is it prime? */
+ if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { goto error; }
+ }
+ } while (res == MP_NO);
+
+ if (flags & LTM_PRIME_SAFE) {
+ /* restore a to the original value */
+ if ((err = mp_mul_2(a, a)) != MP_OKAY) { goto error; }
+ if ((err = mp_add_d(a, 1, a)) != MP_OKAY) { goto error; }
+ }
+
+ err = MP_OKAY;
+error:
+ XFREE(tmp);
+ return err;
+}
+
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_prime_random_ex.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_radix_size.c b/dep/StormLib/src/libtommath/bn_mp_radix_size.c
new file mode 100644
index 00000000000..2378f1fc1ac
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_radix_size.c
@@ -0,0 +1,78 @@
+#include "tommath.h"
+#ifdef BN_MP_RADIX_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* returns size of ASCII reprensentation */
+int mp_radix_size (mp_int * a, int radix, int *size)
+{
+ int res, digs;
+ mp_int t;
+ mp_digit d;
+
+ *size = 0;
+
+ /* special case for binary */
+ if (radix == 2) {
+ *size = mp_count_bits (a) + (a->sign == MP_NEG ? 1 : 0) + 1;
+ return MP_OKAY;
+ }
+
+ /* make sure the radix is in range */
+ if (radix < 2 || radix > 64) {
+ return MP_VAL;
+ }
+
+ if (mp_iszero(a) == MP_YES) {
+ *size = 2;
+ return MP_OKAY;
+ }
+
+ /* digs is the digit count */
+ digs = 0;
+
+ /* if it's negative add one for the sign */
+ if (a->sign == MP_NEG) {
+ ++digs;
+ }
+
+ /* init a copy of the input */
+ if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
+ return res;
+ }
+
+ /* force temp to positive */
+ t.sign = MP_ZPOS;
+
+ /* fetch out all of the digits */
+ while (mp_iszero (&t) == MP_NO) {
+ if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ ++digs;
+ }
+ mp_clear (&t);
+
+ /* return digs + 1, the 1 is for the NULL byte that would be required. */
+ *size = digs + 1;
+ return MP_OKAY;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_radix_size.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_radix_smap.c b/dep/StormLib/src/libtommath/bn_mp_radix_smap.c
new file mode 100644
index 00000000000..5cbe9520b5b
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_radix_smap.c
@@ -0,0 +1,24 @@
+#include "tommath.h"
+#ifdef BN_MP_RADIX_SMAP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* chars used in radix conversions */
+const char *mp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_radix_smap.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_rand.c b/dep/StormLib/src/libtommath/bn_mp_rand.c
new file mode 100644
index 00000000000..e1241785e88
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_rand.c
@@ -0,0 +1,55 @@
+#include "tommath.h"
+#ifdef BN_MP_RAND_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* makes a pseudo-random int of a given size */
+int
+mp_rand (mp_int * a, int digits)
+{
+ int res;
+ mp_digit d;
+
+ mp_zero (a);
+ if (digits <= 0) {
+ return MP_OKAY;
+ }
+
+ /* first place a random non-zero digit */
+ do {
+ d = ((mp_digit) abs (rand ())) & MP_MASK;
+ } while (d == 0);
+
+ if ((res = mp_add_d (a, d, a)) != MP_OKAY) {
+ return res;
+ }
+
+ while (--digits > 0) {
+ if ((res = mp_lshd (a, 1)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_add_d (a, ((mp_digit) abs (rand ())), a)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_rand.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_read_radix.c b/dep/StormLib/src/libtommath/bn_mp_read_radix.c
new file mode 100644
index 00000000000..6869668fb88
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_read_radix.c
@@ -0,0 +1,85 @@
+#include "tommath.h"
+#ifdef BN_MP_READ_RADIX_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* read a string [ASCII] in a given radix */
+int mp_read_radix (mp_int * a, const char *str, int radix)
+{
+ int y, res, neg;
+ char ch;
+
+ /* zero the digit bignum */
+ mp_zero(a);
+
+ /* make sure the radix is ok */
+ if (radix < 2 || radix > 64) {
+ return MP_VAL;
+ }
+
+ /* if the leading digit is a
+ * minus set the sign to negative.
+ */
+ if (*str == '-') {
+ ++str;
+ neg = MP_NEG;
+ } else {
+ neg = MP_ZPOS;
+ }
+
+ /* set the integer to the default of zero */
+ mp_zero (a);
+
+ /* process each digit of the string */
+ while (*str) {
+ /* if the radix < 36 the conversion is case insensitive
+ * this allows numbers like 1AB and 1ab to represent the same value
+ * [e.g. in hex]
+ */
+ ch = (char) ((radix < 36) ? toupper (*str) : *str);
+ for (y = 0; y < 64; y++) {
+ if (ch == mp_s_rmap[y]) {
+ break;
+ }
+ }
+
+ /* if the char was found in the map
+ * and is less than the given radix add it
+ * to the number, otherwise exit the loop.
+ */
+ if (y < radix) {
+ if ((res = mp_mul_d (a, (mp_digit) radix, a)) != MP_OKAY) {
+ return res;
+ }
+ if ((res = mp_add_d (a, (mp_digit) y, a)) != MP_OKAY) {
+ return res;
+ }
+ } else {
+ break;
+ }
+ ++str;
+ }
+
+ /* set the sign only if a != 0 */
+ if (mp_iszero(a) != 1) {
+ a->sign = neg;
+ }
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_read_radix.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_read_signed_bin.c b/dep/StormLib/src/libtommath/bn_mp_read_signed_bin.c
new file mode 100644
index 00000000000..e9a780c28aa
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_read_signed_bin.c
@@ -0,0 +1,41 @@
+#include "tommath.h"
+#ifdef BN_MP_READ_SIGNED_BIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* read signed bin, big endian, first byte is 0==positive or 1==negative */
+int mp_read_signed_bin (mp_int * a, const unsigned char *b, int c)
+{
+ int res;
+
+ /* read magnitude */
+ if ((res = mp_read_unsigned_bin (a, b + 1, c - 1)) != MP_OKAY) {
+ return res;
+ }
+
+ /* first byte is 0 for positive, non-zero for negative */
+ if (b[0] == 0) {
+ a->sign = MP_ZPOS;
+ } else {
+ a->sign = MP_NEG;
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_read_signed_bin.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_read_unsigned_bin.c b/dep/StormLib/src/libtommath/bn_mp_read_unsigned_bin.c
new file mode 100644
index 00000000000..7d35370418c
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_read_unsigned_bin.c
@@ -0,0 +1,55 @@
+#include "tommath.h"
+#ifdef BN_MP_READ_UNSIGNED_BIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* reads a unsigned char array, assumes the msb is stored first [big endian] */
+int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
+{
+ int res;
+
+ /* make sure there are at least two digits */
+ if (a->alloc < 2) {
+ if ((res = mp_grow(a, 2)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* zero the int */
+ mp_zero (a);
+
+ /* read the bytes in */
+ while (c-- > 0) {
+ if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
+ return res;
+ }
+
+#ifndef MP_8BIT
+ a->dp[0] |= *b++;
+ a->used += 1;
+#else
+ a->dp[0] = (*b & MP_MASK);
+ a->dp[1] |= ((*b++ >> 7U) & 1);
+ a->used += 2;
+#endif
+ }
+ mp_clamp (a);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_read_unsigned_bin.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_reduce.c b/dep/StormLib/src/libtommath/bn_mp_reduce.c
new file mode 100644
index 00000000000..3a6bb5aca90
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_reduce.c
@@ -0,0 +1,100 @@
+#include "tommath.h"
+#ifdef BN_MP_REDUCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* reduces x mod m, assumes 0 < x < m**2, mu is
+ * precomputed via mp_reduce_setup.
+ * From HAC pp.604 Algorithm 14.42
+ */
+int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
+{
+ mp_int q;
+ int res, um = m->used;
+
+ /* q = x */
+ if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
+ return res;
+ }
+
+ /* q1 = x / b**(k-1) */
+ mp_rshd (&q, um - 1);
+
+ /* according to HAC this optimization is ok */
+ if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
+ if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+ } else {
+#ifdef BN_S_MP_MUL_HIGH_DIGS_C
+ if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
+ if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+#else
+ {
+ res = MP_VAL;
+ goto CLEANUP;
+ }
+#endif
+ }
+
+ /* q3 = q2 / b**(k+1) */
+ mp_rshd (&q, um + 1);
+
+ /* x = x mod b**(k+1), quick (no division) */
+ if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+
+ /* q = q * m mod b**(k+1), quick (no division) */
+ if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+
+ /* x = x - q */
+ if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+
+ /* If x < 0, add b**(k+1) to it */
+ if (mp_cmp_d (x, 0) == MP_LT) {
+ mp_set (&q, 1);
+ if ((res = mp_lshd (&q, um + 1)) != MP_OKAY)
+ goto CLEANUP;
+ if ((res = mp_add (x, &q, x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ /* Back off if it's too big */
+ while (mp_cmp (x, m) != MP_LT) {
+ if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+ }
+
+CLEANUP:
+ mp_clear (&q);
+
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_reduce_2k.c b/dep/StormLib/src/libtommath/bn_mp_reduce_2k.c
new file mode 100644
index 00000000000..3191d829179
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_reduce_2k.c
@@ -0,0 +1,61 @@
+#include "tommath.h"
+#ifdef BN_MP_REDUCE_2K_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* reduces a modulo n where n is of the form 2**p - d */
+int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d)
+{
+ mp_int q;
+ int p, res;
+
+ if ((res = mp_init(&q)) != MP_OKAY) {
+ return res;
+ }
+
+ p = mp_count_bits(n);
+top:
+ /* q = a/2**p, a = a mod 2**p */
+ if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if (d != 1) {
+ /* q = q * d */
+ if ((res = mp_mul_d(&q, d, &q)) != MP_OKAY) {
+ goto ERR;
+ }
+ }
+
+ /* a = a + q */
+ if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if (mp_cmp_mag(a, n) != MP_LT) {
+ s_mp_sub(a, n, a);
+ goto top;
+ }
+
+ERR:
+ mp_clear(&q);
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_reduce_2k_l.c b/dep/StormLib/src/libtommath/bn_mp_reduce_2k_l.c
new file mode 100644
index 00000000000..49b7e344ed9
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_reduce_2k_l.c
@@ -0,0 +1,62 @@
+#include "tommath.h"
+#ifdef BN_MP_REDUCE_2K_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* reduces a modulo n where n is of the form 2**p - d
+ This differs from reduce_2k since "d" can be larger
+ than a single digit.
+*/
+int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
+{
+ mp_int q;
+ int p, res;
+
+ if ((res = mp_init(&q)) != MP_OKAY) {
+ return res;
+ }
+
+ p = mp_count_bits(n);
+top:
+ /* q = a/2**p, a = a mod 2**p */
+ if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* q = q * d */
+ if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* a = a + q */
+ if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if (mp_cmp_mag(a, n) != MP_LT) {
+ s_mp_sub(a, n, a);
+ goto top;
+ }
+
+ERR:
+ mp_clear(&q);
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k_l.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_reduce_2k_setup.c b/dep/StormLib/src/libtommath/bn_mp_reduce_2k_setup.c
new file mode 100644
index 00000000000..aa3b3bad8db
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_reduce_2k_setup.c
@@ -0,0 +1,47 @@
+#include "tommath.h"
+#ifdef BN_MP_REDUCE_2K_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* determines the setup value */
+int mp_reduce_2k_setup(mp_int *a, mp_digit *d)
+{
+ int res, p;
+ mp_int tmp;
+
+ if ((res = mp_init(&tmp)) != MP_OKAY) {
+ return res;
+ }
+
+ p = mp_count_bits(a);
+ if ((res = mp_2expt(&tmp, p)) != MP_OKAY) {
+ mp_clear(&tmp);
+ return res;
+ }
+
+ if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) {
+ mp_clear(&tmp);
+ return res;
+ }
+
+ *d = tmp.dp[0];
+ mp_clear(&tmp);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k_setup.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_reduce_2k_setup_l.c b/dep/StormLib/src/libtommath/bn_mp_reduce_2k_setup_l.c
new file mode 100644
index 00000000000..4eca87040bc
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_reduce_2k_setup_l.c
@@ -0,0 +1,44 @@
+#include "tommath.h"
+#ifdef BN_MP_REDUCE_2K_SETUP_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* determines the setup value */
+int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
+{
+ int res;
+ mp_int tmp;
+
+ if ((res = mp_init(&tmp)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ERR:
+ mp_clear(&tmp);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k_setup_l.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_reduce_is_2k.c b/dep/StormLib/src/libtommath/bn_mp_reduce_is_2k.c
new file mode 100644
index 00000000000..b9ede978964
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_reduce_is_2k.c
@@ -0,0 +1,52 @@
+#include "tommath.h"
+#ifdef BN_MP_REDUCE_IS_2K_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* determines if mp_reduce_2k can be used */
+int mp_reduce_is_2k(mp_int *a)
+{
+ int ix, iy, iw;
+ mp_digit iz;
+
+ if (a->used == 0) {
+ return MP_NO;
+ } else if (a->used == 1) {
+ return MP_YES;
+ } else if (a->used > 1) {
+ iy = mp_count_bits(a);
+ iz = 1;
+ iw = 1;
+
+ /* Test every bit from the second digit up, must be 1 */
+ for (ix = DIGIT_BIT; ix < iy; ix++) {
+ if ((a->dp[iw] & iz) == 0) {
+ return MP_NO;
+ }
+ iz <<= 1;
+ if (iz > (mp_digit)MP_MASK) {
+ ++iw;
+ iz = 1;
+ }
+ }
+ }
+ return MP_YES;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_is_2k.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_reduce_is_2k_l.c b/dep/StormLib/src/libtommath/bn_mp_reduce_is_2k_l.c
new file mode 100644
index 00000000000..787875f8bbb
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_reduce_is_2k_l.c
@@ -0,0 +1,44 @@
+#include "tommath.h"
+#ifdef BN_MP_REDUCE_IS_2K_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* determines if reduce_2k_l can be used */
+int mp_reduce_is_2k_l(mp_int *a)
+{
+ int ix, iy;
+
+ if (a->used == 0) {
+ return MP_NO;
+ } else if (a->used == 1) {
+ return MP_YES;
+ } else if (a->used > 1) {
+ /* if more than half of the digits are -1 we're sold */
+ for (iy = ix = 0; ix < a->used; ix++) {
+ if (a->dp[ix] == MP_MASK) {
+ ++iy;
+ }
+ }
+ return (iy >= (a->used/2)) ? MP_YES : MP_NO;
+
+ }
+ return MP_NO;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_is_2k_l.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_reduce_setup.c b/dep/StormLib/src/libtommath/bn_mp_reduce_setup.c
new file mode 100644
index 00000000000..00e0a62b9bd
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_reduce_setup.c
@@ -0,0 +1,34 @@
+#include "tommath.h"
+#ifdef BN_MP_REDUCE_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* pre-calculate the value required for Barrett reduction
+ * For a given modulus "b" it calulates the value required in "a"
+ */
+int mp_reduce_setup (mp_int * a, mp_int * b)
+{
+ int res;
+
+ if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
+ return res;
+ }
+ return mp_div (a, b, a, NULL);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_setup.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_rshd.c b/dep/StormLib/src/libtommath/bn_mp_rshd.c
new file mode 100644
index 00000000000..eac6721baf0
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_rshd.c
@@ -0,0 +1,72 @@
+#include "tommath.h"
+#ifdef BN_MP_RSHD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* shift right a certain amount of digits */
+void mp_rshd (mp_int * a, int b)
+{
+ int x;
+
+ /* if b <= 0 then ignore it */
+ if (b <= 0) {
+ return;
+ }
+
+ /* if b > used then simply zero it and return */
+ if (a->used <= b) {
+ mp_zero (a);
+ return;
+ }
+
+ {
+ register mp_digit *bottom, *top;
+
+ /* shift the digits down */
+
+ /* bottom */
+ bottom = a->dp;
+
+ /* top [offset into digits] */
+ top = a->dp + b;
+
+ /* this is implemented as a sliding window where
+ * the window is b-digits long and digits from
+ * the top of the window are copied to the bottom
+ *
+ * e.g.
+
+ b-2 | b-1 | b0 | b1 | b2 | ... | bb | ---->
+ /\ | ---->
+ \-------------------/ ---->
+ */
+ for (x = 0; x < (a->used - b); x++) {
+ *bottom++ = *top++;
+ }
+
+ /* zero the top digits */
+ for (; x < a->used; x++) {
+ *bottom++ = 0;
+ }
+ }
+
+ /* remove excess digits */
+ a->used -= b;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_rshd.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_set.c b/dep/StormLib/src/libtommath/bn_mp_set.c
new file mode 100644
index 00000000000..d76d5bbd324
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_set.c
@@ -0,0 +1,29 @@
+#include "tommath.h"
+#ifdef BN_MP_SET_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* set to a digit */
+void mp_set (mp_int * a, mp_digit b)
+{
+ mp_zero (a);
+ a->dp[0] = b & MP_MASK;
+ a->used = (a->dp[0] != 0) ? 1 : 0;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_set.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_set_int.c b/dep/StormLib/src/libtommath/bn_mp_set_int.c
new file mode 100644
index 00000000000..68cf0e32b27
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_set_int.c
@@ -0,0 +1,48 @@
+#include "tommath.h"
+#ifdef BN_MP_SET_INT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* set a 32-bit const */
+int mp_set_int (mp_int * a, unsigned long b)
+{
+ int x, res;
+
+ mp_zero (a);
+
+ /* set four bits at a time */
+ for (x = 0; x < 8; x++) {
+ /* shift the number up four bits */
+ if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) {
+ return res;
+ }
+
+ /* OR in the top four bits of the source */
+ a->dp[0] |= (b >> 28) & 15;
+
+ /* shift the source up to the next four bits */
+ b <<= 4;
+
+ /* ensure that digits are not clamped off */
+ a->used += 1;
+ }
+ mp_clamp (a);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_set_int.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_shrink.c b/dep/StormLib/src/libtommath/bn_mp_shrink.c
new file mode 100644
index 00000000000..54920d1400a
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_shrink.c
@@ -0,0 +1,35 @@
+#include "tommath.h"
+#ifdef BN_MP_SHRINK_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* shrink a bignum */
+int mp_shrink (mp_int * a)
+{
+ mp_digit *tmp;
+ if (a->alloc != a->used && a->used > 0) {
+ if ((tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * a->used)) == NULL) {
+ return MP_MEM;
+ }
+ a->dp = tmp;
+ a->alloc = a->used;
+ }
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_shrink.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_signed_bin_size.c b/dep/StormLib/src/libtommath/bn_mp_signed_bin_size.c
new file mode 100644
index 00000000000..b9492a5e5ed
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_signed_bin_size.c
@@ -0,0 +1,27 @@
+#include "tommath.h"
+#ifdef BN_MP_SIGNED_BIN_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* get the size for an signed equivalent */
+int mp_signed_bin_size (mp_int * a)
+{
+ return 1 + mp_unsigned_bin_size (a);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_signed_bin_size.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_sqr.c b/dep/StormLib/src/libtommath/bn_mp_sqr.c
new file mode 100644
index 00000000000..c10fa6f3b6e
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_sqr.c
@@ -0,0 +1,58 @@
+#include "tommath.h"
+#ifdef BN_MP_SQR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes b = a*a */
+int
+mp_sqr (mp_int * a, mp_int * b)
+{
+ int res;
+
+#ifdef BN_MP_TOOM_SQR_C
+ /* use Toom-Cook? */
+ if (a->used >= TOOM_SQR_CUTOFF) {
+ res = mp_toom_sqr(a, b);
+ /* Karatsuba? */
+ } else
+#endif
+#ifdef BN_MP_KARATSUBA_SQR_C
+if (a->used >= KARATSUBA_SQR_CUTOFF) {
+ res = mp_karatsuba_sqr (a, b);
+ } else
+#endif
+ {
+#ifdef BN_FAST_S_MP_SQR_C
+ /* can we use the fast comba multiplier? */
+ if ((a->used * 2 + 1) < MP_WARRAY &&
+ a->used <
+ (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
+ res = fast_s_mp_sqr (a, b);
+ } else
+#endif
+#ifdef BN_S_MP_SQR_C
+ res = s_mp_sqr (a, b);
+#else
+ res = MP_VAL;
+#endif
+ }
+ b->sign = MP_ZPOS;
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_sqr.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_sqrmod.c b/dep/StormLib/src/libtommath/bn_mp_sqrmod.c
new file mode 100644
index 00000000000..5f4b2f3d663
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_sqrmod.c
@@ -0,0 +1,41 @@
+#include "tommath.h"
+#ifdef BN_MP_SQRMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* c = a * a (mod b) */
+int
+mp_sqrmod (mp_int * a, mp_int * b, mp_int * c)
+{
+ int res;
+ mp_int t;
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_sqr (a, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ res = mp_mod (&t, b, c);
+ mp_clear (&t);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_sqrmod.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_sqrt.c b/dep/StormLib/src/libtommath/bn_mp_sqrt.c
new file mode 100644
index 00000000000..e15ba98ca88
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_sqrt.c
@@ -0,0 +1,81 @@
+#include "tommath.h"
+#ifdef BN_MP_SQRT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* this function is less generic than mp_n_root, simpler and faster */
+int mp_sqrt(mp_int *arg, mp_int *ret)
+{
+ int res;
+ mp_int t1,t2;
+
+ /* must be positive */
+ if (arg->sign == MP_NEG) {
+ return MP_VAL;
+ }
+
+ /* easy out */
+ if (mp_iszero(arg) == MP_YES) {
+ mp_zero(ret);
+ return MP_OKAY;
+ }
+
+ if ((res = mp_init_copy(&t1, arg)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_init(&t2)) != MP_OKAY) {
+ goto E2;
+ }
+
+ /* First approx. (not very bad for large arg) */
+ mp_rshd (&t1,t1.used/2);
+
+ /* t1 > 0 */
+ if ((res = mp_div(arg,&t1,&t2,NULL)) != MP_OKAY) {
+ goto E1;
+ }
+ if ((res = mp_add(&t1,&t2,&t1)) != MP_OKAY) {
+ goto E1;
+ }
+ if ((res = mp_div_2(&t1,&t1)) != MP_OKAY) {
+ goto E1;
+ }
+ /* And now t1 > sqrt(arg) */
+ do {
+ if ((res = mp_div(arg,&t1,&t2,NULL)) != MP_OKAY) {
+ goto E1;
+ }
+ if ((res = mp_add(&t1,&t2,&t1)) != MP_OKAY) {
+ goto E1;
+ }
+ if ((res = mp_div_2(&t1,&t1)) != MP_OKAY) {
+ goto E1;
+ }
+ /* t1 >= sqrt(arg) >= t2 at this point */
+ } while (mp_cmp_mag(&t1,&t2) == MP_GT);
+
+ mp_exch(&t1,ret);
+
+E1: mp_clear(&t2);
+E2: mp_clear(&t1);
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_sqrt.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_sub.c b/dep/StormLib/src/libtommath/bn_mp_sub.c
new file mode 100644
index 00000000000..6e72138610f
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_sub.c
@@ -0,0 +1,59 @@
+#include "tommath.h"
+#ifdef BN_MP_SUB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* high level subtraction (handles signs) */
+int
+mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+ int sa, sb, res;
+
+ sa = a->sign;
+ sb = b->sign;
+
+ if (sa != sb) {
+ /* subtract a negative from a positive, OR */
+ /* subtract a positive from a negative. */
+ /* In either case, ADD their magnitudes, */
+ /* and use the sign of the first number. */
+ c->sign = sa;
+ res = s_mp_add (a, b, c);
+ } else {
+ /* subtract a positive from a positive, OR */
+ /* subtract a negative from a negative. */
+ /* First, take the difference between their */
+ /* magnitudes, then... */
+ if (mp_cmp_mag (a, b) != MP_LT) {
+ /* Copy the sign from the first */
+ c->sign = sa;
+ /* The first has a larger or equal magnitude */
+ res = s_mp_sub (a, b, c);
+ } else {
+ /* The result has the *opposite* sign from */
+ /* the first number. */
+ c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
+ /* The second has a larger magnitude */
+ res = s_mp_sub (b, a, c);
+ }
+ }
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_sub.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_sub_d.c b/dep/StormLib/src/libtommath/bn_mp_sub_d.c
new file mode 100644
index 00000000000..aa08e31b30b
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_sub_d.c
@@ -0,0 +1,93 @@
+#include "tommath.h"
+#ifdef BN_MP_SUB_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* single digit subtraction */
+int
+mp_sub_d (mp_int * a, mp_digit b, mp_int * c)
+{
+ mp_digit *tmpa, *tmpc, mu;
+ int res, ix, oldused;
+
+ /* grow c as required */
+ if (c->alloc < a->used + 1) {
+ if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* if a is negative just do an unsigned
+ * addition [with fudged signs]
+ */
+ if (a->sign == MP_NEG) {
+ a->sign = MP_ZPOS;
+ res = mp_add_d(a, b, c);
+ a->sign = c->sign = MP_NEG;
+
+ /* clamp */
+ mp_clamp(c);
+
+ return res;
+ }
+
+ /* setup regs */
+ oldused = c->used;
+ tmpa = a->dp;
+ tmpc = c->dp;
+
+ /* if a <= b simply fix the single digit */
+ if ((a->used == 1 && a->dp[0] <= b) || a->used == 0) {
+ if (a->used == 1) {
+ *tmpc++ = b - *tmpa;
+ } else {
+ *tmpc++ = b;
+ }
+ ix = 1;
+
+ /* negative/1digit */
+ c->sign = MP_NEG;
+ c->used = 1;
+ } else {
+ /* positive/size */
+ c->sign = MP_ZPOS;
+ c->used = a->used;
+
+ /* subtract first digit */
+ *tmpc = *tmpa++ - b;
+ mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1);
+ *tmpc++ &= MP_MASK;
+
+ /* handle rest of the digits */
+ for (ix = 1; ix < a->used; ix++) {
+ *tmpc = *tmpa++ - mu;
+ mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1);
+ *tmpc++ &= MP_MASK;
+ }
+ }
+
+ /* zero excess digits */
+ while (ix++ < oldused) {
+ *tmpc++ = 0;
+ }
+ mp_clamp(c);
+ return MP_OKAY;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_sub_d.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_submod.c b/dep/StormLib/src/libtommath/bn_mp_submod.c
new file mode 100644
index 00000000000..6617ff42ceb
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_submod.c
@@ -0,0 +1,42 @@
+#include "tommath.h"
+#ifdef BN_MP_SUBMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* d = a - b (mod c) */
+int
+mp_submod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ int res;
+ mp_int t;
+
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_sub (a, b, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ res = mp_mod (&t, c, d);
+ mp_clear (&t);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_submod.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_to_signed_bin.c b/dep/StormLib/src/libtommath/bn_mp_to_signed_bin.c
new file mode 100644
index 00000000000..154f64b5667
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_to_signed_bin.c
@@ -0,0 +1,33 @@
+#include "tommath.h"
+#ifdef BN_MP_TO_SIGNED_BIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* store in signed [big endian] format */
+int mp_to_signed_bin (mp_int * a, unsigned char *b)
+{
+ int res;
+
+ if ((res = mp_to_unsigned_bin (a, b + 1)) != MP_OKAY) {
+ return res;
+ }
+ b[0] = (unsigned char) ((a->sign == MP_ZPOS) ? 0 : 1);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_to_signed_bin.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_to_signed_bin_n.c b/dep/StormLib/src/libtommath/bn_mp_to_signed_bin_n.c
new file mode 100644
index 00000000000..e119c380a91
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_to_signed_bin_n.c
@@ -0,0 +1,31 @@
+#include "tommath.h"
+#ifdef BN_MP_TO_SIGNED_BIN_N_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* store in signed [big endian] format */
+int mp_to_signed_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen)
+{
+ if (*outlen < (unsigned long)mp_signed_bin_size(a)) {
+ return MP_VAL;
+ }
+ *outlen = mp_signed_bin_size(a);
+ return mp_to_signed_bin(a, b);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_to_signed_bin_n.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_to_unsigned_bin.c b/dep/StormLib/src/libtommath/bn_mp_to_unsigned_bin.c
new file mode 100644
index 00000000000..ce69e5bf364
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_to_unsigned_bin.c
@@ -0,0 +1,48 @@
+#include "tommath.h"
+#ifdef BN_MP_TO_UNSIGNED_BIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* store in unsigned [big endian] format */
+int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
+{
+ int x, res;
+ mp_int t;
+
+ if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
+ return res;
+ }
+
+ x = 0;
+ while (mp_iszero (&t) == 0) {
+#ifndef MP_8BIT
+ b[x++] = (unsigned char) (t.dp[0] & 255);
+#else
+ b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
+#endif
+ if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ }
+ bn_reverse (b, x);
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_to_unsigned_bin.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_to_unsigned_bin_n.c b/dep/StormLib/src/libtommath/bn_mp_to_unsigned_bin_n.c
new file mode 100644
index 00000000000..dfa27c41bab
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_to_unsigned_bin_n.c
@@ -0,0 +1,31 @@
+#include "tommath.h"
+#ifdef BN_MP_TO_UNSIGNED_BIN_N_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* store in unsigned [big endian] format */
+int mp_to_unsigned_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen)
+{
+ if (*outlen < (unsigned long)mp_unsigned_bin_size(a)) {
+ return MP_VAL;
+ }
+ *outlen = mp_unsigned_bin_size(a);
+ return mp_to_unsigned_bin(a, b);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_to_unsigned_bin_n.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_toom_mul.c b/dep/StormLib/src/libtommath/bn_mp_toom_mul.c
new file mode 100644
index 00000000000..e48c6b355c0
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_toom_mul.c
@@ -0,0 +1,284 @@
+#include "tommath.h"
+#ifdef BN_MP_TOOM_MUL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* multiplication using the Toom-Cook 3-way algorithm
+ *
+ * Much more complicated than Karatsuba but has a lower
+ * asymptotic running time of O(N**1.464). This algorithm is
+ * only particularly useful on VERY large inputs
+ * (we're talking 1000s of digits here...).
+*/
+int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c)
+{
+ mp_int w0, w1, w2, w3, w4, tmp1, tmp2, a0, a1, a2, b0, b1, b2;
+ int res, B;
+
+ /* init temps */
+ if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4,
+ &a0, &a1, &a2, &b0, &b1,
+ &b2, &tmp1, &tmp2, NULL)) != MP_OKAY) {
+ return res;
+ }
+
+ /* B */
+ B = MIN(a->used, b->used) / 3;
+
+ /* a = a2 * B**2 + a1 * B + a0 */
+ if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_copy(a, &a1)) != MP_OKAY) {
+ goto ERR;
+ }
+ mp_rshd(&a1, B);
+ mp_mod_2d(&a1, DIGIT_BIT * B, &a1);
+
+ if ((res = mp_copy(a, &a2)) != MP_OKAY) {
+ goto ERR;
+ }
+ mp_rshd(&a2, B*2);
+
+ /* b = b2 * B**2 + b1 * B + b0 */
+ if ((res = mp_mod_2d(b, DIGIT_BIT * B, &b0)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_copy(b, &b1)) != MP_OKAY) {
+ goto ERR;
+ }
+ mp_rshd(&b1, B);
+ mp_mod_2d(&b1, DIGIT_BIT * B, &b1);
+
+ if ((res = mp_copy(b, &b2)) != MP_OKAY) {
+ goto ERR;
+ }
+ mp_rshd(&b2, B*2);
+
+ /* w0 = a0*b0 */
+ if ((res = mp_mul(&a0, &b0, &w0)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* w4 = a2 * b2 */
+ if ((res = mp_mul(&a2, &b2, &w4)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* w1 = (a2 + 2(a1 + 2a0))(b2 + 2(b1 + 2b0)) */
+ if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_mul_2(&b0, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp2, &b2, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_mul(&tmp1, &tmp2, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* w3 = (a0 + 2(a1 + 2a2))(b0 + 2(b1 + 2b2)) */
+ if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_mul_2(&b2, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_mul(&tmp1, &tmp2, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+
+
+ /* w2 = (a2 + a1 + a0)(b2 + b1 + b0) */
+ if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&b2, &b1, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_mul(&tmp1, &tmp2, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* now solve the matrix
+
+ 0 0 0 0 1
+ 1 2 4 8 16
+ 1 1 1 1 1
+ 16 8 4 2 1
+ 1 0 0 0 0
+
+ using 12 subtractions, 4 shifts,
+ 2 small divisions and 1 small multiplication
+ */
+
+ /* r1 - r4 */
+ if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - r0 */
+ if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1/2 */
+ if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3/2 */
+ if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r2 - r0 - r4 */
+ if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1 - r2 */
+ if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - r2 */
+ if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1 - 8r0 */
+ if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - 8r4 */
+ if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* 3r2 - r1 - r3 */
+ if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1 - r2 */
+ if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - r2 */
+ if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1/3 */
+ if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3/3 */
+ if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* at this point shift W[n] by B*n */
+ if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_add(&w0, &w1, c)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, c, c)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ERR:
+ mp_clear_multi(&w0, &w1, &w2, &w3, &w4,
+ &a0, &a1, &a2, &b0, &b1,
+ &b2, &tmp1, &tmp2, NULL);
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_toom_mul.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_toom_sqr.c b/dep/StormLib/src/libtommath/bn_mp_toom_sqr.c
new file mode 100644
index 00000000000..fd8bc672a1a
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_toom_sqr.c
@@ -0,0 +1,226 @@
+#include "tommath.h"
+#ifdef BN_MP_TOOM_SQR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* squaring using Toom-Cook 3-way algorithm */
+int
+mp_toom_sqr(mp_int *a, mp_int *b)
+{
+ mp_int w0, w1, w2, w3, w4, tmp1, a0, a1, a2;
+ int res, B;
+
+ /* init temps */
+ if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL)) != MP_OKAY) {
+ return res;
+ }
+
+ /* B */
+ B = a->used / 3;
+
+ /* a = a2 * B**2 + a1 * B + a0 */
+ if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_copy(a, &a1)) != MP_OKAY) {
+ goto ERR;
+ }
+ mp_rshd(&a1, B);
+ mp_mod_2d(&a1, DIGIT_BIT * B, &a1);
+
+ if ((res = mp_copy(a, &a2)) != MP_OKAY) {
+ goto ERR;
+ }
+ mp_rshd(&a2, B*2);
+
+ /* w0 = a0*a0 */
+ if ((res = mp_sqr(&a0, &w0)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* w4 = a2 * a2 */
+ if ((res = mp_sqr(&a2, &w4)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* w1 = (a2 + 2(a1 + 2a0))**2 */
+ if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_sqr(&tmp1, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* w3 = (a0 + 2(a1 + 2a2))**2 */
+ if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_sqr(&tmp1, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+
+
+ /* w2 = (a2 + a1 + a0)**2 */
+ if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sqr(&tmp1, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* now solve the matrix
+
+ 0 0 0 0 1
+ 1 2 4 8 16
+ 1 1 1 1 1
+ 16 8 4 2 1
+ 1 0 0 0 0
+
+ using 12 subtractions, 4 shifts, 2 small divisions and 1 small multiplication.
+ */
+
+ /* r1 - r4 */
+ if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - r0 */
+ if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1/2 */
+ if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3/2 */
+ if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r2 - r0 - r4 */
+ if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1 - r2 */
+ if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - r2 */
+ if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1 - 8r0 */
+ if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - 8r4 */
+ if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* 3r2 - r1 - r3 */
+ if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1 - r2 */
+ if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - r2 */
+ if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1/3 */
+ if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3/3 */
+ if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* at this point shift W[n] by B*n */
+ if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_add(&w0, &w1, b)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, b, b)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ERR:
+ mp_clear_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL);
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_toom_sqr.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_toradix.c b/dep/StormLib/src/libtommath/bn_mp_toradix.c
new file mode 100644
index 00000000000..539abe9ba6d
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_toradix.c
@@ -0,0 +1,75 @@
+#include "tommath.h"
+#ifdef BN_MP_TORADIX_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* stores a bignum as a ASCII string in a given radix (2..64) */
+int mp_toradix (mp_int * a, char *str, int radix)
+{
+ int res, digs;
+ mp_int t;
+ mp_digit d;
+ char *_s = str;
+
+ /* check range of the radix */
+ if (radix < 2 || radix > 64) {
+ return MP_VAL;
+ }
+
+ /* quick out if its zero */
+ if (mp_iszero(a) == 1) {
+ *str++ = '0';
+ *str = '\0';
+ return MP_OKAY;
+ }
+
+ if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
+ return res;
+ }
+
+ /* if it is negative output a - */
+ if (t.sign == MP_NEG) {
+ ++_s;
+ *str++ = '-';
+ t.sign = MP_ZPOS;
+ }
+
+ digs = 0;
+ while (mp_iszero (&t) == 0) {
+ if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ *str++ = mp_s_rmap[d];
+ ++digs;
+ }
+
+ /* reverse the digits of the string. In this case _s points
+ * to the first digit [exluding the sign] of the number]
+ */
+ bn_reverse ((unsigned char *)_s, digs);
+
+ /* append a NULL so the string is properly terminated */
+ *str = '\0';
+
+ mp_clear (&t);
+ return MP_OKAY;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_toradix.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_toradix_n.c b/dep/StormLib/src/libtommath/bn_mp_toradix_n.c
new file mode 100644
index 00000000000..0322f8d4b2a
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_toradix_n.c
@@ -0,0 +1,88 @@
+#include "tommath.h"
+#ifdef BN_MP_TORADIX_N_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* stores a bignum as a ASCII string in a given radix (2..64)
+ *
+ * Stores upto maxlen-1 chars and always a NULL byte
+ */
+int mp_toradix_n(mp_int * a, char *str, int radix, int maxlen)
+{
+ int res, digs;
+ mp_int t;
+ mp_digit d;
+ char *_s = str;
+
+ /* check range of the maxlen, radix */
+ if (maxlen < 2 || radix < 2 || radix > 64) {
+ return MP_VAL;
+ }
+
+ /* quick out if its zero */
+ if (mp_iszero(a) == MP_YES) {
+ *str++ = '0';
+ *str = '\0';
+ return MP_OKAY;
+ }
+
+ if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
+ return res;
+ }
+
+ /* if it is negative output a - */
+ if (t.sign == MP_NEG) {
+ /* we have to reverse our digits later... but not the - sign!! */
+ ++_s;
+
+ /* store the flag and mark the number as positive */
+ *str++ = '-';
+ t.sign = MP_ZPOS;
+
+ /* subtract a char */
+ --maxlen;
+ }
+
+ digs = 0;
+ while (mp_iszero (&t) == 0) {
+ if (--maxlen < 1) {
+ /* no more room */
+ break;
+ }
+ if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ *str++ = mp_s_rmap[d];
+ ++digs;
+ }
+
+ /* reverse the digits of the string. In this case _s points
+ * to the first digit [exluding the sign] of the number
+ */
+ bn_reverse ((unsigned char *)_s, digs);
+
+ /* append a NULL so the string is properly terminated */
+ *str = '\0';
+
+ mp_clear (&t);
+ return MP_OKAY;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_toradix_n.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_unsigned_bin_size.c b/dep/StormLib/src/libtommath/bn_mp_unsigned_bin_size.c
new file mode 100644
index 00000000000..88f3e92dde8
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_unsigned_bin_size.c
@@ -0,0 +1,28 @@
+#include "tommath.h"
+#ifdef BN_MP_UNSIGNED_BIN_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* get the size for an unsigned equivalent */
+int mp_unsigned_bin_size (mp_int * a)
+{
+ int size = mp_count_bits (a);
+ return (size / 8 + ((size & 7) != 0 ? 1 : 0));
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_unsigned_bin_size.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_xor.c b/dep/StormLib/src/libtommath/bn_mp_xor.c
new file mode 100644
index 00000000000..bf0446ecfe8
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_xor.c
@@ -0,0 +1,51 @@
+#include "tommath.h"
+#ifdef BN_MP_XOR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* XOR two ints together */
+int
+mp_xor (mp_int * a, mp_int * b, mp_int * c)
+{
+ int res, ix, px;
+ mp_int t, *x;
+
+ if (a->used > b->used) {
+ if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
+ return res;
+ }
+ px = b->used;
+ x = b;
+ } else {
+ if ((res = mp_init_copy (&t, b)) != MP_OKAY) {
+ return res;
+ }
+ px = a->used;
+ x = a;
+ }
+
+ for (ix = 0; ix < px; ix++) {
+ t.dp[ix] ^= x->dp[ix];
+ }
+ mp_clamp (&t);
+ mp_exch (c, &t);
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_xor.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_mp_zero.c b/dep/StormLib/src/libtommath/bn_mp_zero.c
new file mode 100644
index 00000000000..f21db5ed589
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_mp_zero.c
@@ -0,0 +1,36 @@
+#include "tommath.h"
+#ifdef BN_MP_ZERO_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* set to zero */
+void mp_zero (mp_int * a)
+{
+ int n;
+ mp_digit *tmp;
+
+ a->sign = MP_ZPOS;
+ a->used = 0;
+
+ tmp = a->dp;
+ for (n = 0; n < a->alloc; n++) {
+ *tmp++ = 0;
+ }
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_zero.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_prime_tab.c b/dep/StormLib/src/libtommath/bn_prime_tab.c
new file mode 100644
index 00000000000..7d306dd56a6
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_prime_tab.c
@@ -0,0 +1,61 @@
+#include "tommath.h"
+#ifdef BN_PRIME_TAB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+const mp_digit ltm_prime_tab[] = {
+ 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
+ 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
+ 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
+ 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F,
+#ifndef MP_8BIT
+ 0x0083,
+ 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD,
+ 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF,
+ 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107,
+ 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137,
+
+ 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167,
+ 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199,
+ 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9,
+ 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7,
+ 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239,
+ 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265,
+ 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293,
+ 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF,
+
+ 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301,
+ 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B,
+ 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371,
+ 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD,
+ 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5,
+ 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419,
+ 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449,
+ 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B,
+
+ 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7,
+ 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503,
+ 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529,
+ 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F,
+ 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3,
+ 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7,
+ 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
+ 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653
+#endif
+};
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_prime_tab.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_reverse.c b/dep/StormLib/src/libtommath/bn_reverse.c
new file mode 100644
index 00000000000..d4a919af486
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_reverse.c
@@ -0,0 +1,39 @@
+#include "tommath.h"
+#ifdef BN_REVERSE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* reverse an array, used for radix code */
+void
+bn_reverse (unsigned char *s, int len)
+{
+ int ix, iy;
+ unsigned char t;
+
+ ix = 0;
+ iy = len - 1;
+ while (ix < iy) {
+ t = s[ix];
+ s[ix] = s[iy];
+ s[iy] = t;
+ ++ix;
+ --iy;
+ }
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_reverse.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_s_mp_add.c b/dep/StormLib/src/libtommath/bn_s_mp_add.c
new file mode 100644
index 00000000000..5ea9c6d205c
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_s_mp_add.c
@@ -0,0 +1,109 @@
+#include "tommath.h"
+#ifdef BN_S_MP_ADD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* low level addition, based on HAC pp.594, Algorithm 14.7 */
+int
+s_mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int *x;
+ int olduse, res, min, max;
+
+ /* find sizes, we let |a| <= |b| which means we have to sort
+ * them. "x" will point to the input with the most digits
+ */
+ if (a->used > b->used) {
+ min = b->used;
+ max = a->used;
+ x = a;
+ } else {
+ min = a->used;
+ max = b->used;
+ x = b;
+ }
+
+ /* init result */
+ if (c->alloc < max + 1) {
+ if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* get old used digit count and set new one */
+ olduse = c->used;
+ c->used = max + 1;
+
+ {
+ register mp_digit u, *tmpa, *tmpb, *tmpc;
+ register int i;
+
+ /* alias for digit pointers */
+
+ /* first input */
+ tmpa = a->dp;
+
+ /* second input */
+ tmpb = b->dp;
+
+ /* destination */
+ tmpc = c->dp;
+
+ /* zero the carry */
+ u = 0;
+ for (i = 0; i < min; i++) {
+ /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
+ *tmpc = *tmpa++ + *tmpb++ + u;
+
+ /* U = carry bit of T[i] */
+ u = *tmpc >> ((mp_digit)DIGIT_BIT);
+
+ /* take away carry bit from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+
+ /* now copy higher words if any, that is in A+B
+ * if A or B has more digits add those in
+ */
+ if (min != max) {
+ for (; i < max; i++) {
+ /* T[i] = X[i] + U */
+ *tmpc = x->dp[i] + u;
+
+ /* U = carry bit of T[i] */
+ u = *tmpc >> ((mp_digit)DIGIT_BIT);
+
+ /* take away carry bit from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+ }
+
+ /* add carry */
+ *tmpc++ = u;
+
+ /* clear digits above oldused */
+ for (i = c->used; i < olduse; i++) {
+ *tmpc++ = 0;
+ }
+ }
+
+ mp_clamp (c);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_s_mp_add.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_s_mp_exptmod.c b/dep/StormLib/src/libtommath/bn_s_mp_exptmod.c
new file mode 100644
index 00000000000..9fb2da8fd21
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_s_mp_exptmod.c
@@ -0,0 +1,252 @@
+#include "tommath.h"
+#ifdef BN_S_MP_EXPTMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#ifdef MP_LOW_MEM
+ #define TAB_SIZE 32
+#else
+ #define TAB_SIZE 256
+#endif
+
+int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
+{
+ mp_int M[TAB_SIZE], res, mu;
+ mp_digit buf;
+ int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+ int (*redux)(mp_int*,mp_int*,mp_int*);
+
+ /* find window size */
+ x = mp_count_bits (X);
+ if (x <= 7) {
+ winsize = 2;
+ } else if (x <= 36) {
+ winsize = 3;
+ } else if (x <= 140) {
+ winsize = 4;
+ } else if (x <= 450) {
+ winsize = 5;
+ } else if (x <= 1303) {
+ winsize = 6;
+ } else if (x <= 3529) {
+ winsize = 7;
+ } else {
+ winsize = 8;
+ }
+
+#ifdef MP_LOW_MEM
+ if (winsize > 5) {
+ winsize = 5;
+ }
+#endif
+
+ /* init M array */
+ /* init first cell */
+ if ((err = mp_init(&M[1])) != MP_OKAY) {
+ return err;
+ }
+
+ /* now init the second half of the array */
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ if ((err = mp_init(&M[x])) != MP_OKAY) {
+ for (y = 1<<(winsize-1); y < x; y++) {
+ mp_clear (&M[y]);
+ }
+ mp_clear(&M[1]);
+ return err;
+ }
+ }
+
+ /* create mu, used for Barrett reduction */
+ if ((err = mp_init (&mu)) != MP_OKAY) {
+ goto LBL_M;
+ }
+
+ if (redmode == 0) {
+ if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ redux = mp_reduce;
+ } else {
+ if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ redux = mp_reduce_2k_l;
+ }
+
+ /* create M table
+ *
+ * The M table contains powers of the base,
+ * e.g. M[x] = G**x mod P
+ *
+ * The first half of the table is not
+ * computed though accept for M[0] and M[1]
+ */
+ if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
+ goto LBL_MU;
+ }
+
+ /* compute the value at M[1<<(winsize-1)] by squaring
+ * M[1] (winsize-1) times
+ */
+ if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
+ goto LBL_MU;
+ }
+
+ for (x = 0; x < (winsize - 1); x++) {
+ /* square it */
+ if ((err = mp_sqr (&M[1 << (winsize - 1)],
+ &M[1 << (winsize - 1)])) != MP_OKAY) {
+ goto LBL_MU;
+ }
+
+ /* reduce modulo P */
+ if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ }
+
+ /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
+ * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
+ */
+ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+ if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ }
+
+ /* setup result */
+ if ((err = mp_init (&res)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ mp_set (&res, 1);
+
+ /* set initial mode and bit cnt */
+ mode = 0;
+ bitcnt = 1;
+ buf = 0;
+ digidx = X->used - 1;
+ bitcpy = 0;
+ bitbuf = 0;
+
+ for (;;) {
+ /* grab next digit as required */
+ if (--bitcnt == 0) {
+ /* if digidx == -1 we are out of digits */
+ if (digidx == -1) {
+ break;
+ }
+ /* read next digit and reset the bitcnt */
+ buf = X->dp[digidx--];
+ bitcnt = (int) DIGIT_BIT;
+ }
+
+ /* grab the next msb from the exponent */
+ y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
+ buf <<= (mp_digit)1;
+
+ /* if the bit is zero and mode == 0 then we ignore it
+ * These represent the leading zero bits before the first 1 bit
+ * in the exponent. Technically this opt is not required but it
+ * does lower the # of trivial squaring/reductions used
+ */
+ if (mode == 0 && y == 0) {
+ continue;
+ }
+
+ /* if the bit is zero and mode == 1 then we square */
+ if (mode == 1 && y == 0) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ continue;
+ }
+
+ /* else we add it to the window */
+ bitbuf |= (y << (winsize - ++bitcpy));
+ mode = 2;
+
+ if (bitcpy == winsize) {
+ /* ok window is filled so square as required and multiply */
+ /* square first */
+ for (x = 0; x < winsize; x++) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* then multiply */
+ if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ /* empty window and reset */
+ bitcpy = 0;
+ bitbuf = 0;
+ mode = 1;
+ }
+ }
+
+ /* if bits remain then square/multiply */
+ if (mode == 2 && bitcpy > 0) {
+ /* square then multiply if the bit is set */
+ for (x = 0; x < bitcpy; x++) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ bitbuf <<= 1;
+ if ((bitbuf & (1 << winsize)) != 0) {
+ /* then multiply */
+ if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+ }
+ }
+
+ mp_exch (&res, Y);
+ err = MP_OKAY;
+LBL_RES:mp_clear (&res);
+LBL_MU:mp_clear (&mu);
+LBL_M:
+ mp_clear(&M[1]);
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ mp_clear (&M[x]);
+ }
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_s_mp_exptmod.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_s_mp_mul_digs.c b/dep/StormLib/src/libtommath/bn_s_mp_mul_digs.c
new file mode 100644
index 00000000000..f04dacfb9ea
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_s_mp_mul_digs.c
@@ -0,0 +1,90 @@
+#include "tommath.h"
+#ifdef BN_S_MP_MUL_DIGS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* multiplies |a| * |b| and only computes upto digs digits of result
+ * HAC pp. 595, Algorithm 14.12 Modified so you can control how
+ * many digits of output are created.
+ */
+int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+ mp_int t;
+ int res, pa, pb, ix, iy;
+ mp_digit u;
+ mp_word r;
+ mp_digit tmpx, *tmpt, *tmpy;
+
+ /* can we use the fast multiplier? */
+ if (((digs) < MP_WARRAY) &&
+ MIN (a->used, b->used) <
+ (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ return fast_s_mp_mul_digs (a, b, c, digs);
+ }
+
+ if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
+ return res;
+ }
+ t.used = digs;
+
+ /* compute the digits of the product directly */
+ pa = a->used;
+ for (ix = 0; ix < pa; ix++) {
+ /* set the carry to zero */
+ u = 0;
+
+ /* limit ourselves to making digs digits of output */
+ pb = MIN (b->used, digs - ix);
+
+ /* setup some aliases */
+ /* copy of the digit from a used within the nested loop */
+ tmpx = a->dp[ix];
+
+ /* an alias for the destination shifted ix places */
+ tmpt = t.dp + ix;
+
+ /* an alias for the digits of b */
+ tmpy = b->dp;
+
+ /* compute the columns of the output and propagate the carry */
+ for (iy = 0; iy < pb; iy++) {
+ /* compute the column as a mp_word */
+ r = ((mp_word)*tmpt) +
+ ((mp_word)tmpx) * ((mp_word)*tmpy++) +
+ ((mp_word) u);
+
+ /* the new column is the lower part of the result */
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* get the carry word from the result */
+ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+ }
+ /* set carry if it is placed below digs */
+ if (ix + iy < digs) {
+ *tmpt = u;
+ }
+ }
+
+ mp_clamp (&t);
+ mp_exch (&t, c);
+
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_s_mp_mul_digs.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_s_mp_mul_high_digs.c b/dep/StormLib/src/libtommath/bn_s_mp_mul_high_digs.c
new file mode 100644
index 00000000000..b1d019925a6
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_s_mp_mul_high_digs.c
@@ -0,0 +1,81 @@
+#include "tommath.h"
+#ifdef BN_S_MP_MUL_HIGH_DIGS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* multiplies |a| * |b| and does not compute the lower digs digits
+ * [meant to get the higher part of the product]
+ */
+int
+s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+ mp_int t;
+ int res, pa, pb, ix, iy;
+ mp_digit u;
+ mp_word r;
+ mp_digit tmpx, *tmpt, *tmpy;
+
+ /* can we use the fast multiplier? */
+#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
+ if (((a->used + b->used + 1) < MP_WARRAY)
+ && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ return fast_s_mp_mul_high_digs (a, b, c, digs);
+ }
+#endif
+
+ if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ t.used = a->used + b->used + 1;
+
+ pa = a->used;
+ pb = b->used;
+ for (ix = 0; ix < pa; ix++) {
+ /* clear the carry */
+ u = 0;
+
+ /* left hand side of A[ix] * B[iy] */
+ tmpx = a->dp[ix];
+
+ /* alias to the address of where the digits will be stored */
+ tmpt = &(t.dp[digs]);
+
+ /* alias for where to read the right hand side from */
+ tmpy = b->dp + (digs - ix);
+
+ for (iy = digs - ix; iy < pb; iy++) {
+ /* calculate the double precision result */
+ r = ((mp_word)*tmpt) +
+ ((mp_word)tmpx) * ((mp_word)*tmpy++) +
+ ((mp_word) u);
+
+ /* get the lower part */
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* carry the carry */
+ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+ }
+ *tmpt = u;
+ }
+ mp_clamp (&t);
+ mp_exch (&t, c);
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_s_mp_mul_high_digs.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_s_mp_sqr.c b/dep/StormLib/src/libtommath/bn_s_mp_sqr.c
new file mode 100644
index 00000000000..c1e994efddf
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_s_mp_sqr.c
@@ -0,0 +1,84 @@
+#include "tommath.h"
+#ifdef BN_S_MP_SQR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
+int s_mp_sqr (mp_int * a, mp_int * b)
+{
+ mp_int t;
+ int res, ix, iy, pa;
+ mp_word r;
+ mp_digit u, tmpx, *tmpt;
+
+ pa = a->used;
+ if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
+ return res;
+ }
+
+ /* default used is maximum possible size */
+ t.used = 2*pa + 1;
+
+ for (ix = 0; ix < pa; ix++) {
+ /* first calculate the digit at 2*ix */
+ /* calculate double precision result */
+ r = ((mp_word) t.dp[2*ix]) +
+ ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
+
+ /* store lower part in result */
+ t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* get the carry */
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+
+ /* left hand side of A[ix] * A[iy] */
+ tmpx = a->dp[ix];
+
+ /* alias for where to store the results */
+ tmpt = t.dp + (2*ix + 1);
+
+ for (iy = ix + 1; iy < pa; iy++) {
+ /* first calculate the product */
+ r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
+
+ /* now calculate the double precision result, note we use
+ * addition instead of *2 since it's easier to optimize
+ */
+ r = ((mp_word) *tmpt) + r + r + ((mp_word) u);
+
+ /* store lower part */
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* get carry */
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+ }
+ /* propagate upwards */
+ while (u != ((mp_digit) 0)) {
+ r = ((mp_word) *tmpt) + ((mp_word) u);
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+ }
+ }
+
+ mp_clamp (&t);
+ mp_exch (&t, b);
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_s_mp_sqr.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bn_s_mp_sub.c b/dep/StormLib/src/libtommath/bn_s_mp_sub.c
new file mode 100644
index 00000000000..0ae91cc4d17
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bn_s_mp_sub.c
@@ -0,0 +1,89 @@
+#include "tommath.h"
+#ifdef BN_S_MP_SUB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
+int
+s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+ int olduse, res, min, max;
+
+ /* find sizes */
+ min = b->used;
+ max = a->used;
+
+ /* init result */
+ if (c->alloc < max) {
+ if ((res = mp_grow (c, max)) != MP_OKAY) {
+ return res;
+ }
+ }
+ olduse = c->used;
+ c->used = max;
+
+ {
+ register mp_digit u, *tmpa, *tmpb, *tmpc;
+ register int i;
+
+ /* alias for digit pointers */
+ tmpa = a->dp;
+ tmpb = b->dp;
+ tmpc = c->dp;
+
+ /* set carry to zero */
+ u = 0;
+ for (i = 0; i < min; i++) {
+ /* T[i] = A[i] - B[i] - U */
+ *tmpc = *tmpa++ - *tmpb++ - u;
+
+ /* U = carry bit of T[i]
+ * Note this saves performing an AND operation since
+ * if a carry does occur it will propagate all the way to the
+ * MSB. As a result a single shift is enough to get the carry
+ */
+ u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
+
+ /* Clear carry from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+
+ /* now copy higher words if any, e.g. if A has more digits than B */
+ for (; i < max; i++) {
+ /* T[i] = A[i] - U */
+ *tmpc = *tmpa++ - u;
+
+ /* U = carry bit of T[i] */
+ u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
+
+ /* Clear carry from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+
+ /* clear digits above used (since we may not have grown result above) */
+ for (i = c->used; i < olduse; i++) {
+ *tmpc++ = 0;
+ }
+ }
+
+ mp_clamp (c);
+ return MP_OKAY;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_s_mp_sub.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/bncore.c b/dep/StormLib/src/libtommath/bncore.c
new file mode 100644
index 00000000000..ad7347f8424
--- /dev/null
+++ b/dep/StormLib/src/libtommath/bncore.c
@@ -0,0 +1,36 @@
+#include "tommath.h"
+#ifdef BNCORE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Known optimal configurations
+
+ CPU /Compiler /MUL CUTOFF/SQR CUTOFF
+-------------------------------------------------------------
+ Intel P4 Northwood /GCC v3.4.1 / 88/ 128/LTM 0.32 ;-)
+ AMD Athlon64 /GCC v3.4.4 / 80/ 120/LTM 0.35
+
+*/
+
+int KARATSUBA_MUL_CUTOFF = 80, /* Min. number of digits before Karatsuba multiplication is used. */
+ KARATSUBA_SQR_CUTOFF = 120, /* Min. number of digits before Karatsuba squaring is used. */
+
+ TOOM_MUL_CUTOFF = 350, /* no optimal values of these are known yet so set em high */
+ TOOM_SQR_CUTOFF = 400;
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bncore.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/dep/StormLib/src/libtommath/tommath.h b/dep/StormLib/src/libtommath/tommath.h
new file mode 100644
index 00000000000..1ead3d04bf5
--- /dev/null
+++ b/dep/StormLib/src/libtommath/tommath.h
@@ -0,0 +1,584 @@
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com
+ */
+#ifndef BN_H_
+#define BN_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+
+#include "tommath_class.h"
+
+#ifndef MIN
+ #define MIN(x,y) ((x)<(y)?(x):(y))
+#endif
+
+#ifndef MAX
+ #define MAX(x,y) ((x)>(y)?(x):(y))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+
+/* C++ compilers don't like assigning void * to mp_digit * */
+#define OPT_CAST(x) (x *)
+
+#else
+
+/* C on the other hand doesn't care */
+#define OPT_CAST(x)
+
+#endif
+
+
+/* detect 64-bit mode if possible */
+#if defined(__x86_64__)
+ #if !(defined(MP_64BIT) && defined(MP_16BIT) && defined(MP_8BIT))
+ #define MP_64BIT
+ #endif
+#endif
+
+/* some default configurations.
+ *
+ * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits
+ * A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits
+ *
+ * At the very least a mp_digit must be able to hold 7 bits
+ * [any size beyond that is ok provided it doesn't overflow the data type]
+ */
+#ifdef MP_8BIT
+ typedef unsigned char mp_digit;
+ typedef unsigned short mp_word;
+#elif defined(MP_16BIT)
+ typedef unsigned short mp_digit;
+ typedef unsigned long mp_word;
+#elif defined(MP_64BIT)
+ /* for GCC only on supported platforms */
+#ifndef CRYPT
+ typedef unsigned long long ulong64;
+ typedef signed long long long64;
+#endif
+
+ typedef unsigned long mp_digit;
+ typedef unsigned long mp_word __attribute__ ((mode(TI)));
+
+ #define DIGIT_BIT 60
+#else
+ /* this is the default case, 28-bit digits */
+
+ /* this is to make porting into LibTomCrypt easier :-) */
+#ifndef CRYPT
+ #if defined(_MSC_VER) || defined(__BORLANDC__)
+ typedef unsigned __int64 ulong64;
+ typedef signed __int64 long64;
+ #else
+ typedef unsigned long long ulong64;
+ typedef signed long long long64;
+ #endif
+#endif
+
+ typedef unsigned long mp_digit;
+ typedef ulong64 mp_word;
+
+#ifdef MP_31BIT
+ /* this is an extension that uses 31-bit digits */
+ #define DIGIT_BIT 31
+#else
+ /* default case is 28-bit digits, defines MP_28BIT as a handy macro to test */
+ #define DIGIT_BIT 28
+ #define MP_28BIT
+#endif
+#endif
+
+/* define heap macros */
+#ifndef CRYPT
+ /* default to libc stuff */
+ #ifndef XMALLOC
+ #define XMALLOC malloc
+ #define XFREE free
+ #define XREALLOC realloc
+ #define XCALLOC calloc
+ #else
+ /* prototypes for our heap functions */
+ extern void *XMALLOC(size_t n);
+ extern void *XREALLOC(void *p, size_t n);
+ extern void *XCALLOC(size_t n, size_t s);
+ extern void XFREE(void *p);
+ #endif
+#endif
+
+
+/* otherwise the bits per digit is calculated automatically from the size of a mp_digit */
+#ifndef DIGIT_BIT
+ #define DIGIT_BIT ((int)((CHAR_BIT * sizeof(mp_digit) - 1))) /* bits per digit */
+#endif
+
+#define MP_DIGIT_BIT DIGIT_BIT
+#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
+#define MP_DIGIT_MAX MP_MASK
+
+/* equalities */
+#define MP_LT -1 /* less than */
+#define MP_EQ 0 /* equal to */
+#define MP_GT 1 /* greater than */
+
+#define MP_ZPOS 0 /* positive integer */
+#define MP_NEG 1 /* negative */
+
+#define MP_OKAY 0 /* ok result */
+#define MP_MEM -2 /* out of mem */
+#define MP_VAL -3 /* invalid input */
+#define MP_RANGE MP_VAL
+
+#define MP_YES 1 /* yes response */
+#define MP_NO 0 /* no response */
+
+/* Primality generation flags */
+#define LTM_PRIME_BBS 0x0001 /* BBS style prime */
+#define LTM_PRIME_SAFE 0x0002 /* Safe prime (p-1)/2 == prime */
+#define LTM_PRIME_2MSB_ON 0x0008 /* force 2nd MSB to 1 */
+
+typedef int mp_err;
+
+/* you'll have to tune these... */
+extern int KARATSUBA_MUL_CUTOFF,
+ KARATSUBA_SQR_CUTOFF,
+ TOOM_MUL_CUTOFF,
+ TOOM_SQR_CUTOFF;
+
+/* define this to use lower memory usage routines (exptmods mostly) */
+/* #define MP_LOW_MEM */
+
+/* default precision */
+#ifndef MP_PREC
+ #ifndef MP_LOW_MEM
+ #define MP_PREC 32 /* default digits of precision */
+ #else
+ #define MP_PREC 8 /* default digits of precision */
+ #endif
+#endif
+
+/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
+#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
+
+/* the infamous mp_int structure */
+typedef struct {
+ int used, alloc, sign;
+ mp_digit *dp;
+} mp_int;
+
+/* callback for mp_prime_random, should fill dst with random bytes and return how many read [upto len] */
+typedef int ltm_prime_callback(unsigned char *dst, int len, void *dat);
+
+
+#define USED(m) ((m)->used)
+#define DIGIT(m,k) ((m)->dp[(k)])
+#define SIGN(m) ((m)->sign)
+
+/* error code to char* string */
+char *mp_error_to_string(int code);
+
+/* ---> init and deinit bignum functions <--- */
+/* init a bignum */
+int mp_init(mp_int *a);
+
+/* free a bignum */
+void mp_clear(mp_int *a);
+
+/* init a null terminated series of arguments */
+int mp_init_multi(mp_int *mp, ...);
+
+/* clear a null terminated series of arguments */
+void mp_clear_multi(mp_int *mp, ...);
+
+/* exchange two ints */
+void mp_exch(mp_int *a, mp_int *b);
+
+/* shrink ram required for a bignum */
+int mp_shrink(mp_int *a);
+
+/* grow an int to a given size */
+int mp_grow(mp_int *a, int size);
+
+/* init to a given number of digits */
+int mp_init_size(mp_int *a, int size);
+
+/* ---> Basic Manipulations <--- */
+#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
+#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
+#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
+
+/* set to zero */
+void mp_zero(mp_int *a);
+
+/* set to a digit */
+void mp_set(mp_int *a, mp_digit b);
+
+/* set a 32-bit const */
+int mp_set_int(mp_int *a, unsigned long b);
+
+/* get a 32-bit value */
+unsigned long mp_get_int(mp_int * a);
+
+/* initialize and set a digit */
+int mp_init_set (mp_int * a, mp_digit b);
+
+/* initialize and set 32-bit value */
+int mp_init_set_int (mp_int * a, unsigned long b);
+
+/* copy, b = a */
+int mp_copy(mp_int *a, mp_int *b);
+
+/* inits and copies, a = b */
+int mp_init_copy(mp_int *a, mp_int *b);
+
+/* trim unused digits */
+void mp_clamp(mp_int *a);
+
+/* ---> digit manipulation <--- */
+
+/* right shift by "b" digits */
+void mp_rshd(mp_int *a, int b);
+
+/* left shift by "b" digits */
+int mp_lshd(mp_int *a, int b);
+
+/* c = a / 2**b */
+int mp_div_2d(mp_int *a, int b, mp_int *c, mp_int *d);
+
+/* b = a/2 */
+int mp_div_2(mp_int *a, mp_int *b);
+
+/* c = a * 2**b */
+int mp_mul_2d(mp_int *a, int b, mp_int *c);
+
+/* b = a*2 */
+int mp_mul_2(mp_int *a, mp_int *b);
+
+/* c = a mod 2**d */
+int mp_mod_2d(mp_int *a, int b, mp_int *c);
+
+/* computes a = 2**b */
+int mp_2expt(mp_int *a, int b);
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int mp_cnt_lsb(mp_int *a);
+
+/* I Love Earth! */
+
+/* makes a pseudo-random int of a given size */
+int mp_rand(mp_int *a, int digits);
+
+/* ---> binary operations <--- */
+/* c = a XOR b */
+int mp_xor(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = a OR b */
+int mp_or(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = a AND b */
+int mp_and(mp_int *a, mp_int *b, mp_int *c);
+
+/* ---> Basic arithmetic <--- */
+
+/* b = -a */
+int mp_neg(mp_int *a, mp_int *b);
+
+/* b = |a| */
+int mp_abs(mp_int *a, mp_int *b);
+
+/* compare a to b */
+int mp_cmp(mp_int *a, mp_int *b);
+
+/* compare |a| to |b| */
+int mp_cmp_mag(mp_int *a, mp_int *b);
+
+/* c = a + b */
+int mp_add(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = a - b */
+int mp_sub(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = a * b */
+int mp_mul(mp_int *a, mp_int *b, mp_int *c);
+
+/* b = a*a */
+int mp_sqr(mp_int *a, mp_int *b);
+
+/* a/b => cb + d == a */
+int mp_div(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* c = a mod b, 0 <= c < b */
+int mp_mod(mp_int *a, mp_int *b, mp_int *c);
+
+/* ---> single digit functions <--- */
+
+/* compare against a single digit */
+int mp_cmp_d(mp_int *a, mp_digit b);
+
+/* c = a + b */
+int mp_add_d(mp_int *a, mp_digit b, mp_int *c);
+
+/* c = a - b */
+int mp_sub_d(mp_int *a, mp_digit b, mp_int *c);
+
+/* c = a * b */
+int mp_mul_d(mp_int *a, mp_digit b, mp_int *c);
+
+/* a/b => cb + d == a */
+int mp_div_d(mp_int *a, mp_digit b, mp_int *c, mp_digit *d);
+
+/* a/3 => 3c + d == a */
+int mp_div_3(mp_int *a, mp_int *c, mp_digit *d);
+
+/* c = a**b */
+int mp_expt_d(mp_int *a, mp_digit b, mp_int *c);
+
+/* c = a mod b, 0 <= c < b */
+int mp_mod_d(mp_int *a, mp_digit b, mp_digit *c);
+
+/* ---> number theory <--- */
+
+/* d = a + b (mod c) */
+int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* d = a - b (mod c) */
+int mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* d = a * b (mod c) */
+int mp_mulmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* c = a * a (mod b) */
+int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = 1/a (mod b) */
+int mp_invmod(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = (a, b) */
+int mp_gcd(mp_int *a, mp_int *b, mp_int *c);
+
+/* produces value such that U1*a + U2*b = U3 */
+int mp_exteuclid(mp_int *a, mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3);
+
+/* c = [a, b] or (a*b)/(a, b) */
+int mp_lcm(mp_int *a, mp_int *b, mp_int *c);
+
+/* finds one of the b'th root of a, such that |c|**b <= |a|
+ *
+ * returns error if a < 0 and b is even
+ */
+int mp_n_root(mp_int *a, mp_digit b, mp_int *c);
+
+/* special sqrt algo */
+int mp_sqrt(mp_int *arg, mp_int *ret);
+
+/* is number a square? */
+int mp_is_square(mp_int *arg, int *ret);
+
+/* computes the jacobi c = (a | n) (or Legendre if b is prime) */
+int mp_jacobi(mp_int *a, mp_int *n, int *c);
+
+/* used to setup the Barrett reduction for a given modulus b */
+int mp_reduce_setup(mp_int *a, mp_int *b);
+
+/* Barrett Reduction, computes a (mod b) with a precomputed value c
+ *
+ * Assumes that 0 < a <= b*b, note if 0 > a > -(b*b) then you can merely
+ * compute the reduction as -1 * mp_reduce(mp_abs(a)) [pseudo code].
+ */
+int mp_reduce(mp_int *a, mp_int *b, mp_int *c);
+
+/* setups the montgomery reduction */
+int mp_montgomery_setup(mp_int *a, mp_digit *mp);
+
+/* computes a = B**n mod b without division or multiplication useful for
+ * normalizing numbers in a Montgomery system.
+ */
+int mp_montgomery_calc_normalization(mp_int *a, mp_int *b);
+
+/* computes x/R == x (mod N) via Montgomery Reduction */
+int mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
+
+/* returns 1 if a is a valid DR modulus */
+int mp_dr_is_modulus(mp_int *a);
+
+/* sets the value of "d" required for mp_dr_reduce */
+void mp_dr_setup(mp_int *a, mp_digit *d);
+
+/* reduces a modulo b using the Diminished Radix method */
+int mp_dr_reduce(mp_int *a, mp_int *b, mp_digit mp);
+
+/* returns true if a can be reduced with mp_reduce_2k */
+int mp_reduce_is_2k(mp_int *a);
+
+/* determines k value for 2k reduction */
+int mp_reduce_2k_setup(mp_int *a, mp_digit *d);
+
+/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */
+int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d);
+
+/* returns true if a can be reduced with mp_reduce_2k_l */
+int mp_reduce_is_2k_l(mp_int *a);
+
+/* determines k value for 2k reduction */
+int mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
+
+/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */
+int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
+
+/* d = a**b (mod c) */
+int mp_exptmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* ---> Primes <--- */
+
+/* number of primes */
+#ifdef MP_8BIT
+ #define PRIME_SIZE 31
+#else
+ #define PRIME_SIZE 256
+#endif
+
+/* table of first PRIME_SIZE primes */
+extern const mp_digit ltm_prime_tab[];
+
+/* result=1 if a is divisible by one of the first PRIME_SIZE primes */
+int mp_prime_is_divisible(mp_int *a, int *result);
+
+/* performs one Fermat test of "a" using base "b".
+ * Sets result to 0 if composite or 1 if probable prime
+ */
+int mp_prime_fermat(mp_int *a, mp_int *b, int *result);
+
+/* performs one Miller-Rabin test of "a" using base "b".
+ * Sets result to 0 if composite or 1 if probable prime
+ */
+int mp_prime_miller_rabin(mp_int *a, mp_int *b, int *result);
+
+/* This gives [for a given bit size] the number of trials required
+ * such that Miller-Rabin gives a prob of failure lower than 2^-96
+ */
+int mp_prime_rabin_miller_trials(int size);
+
+/* performs t rounds of Miller-Rabin on "a" using the first
+ * t prime bases. Also performs an initial sieve of trial
+ * division. Determines if "a" is prime with probability
+ * of error no more than (1/4)**t.
+ *
+ * Sets result to 1 if probably prime, 0 otherwise
+ */
+int mp_prime_is_prime(mp_int *a, int t, int *result);
+
+/* finds the next prime after the number "a" using "t" trials
+ * of Miller-Rabin.
+ *
+ * bbs_style = 1 means the prime must be congruent to 3 mod 4
+ */
+int mp_prime_next_prime(mp_int *a, int t, int bbs_style);
+
+/* makes a truly random prime of a given size (bytes),
+ * call with bbs = 1 if you want it to be congruent to 3 mod 4
+ *
+ * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
+ * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
+ * so it can be NULL
+ *
+ * The prime generated will be larger than 2^(8*size).
+ */
+#define mp_prime_random(a, t, size, bbs, cb, dat) mp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?LTM_PRIME_BBS:0, cb, dat)
+
+/* makes a truly random prime of a given size (bits),
+ *
+ * Flags are as follows:
+ *
+ * LTM_PRIME_BBS - make prime congruent to 3 mod 4
+ * LTM_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies LTM_PRIME_BBS)
+ * LTM_PRIME_2MSB_OFF - make the 2nd highest bit zero
+ * LTM_PRIME_2MSB_ON - make the 2nd highest bit one
+ *
+ * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
+ * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
+ * so it can be NULL
+ *
+ */
+int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat);
+
+/* ---> radix conversion <--- */
+int mp_count_bits(mp_int *a);
+
+int mp_unsigned_bin_size(mp_int *a);
+int mp_read_unsigned_bin(mp_int *a, const unsigned char *b, int c);
+int mp_to_unsigned_bin(mp_int *a, unsigned char *b);
+int mp_to_unsigned_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen);
+
+int mp_signed_bin_size(mp_int *a);
+int mp_read_signed_bin(mp_int *a, const unsigned char *b, int c);
+int mp_to_signed_bin(mp_int *a, unsigned char *b);
+int mp_to_signed_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen);
+
+int mp_read_radix(mp_int *a, const char *str, int radix);
+int mp_toradix(mp_int *a, char *str, int radix);
+int mp_toradix_n(mp_int * a, char *str, int radix, int maxlen);
+int mp_radix_size(mp_int *a, int radix, int *size);
+
+int mp_fread(mp_int *a, int radix, FILE *stream);
+int mp_fwrite(mp_int *a, int radix, FILE *stream);
+
+#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len))
+#define mp_raw_size(mp) mp_signed_bin_size(mp)
+#define mp_toraw(mp, str) mp_to_signed_bin((mp), (str))
+#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len))
+#define mp_mag_size(mp) mp_unsigned_bin_size(mp)
+#define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str))
+
+#define mp_tobinary(M, S) mp_toradix((M), (S), 2)
+#define mp_tooctal(M, S) mp_toradix((M), (S), 8)
+#define mp_todecimal(M, S) mp_toradix((M), (S), 10)
+#define mp_tohex(M, S) mp_toradix((M), (S), 16)
+
+/* lowlevel functions, do not call! */
+int s_mp_add(mp_int *a, mp_int *b, mp_int *c);
+int s_mp_sub(mp_int *a, mp_int *b, mp_int *c);
+#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
+int fast_s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
+int s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
+int fast_s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
+int s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
+int fast_s_mp_sqr(mp_int *a, mp_int *b);
+int s_mp_sqr(mp_int *a, mp_int *b);
+int mp_karatsuba_mul(mp_int *a, mp_int *b, mp_int *c);
+int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c);
+int mp_karatsuba_sqr(mp_int *a, mp_int *b);
+int mp_toom_sqr(mp_int *a, mp_int *b);
+int fast_mp_invmod(mp_int *a, mp_int *b, mp_int *c);
+int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c);
+int fast_mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
+int mp_exptmod_fast(mp_int *G, mp_int *X, mp_int *P, mp_int *Y, int mode);
+int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int mode);
+void bn_reverse(unsigned char *s, int len);
+
+extern const char *mp_s_rmap;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtommath/tommath.h,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2006/03/31 14:18:44 $ */
diff --git a/dep/StormLib/src/libtommath/tommath_class.h b/dep/StormLib/src/libtommath/tommath_class.h
new file mode 100644
index 00000000000..18d1553dee7
--- /dev/null
+++ b/dep/StormLib/src/libtommath/tommath_class.h
@@ -0,0 +1,999 @@
+#if !(defined(LTM1) && defined(LTM2) && defined(LTM3))
+#if defined(LTM2)
+#define LTM3
+#endif
+#if defined(LTM1)
+#define LTM2
+#endif
+#define LTM1
+
+#if defined(LTM_ALL)
+#define BN_ERROR_C
+#define BN_FAST_MP_INVMOD_C
+#define BN_FAST_MP_MONTGOMERY_REDUCE_C
+#define BN_FAST_S_MP_MUL_DIGS_C
+#define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+#define BN_FAST_S_MP_SQR_C
+#define BN_MP_2EXPT_C
+#define BN_MP_ABS_C
+#define BN_MP_ADD_C
+#define BN_MP_ADD_D_C
+#define BN_MP_ADDMOD_C
+#define BN_MP_AND_C
+#define BN_MP_CLAMP_C
+#define BN_MP_CLEAR_C
+#define BN_MP_CLEAR_MULTI_C
+#define BN_MP_CMP_C
+#define BN_MP_CMP_D_C
+#define BN_MP_CMP_MAG_C
+#define BN_MP_CNT_LSB_C
+#define BN_MP_COPY_C
+#define BN_MP_COUNT_BITS_C
+#define BN_MP_DIV_C
+#define BN_MP_DIV_2_C
+#define BN_MP_DIV_2D_C
+#define BN_MP_DIV_3_C
+#define BN_MP_DIV_D_C
+#define BN_MP_DR_IS_MODULUS_C
+#define BN_MP_DR_REDUCE_C
+#define BN_MP_DR_SETUP_C
+#define BN_MP_EXCH_C
+#define BN_MP_EXPT_D_C
+#define BN_MP_EXPTMOD_C
+#define BN_MP_EXPTMOD_FAST_C
+#define BN_MP_EXTEUCLID_C
+#define BN_MP_FREAD_C
+#define BN_MP_FWRITE_C
+#define BN_MP_GCD_C
+#define BN_MP_GET_INT_C
+#define BN_MP_GROW_C
+#define BN_MP_INIT_C
+#define BN_MP_INIT_COPY_C
+#define BN_MP_INIT_MULTI_C
+#define BN_MP_INIT_SET_C
+#define BN_MP_INIT_SET_INT_C
+#define BN_MP_INIT_SIZE_C
+#define BN_MP_INVMOD_C
+#define BN_MP_INVMOD_SLOW_C
+#define BN_MP_IS_SQUARE_C
+#define BN_MP_JACOBI_C
+#define BN_MP_KARATSUBA_MUL_C
+#define BN_MP_KARATSUBA_SQR_C
+#define BN_MP_LCM_C
+#define BN_MP_LSHD_C
+#define BN_MP_MOD_C
+#define BN_MP_MOD_2D_C
+#define BN_MP_MOD_D_C
+#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+#define BN_MP_MONTGOMERY_REDUCE_C
+#define BN_MP_MONTGOMERY_SETUP_C
+#define BN_MP_MUL_C
+#define BN_MP_MUL_2_C
+#define BN_MP_MUL_2D_C
+#define BN_MP_MUL_D_C
+#define BN_MP_MULMOD_C
+#define BN_MP_N_ROOT_C
+#define BN_MP_NEG_C
+#define BN_MP_OR_C
+#define BN_MP_PRIME_FERMAT_C
+#define BN_MP_PRIME_IS_DIVISIBLE_C
+#define BN_MP_PRIME_IS_PRIME_C
+#define BN_MP_PRIME_MILLER_RABIN_C
+#define BN_MP_PRIME_NEXT_PRIME_C
+#define BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+#define BN_MP_PRIME_RANDOM_EX_C
+#define BN_MP_RADIX_SIZE_C
+#define BN_MP_RADIX_SMAP_C
+#define BN_MP_RAND_C
+#define BN_MP_READ_RADIX_C
+#define BN_MP_READ_SIGNED_BIN_C
+#define BN_MP_READ_UNSIGNED_BIN_C
+#define BN_MP_REDUCE_C
+#define BN_MP_REDUCE_2K_C
+#define BN_MP_REDUCE_2K_L_C
+#define BN_MP_REDUCE_2K_SETUP_C
+#define BN_MP_REDUCE_2K_SETUP_L_C
+#define BN_MP_REDUCE_IS_2K_C
+#define BN_MP_REDUCE_IS_2K_L_C
+#define BN_MP_REDUCE_SETUP_C
+#define BN_MP_RSHD_C
+#define BN_MP_SET_C
+#define BN_MP_SET_INT_C
+#define BN_MP_SHRINK_C
+#define BN_MP_SIGNED_BIN_SIZE_C
+#define BN_MP_SQR_C
+#define BN_MP_SQRMOD_C
+#define BN_MP_SQRT_C
+#define BN_MP_SUB_C
+#define BN_MP_SUB_D_C
+#define BN_MP_SUBMOD_C
+#define BN_MP_TO_SIGNED_BIN_C
+#define BN_MP_TO_SIGNED_BIN_N_C
+#define BN_MP_TO_UNSIGNED_BIN_C
+#define BN_MP_TO_UNSIGNED_BIN_N_C
+#define BN_MP_TOOM_MUL_C
+#define BN_MP_TOOM_SQR_C
+#define BN_MP_TORADIX_C
+#define BN_MP_TORADIX_N_C
+#define BN_MP_UNSIGNED_BIN_SIZE_C
+#define BN_MP_XOR_C
+#define BN_MP_ZERO_C
+#define BN_PRIME_TAB_C
+#define BN_REVERSE_C
+#define BN_S_MP_ADD_C
+#define BN_S_MP_EXPTMOD_C
+#define BN_S_MP_MUL_DIGS_C
+#define BN_S_MP_MUL_HIGH_DIGS_C
+#define BN_S_MP_SQR_C
+#define BN_S_MP_SUB_C
+#define BNCORE_C
+#endif
+
+#if defined(BN_ERROR_C)
+ #define BN_MP_ERROR_TO_STRING_C
+#endif
+
+#if defined(BN_FAST_MP_INVMOD_C)
+ #define BN_MP_ISEVEN_C
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_COPY_C
+ #define BN_MP_MOD_C
+ #define BN_MP_SET_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_ISODD_C
+ #define BN_MP_SUB_C
+ #define BN_MP_CMP_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_CMP_D_C
+ #define BN_MP_ADD_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_FAST_MP_MONTGOMERY_REDUCE_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_FAST_S_MP_MUL_DIGS_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_FAST_S_MP_SQR_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_2EXPT_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_ABS_C)
+ #define BN_MP_COPY_C
+#endif
+
+#if defined(BN_MP_ADD_C)
+ #define BN_S_MP_ADD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_ADD_D_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_ADDMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_ADD_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_AND_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_CLAMP_C)
+#endif
+
+#if defined(BN_MP_CLEAR_C)
+#endif
+
+#if defined(BN_MP_CLEAR_MULTI_C)
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_CMP_C)
+ #define BN_MP_CMP_MAG_C
+#endif
+
+#if defined(BN_MP_CMP_D_C)
+#endif
+
+#if defined(BN_MP_CMP_MAG_C)
+#endif
+
+#if defined(BN_MP_CNT_LSB_C)
+ #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_COPY_C)
+ #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_COUNT_BITS_C)
+#endif
+
+#if defined(BN_MP_DIV_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_COPY_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_SET_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_ABS_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_CMP_C
+ #define BN_MP_SUB_C
+ #define BN_MP_ADD_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_MULTI_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_INIT_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DIV_2_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_DIV_2D_C)
+ #define BN_MP_COPY_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_INIT_C
+ #define BN_MP_MOD_2D_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_DIV_3_C)
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DIV_D_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_COPY_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_DIV_3_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DR_IS_MODULUS_C)
+#endif
+
+#if defined(BN_MP_DR_REDUCE_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_DR_SETUP_C)
+#endif
+
+#if defined(BN_MP_EXCH_C)
+#endif
+
+#if defined(BN_MP_EXPT_D_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_SET_C
+ #define BN_MP_SQR_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MUL_C
+#endif
+
+#if defined(BN_MP_EXPTMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_INVMOD_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_ABS_C
+ #define BN_MP_CLEAR_MULTI_C
+ #define BN_MP_REDUCE_IS_2K_L_C
+ #define BN_S_MP_EXPTMOD_C
+ #define BN_MP_DR_IS_MODULUS_C
+ #define BN_MP_REDUCE_IS_2K_C
+ #define BN_MP_ISODD_C
+ #define BN_MP_EXPTMOD_FAST_C
+#endif
+
+#if defined(BN_MP_EXPTMOD_FAST_C)
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_INIT_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MONTGOMERY_SETUP_C
+ #define BN_FAST_MP_MONTGOMERY_REDUCE_C
+ #define BN_MP_MONTGOMERY_REDUCE_C
+ #define BN_MP_DR_SETUP_C
+ #define BN_MP_DR_REDUCE_C
+ #define BN_MP_REDUCE_2K_SETUP_C
+ #define BN_MP_REDUCE_2K_C
+ #define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+ #define BN_MP_MULMOD_C
+ #define BN_MP_SET_C
+ #define BN_MP_MOD_C
+ #define BN_MP_COPY_C
+ #define BN_MP_SQR_C
+ #define BN_MP_MUL_C
+ #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_EXTEUCLID_C)
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_SET_C
+ #define BN_MP_COPY_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_DIV_C
+ #define BN_MP_MUL_C
+ #define BN_MP_SUB_C
+ #define BN_MP_NEG_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_FREAD_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_S_RMAP_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_CMP_D_C
+#endif
+
+#if defined(BN_MP_FWRITE_C)
+ #define BN_MP_RADIX_SIZE_C
+ #define BN_MP_TORADIX_C
+#endif
+
+#if defined(BN_MP_GCD_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_ABS_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CNT_LSB_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_EXCH_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_GET_INT_C)
+#endif
+
+#if defined(BN_MP_GROW_C)
+#endif
+
+#if defined(BN_MP_INIT_C)
+#endif
+
+#if defined(BN_MP_INIT_COPY_C)
+ #define BN_MP_COPY_C
+#endif
+
+#if defined(BN_MP_INIT_MULTI_C)
+ #define BN_MP_ERR_C
+ #define BN_MP_INIT_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_INIT_SET_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SET_C
+#endif
+
+#if defined(BN_MP_INIT_SET_INT_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SET_INT_C
+#endif
+
+#if defined(BN_MP_INIT_SIZE_C)
+ #define BN_MP_INIT_C
+#endif
+
+#if defined(BN_MP_INVMOD_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_ISODD_C
+ #define BN_FAST_MP_INVMOD_C
+ #define BN_MP_INVMOD_SLOW_C
+#endif
+
+#if defined(BN_MP_INVMOD_SLOW_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_MOD_C
+ #define BN_MP_COPY_C
+ #define BN_MP_ISEVEN_C
+ #define BN_MP_SET_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_ISODD_C
+ #define BN_MP_ADD_C
+ #define BN_MP_SUB_C
+ #define BN_MP_CMP_C
+ #define BN_MP_CMP_D_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_IS_SQUARE_C)
+ #define BN_MP_MOD_D_C
+ #define BN_MP_INIT_SET_INT_C
+ #define BN_MP_MOD_C
+ #define BN_MP_GET_INT_C
+ #define BN_MP_SQRT_C
+ #define BN_MP_SQR_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_JACOBI_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CNT_LSB_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_MOD_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_KARATSUBA_MUL_C)
+ #define BN_MP_MUL_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_SUB_C
+ #define BN_MP_ADD_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_KARATSUBA_SQR_C)
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_SQR_C
+ #define BN_MP_SUB_C
+ #define BN_S_MP_ADD_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_ADD_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_LCM_C)
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_GCD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_DIV_C
+ #define BN_MP_MUL_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_LSHD_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_RSHD_C
+#endif
+
+#if defined(BN_MP_MOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_DIV_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_ADD_C
+ #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_MOD_2D_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_COPY_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MOD_D_C)
+ #define BN_MP_DIV_D_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_CALC_NORMALIZATION_C)
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_2EXPT_C
+ #define BN_MP_SET_C
+ #define BN_MP_MUL_2_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_REDUCE_C)
+ #define BN_FAST_MP_MONTGOMERY_REDUCE_C
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_SETUP_C)
+#endif
+
+#if defined(BN_MP_MUL_C)
+ #define BN_MP_TOOM_MUL_C
+ #define BN_MP_KARATSUBA_MUL_C
+ #define BN_FAST_S_MP_MUL_DIGS_C
+ #define BN_S_MP_MUL_C
+ #define BN_S_MP_MUL_DIGS_C
+#endif
+
+#if defined(BN_MP_MUL_2_C)
+ #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_MUL_2D_C)
+ #define BN_MP_COPY_C
+ #define BN_MP_GROW_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MUL_D_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MULMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_MUL_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_N_ROOT_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SET_C
+ #define BN_MP_COPY_C
+ #define BN_MP_EXPT_D_C
+ #define BN_MP_MUL_C
+ #define BN_MP_SUB_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_DIV_C
+ #define BN_MP_CMP_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_NEG_C)
+ #define BN_MP_COPY_C
+ #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_OR_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_FERMAT_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_INIT_C
+ #define BN_MP_EXPTMOD_C
+ #define BN_MP_CMP_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_IS_DIVISIBLE_C)
+ #define BN_MP_MOD_D_C
+#endif
+
+#if defined(BN_MP_PRIME_IS_PRIME_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_PRIME_IS_DIVISIBLE_C
+ #define BN_MP_INIT_C
+ #define BN_MP_SET_C
+ #define BN_MP_PRIME_MILLER_RABIN_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_MILLER_RABIN_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_CNT_LSB_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_EXPTMOD_C
+ #define BN_MP_CMP_C
+ #define BN_MP_SQRMOD_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_NEXT_PRIME_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_SET_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_ISEVEN_C
+ #define BN_MP_MOD_D_C
+ #define BN_MP_INIT_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_PRIME_MILLER_RABIN_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_RABIN_MILLER_TRIALS_C)
+#endif
+
+#if defined(BN_MP_PRIME_RANDOM_EX_C)
+ #define BN_MP_READ_UNSIGNED_BIN_C
+ #define BN_MP_PRIME_IS_PRIME_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_MUL_2_C
+ #define BN_MP_ADD_D_C
+#endif
+
+#if defined(BN_MP_RADIX_SIZE_C)
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_DIV_D_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_RADIX_SMAP_C)
+ #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_RAND_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_LSHD_C
+#endif
+
+#if defined(BN_MP_READ_RADIX_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_S_RMAP_C
+ #define BN_MP_RADIX_SMAP_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_READ_SIGNED_BIN_C)
+ #define BN_MP_READ_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_READ_UNSIGNED_BIN_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_REDUCE_C)
+ #define BN_MP_REDUCE_SETUP_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_MUL_C
+ #define BN_S_MP_MUL_HIGH_DIGS_C
+ #define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+ #define BN_MP_MOD_2D_C
+ #define BN_S_MP_MUL_DIGS_C
+ #define BN_MP_SUB_C
+ #define BN_MP_CMP_D_C
+ #define BN_MP_SET_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_ADD_C
+ #define BN_MP_CMP_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_MUL_D_C
+ #define BN_S_MP_ADD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_L_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_MUL_C
+ #define BN_S_MP_ADD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_SETUP_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_2EXPT_C
+ #define BN_MP_CLEAR_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_SETUP_L_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_2EXPT_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_IS_2K_C)
+ #define BN_MP_REDUCE_2K_C
+ #define BN_MP_COUNT_BITS_C
+#endif
+
+#if defined(BN_MP_REDUCE_IS_2K_L_C)
+#endif
+
+#if defined(BN_MP_REDUCE_SETUP_C)
+ #define BN_MP_2EXPT_C
+ #define BN_MP_DIV_C
+#endif
+
+#if defined(BN_MP_RSHD_C)
+ #define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_SET_C)
+ #define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_SET_INT_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_SHRINK_C)
+#endif
+
+#if defined(BN_MP_SIGNED_BIN_SIZE_C)
+ #define BN_MP_UNSIGNED_BIN_SIZE_C
+#endif
+
+#if defined(BN_MP_SQR_C)
+ #define BN_MP_TOOM_SQR_C
+ #define BN_MP_KARATSUBA_SQR_C
+ #define BN_FAST_S_MP_SQR_C
+ #define BN_S_MP_SQR_C
+#endif
+
+#if defined(BN_MP_SQRMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SQR_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_SQRT_C)
+ #define BN_MP_N_ROOT_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_DIV_C
+ #define BN_MP_ADD_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_SUB_C)
+ #define BN_S_MP_ADD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_SUB_D_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_SUBMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SUB_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_TO_SIGNED_BIN_C)
+ #define BN_MP_TO_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TO_SIGNED_BIN_N_C)
+ #define BN_MP_SIGNED_BIN_SIZE_C
+ #define BN_MP_TO_SIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TO_UNSIGNED_BIN_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_TO_UNSIGNED_BIN_N_C)
+ #define BN_MP_UNSIGNED_BIN_SIZE_C
+ #define BN_MP_TO_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TOOM_MUL_C)
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_MOD_2D_C
+ #define BN_MP_COPY_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_MUL_C
+ #define BN_MP_MUL_2_C
+ #define BN_MP_ADD_C
+ #define BN_MP_SUB_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_DIV_3_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_TOOM_SQR_C)
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_MOD_2D_C
+ #define BN_MP_COPY_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_SQR_C
+ #define BN_MP_MUL_2_C
+ #define BN_MP_ADD_C
+ #define BN_MP_SUB_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_DIV_3_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_TORADIX_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_DIV_D_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_TORADIX_N_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_DIV_D_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_UNSIGNED_BIN_SIZE_C)
+ #define BN_MP_COUNT_BITS_C
+#endif
+
+#if defined(BN_MP_XOR_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_ZERO_C)
+#endif
+
+#if defined(BN_PRIME_TAB_C)
+#endif
+
+#if defined(BN_REVERSE_C)
+#endif
+
+#if defined(BN_S_MP_ADD_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_S_MP_EXPTMOD_C)
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_INIT_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_REDUCE_SETUP_C
+ #define BN_MP_REDUCE_C
+ #define BN_MP_REDUCE_2K_SETUP_L_C
+ #define BN_MP_REDUCE_2K_L_C
+ #define BN_MP_MOD_C
+ #define BN_MP_COPY_C
+ #define BN_MP_SQR_C
+ #define BN_MP_MUL_C
+ #define BN_MP_SET_C
+ #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_S_MP_MUL_DIGS_C)
+ #define BN_FAST_S_MP_MUL_DIGS_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_MUL_HIGH_DIGS_C)
+ #define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_SQR_C)
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_SUB_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BNCORE_C)
+#endif
+
+#ifdef LTM3
+#define LTM_LAST
+#endif
+#include "tommath_superclass.h"
+#include "tommath_class.h"
+#else
+#define LTM_LAST
+#endif
+
+/* $Source: /cvs/libtom/libtommath/tommath_class.h,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2005/07/28 11:59:32 $ */
diff --git a/dep/StormLib/src/libtommath/tommath_superclass.h b/dep/StormLib/src/libtommath/tommath_superclass.h
new file mode 100644
index 00000000000..2fdebe6838f
--- /dev/null
+++ b/dep/StormLib/src/libtommath/tommath_superclass.h
@@ -0,0 +1,76 @@
+/* super class file for PK algos */
+
+/* default ... include all MPI */
+#define LTM_ALL
+
+/* RSA only (does not support DH/DSA/ECC) */
+/* #define SC_RSA_1 */
+
+/* For reference.... On an Athlon64 optimizing for speed...
+
+ LTM's mpi.o with all functions [striped] is 142KiB in size.
+
+*/
+
+/* Works for RSA only, mpi.o is 68KiB */
+#ifdef SC_RSA_1
+ #define BN_MP_SHRINK_C
+ #define BN_MP_LCM_C
+ #define BN_MP_PRIME_RANDOM_EX_C
+ #define BN_MP_INVMOD_C
+ #define BN_MP_GCD_C
+ #define BN_MP_MOD_C
+ #define BN_MP_MULMOD_C
+ #define BN_MP_ADDMOD_C
+ #define BN_MP_EXPTMOD_C
+ #define BN_MP_SET_INT_C
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_CLEAR_MULTI_C
+ #define BN_MP_UNSIGNED_BIN_SIZE_C
+ #define BN_MP_TO_UNSIGNED_BIN_C
+ #define BN_MP_MOD_D_C
+ #define BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+ #define BN_REVERSE_C
+ #define BN_PRIME_TAB_C
+
+ /* other modifiers */
+ #define BN_MP_DIV_SMALL /* Slower division, not critical */
+
+ /* here we are on the last pass so we turn things off. The functions classes are still there
+ * but we remove them specifically from the build. This also invokes tweaks in functions
+ * like removing support for even moduli, etc...
+ */
+#ifdef LTM_LAST
+ #undef BN_MP_TOOM_MUL_C
+ #undef BN_MP_TOOM_SQR_C
+ #undef BN_MP_KARATSUBA_MUL_C
+ #undef BN_MP_KARATSUBA_SQR_C
+ #undef BN_MP_REDUCE_C
+ #undef BN_MP_REDUCE_SETUP_C
+ #undef BN_MP_DR_IS_MODULUS_C
+ #undef BN_MP_DR_SETUP_C
+ #undef BN_MP_DR_REDUCE_C
+ #undef BN_MP_REDUCE_IS_2K_C
+ #undef BN_MP_REDUCE_2K_SETUP_C
+ #undef BN_MP_REDUCE_2K_C
+ #undef BN_S_MP_EXPTMOD_C
+ #undef BN_MP_DIV_3_C
+ #undef BN_S_MP_MUL_HIGH_DIGS_C
+ #undef BN_FAST_S_MP_MUL_HIGH_DIGS_C
+ #undef BN_FAST_MP_INVMOD_C
+
+ /* To safely undefine these you have to make sure your RSA key won't exceed the Comba threshold
+ * which is roughly 255 digits [7140 bits for 32-bit machines, 15300 bits for 64-bit machines]
+ * which means roughly speaking you can handle upto 2536-bit RSA keys with these defined without
+ * trouble.
+ */
+ #undef BN_S_MP_MUL_DIGS_C
+ #undef BN_S_MP_SQR_C
+ #undef BN_MP_MONTGOMERY_REDUCE_C
+#endif
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/tommath_superclass.h,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2005/05/14 13:29:17 $ */
diff --git a/dep/StormLib/src/lzma/C/LzFind.c b/dep/StormLib/src/lzma/C/LzFind.c
new file mode 100644
index 00000000000..e3ecb05420e
--- /dev/null
+++ b/dep/StormLib/src/lzma/C/LzFind.c
@@ -0,0 +1,761 @@
+/* LzFind.c -- Match finder for LZ algorithms
+2009-04-22 : Igor Pavlov : Public domain */
+
+#include <string.h>
+
+#include "LzFind.h"
+#include "LzHash.h"
+
+#define kEmptyHashValue 0
+#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
+#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
+#define kNormalizeMask (~(kNormalizeStepMin - 1))
+#define kMaxHistorySize ((UInt32)3 << 30)
+
+#define kStartMaxLen 3
+
+static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+ if (!p->directInput)
+ {
+ alloc->Free(alloc, p->bufferBase);
+ p->bufferBase = 0;
+ }
+}
+
+/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
+
+static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
+{
+ UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
+ if (p->directInput)
+ {
+ p->blockSize = blockSize;
+ return 1;
+ }
+ if (p->bufferBase == 0 || p->blockSize != blockSize)
+ {
+ LzInWindow_Free(p, alloc);
+ p->blockSize = blockSize;
+ p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
+ }
+ return (p->bufferBase != 0);
+}
+
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
+
+UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
+
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
+{
+ p->posLimit -= subValue;
+ p->pos -= subValue;
+ p->streamPos -= subValue;
+}
+
+static void MatchFinder_ReadBlock(CMatchFinder *p)
+{
+ if (p->streamEndWasReached || p->result != SZ_OK)
+ return;
+ if (p->directInput)
+ {
+ UInt32 curSize = 0xFFFFFFFF - p->streamPos;
+ if (curSize > p->directInputRem)
+ curSize = (UInt32)p->directInputRem;
+ p->directInputRem -= curSize;
+ p->streamPos += curSize;
+ if (p->directInputRem == 0)
+ p->streamEndWasReached = 1;
+ return;
+ }
+ for (;;)
+ {
+ Byte *dest = p->buffer + (p->streamPos - p->pos);
+ size_t size = (p->bufferBase + p->blockSize - dest);
+ if (size == 0)
+ return;
+ p->result = p->stream->Read(p->stream, dest, &size);
+ if (p->result != SZ_OK)
+ return;
+ if (size == 0)
+ {
+ p->streamEndWasReached = 1;
+ return;
+ }
+ p->streamPos += (UInt32)size;
+ if (p->streamPos - p->pos > p->keepSizeAfter)
+ return;
+ }
+}
+
+void MatchFinder_MoveBlock(CMatchFinder *p)
+{
+ memmove(p->bufferBase,
+ p->buffer - p->keepSizeBefore,
+ (size_t)(p->streamPos - p->pos + p->keepSizeBefore));
+ p->buffer = p->bufferBase + p->keepSizeBefore;
+}
+
+int MatchFinder_NeedMove(CMatchFinder *p)
+{
+ if (p->directInput)
+ return 0;
+ /* if (p->streamEndWasReached) return 0; */
+ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
+}
+
+void MatchFinder_ReadIfRequired(CMatchFinder *p)
+{
+ if (p->streamEndWasReached)
+ return;
+ if (p->keepSizeAfter >= p->streamPos - p->pos)
+ MatchFinder_ReadBlock(p);
+}
+
+static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
+{
+ if (MatchFinder_NeedMove(p))
+ MatchFinder_MoveBlock(p);
+ MatchFinder_ReadBlock(p);
+}
+
+static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
+{
+ p->cutValue = 32;
+ p->btMode = 1;
+ p->numHashBytes = 4;
+ p->bigHash = 0;
+}
+
+#define kCrcPoly 0xEDB88320
+
+void MatchFinder_Construct(CMatchFinder *p)
+{
+ UInt32 i;
+ p->bufferBase = 0;
+ p->directInput = 0;
+ p->hash = 0;
+ MatchFinder_SetDefaultSettings(p);
+
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ int j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
+ p->crc[i] = r;
+ }
+}
+
+static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->hash);
+ p->hash = 0;
+}
+
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ LzInWindow_Free(p, alloc);
+}
+
+static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
+{
+ size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
+ if (sizeInBytes / sizeof(CLzRef) != num)
+ return 0;
+ return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
+}
+
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAlloc *alloc)
+{
+ UInt32 sizeReserv;
+ if (historySize > kMaxHistorySize)
+ {
+ MatchFinder_Free(p, alloc);
+ return 0;
+ }
+ sizeReserv = historySize >> 1;
+ if (historySize > ((UInt32)2 << 30))
+ sizeReserv = historySize >> 2;
+ sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
+
+ p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
+ p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
+ /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
+ if (LzInWindow_Create(p, sizeReserv, alloc))
+ {
+ UInt32 newCyclicBufferSize = historySize + 1;
+ UInt32 hs;
+ p->matchMaxLen = matchMaxLen;
+ {
+ p->fixedHashSize = 0;
+ if (p->numHashBytes == 2)
+ hs = (1 << 16) - 1;
+ else
+ {
+ hs = historySize - 1;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ hs >>= 1;
+ hs |= 0xFFFF; /* don't change it! It's required for Deflate */
+ if (hs > (1 << 24))
+ {
+ if (p->numHashBytes == 3)
+ hs = (1 << 24) - 1;
+ else
+ hs >>= 1;
+ }
+ }
+ p->hashMask = hs;
+ hs++;
+ if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
+ if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
+ if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
+ hs += p->fixedHashSize;
+ }
+
+ {
+ UInt32 prevSize = p->hashSizeSum + p->numSons;
+ UInt32 newSize;
+ p->historySize = historySize;
+ p->hashSizeSum = hs;
+ p->cyclicBufferSize = newCyclicBufferSize;
+ p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
+ newSize = p->hashSizeSum + p->numSons;
+ if (p->hash != 0 && prevSize == newSize)
+ return 1;
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ p->hash = AllocRefs(newSize, alloc);
+ if (p->hash != 0)
+ {
+ p->son = p->hash + p->hashSizeSum;
+ return 1;
+ }
+ }
+ }
+ MatchFinder_Free(p, alloc);
+ return 0;
+}
+
+static void MatchFinder_SetLimits(CMatchFinder *p)
+{
+ UInt32 limit = kMaxValForNormalize - p->pos;
+ UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
+ if (limit2 < limit)
+ limit = limit2;
+ limit2 = p->streamPos - p->pos;
+ if (limit2 <= p->keepSizeAfter)
+ {
+ if (limit2 > 0)
+ limit2 = 1;
+ }
+ else
+ limit2 -= p->keepSizeAfter;
+ if (limit2 < limit)
+ limit = limit2;
+ {
+ UInt32 lenLimit = p->streamPos - p->pos;
+ if (lenLimit > p->matchMaxLen)
+ lenLimit = p->matchMaxLen;
+ p->lenLimit = lenLimit;
+ }
+ p->posLimit = p->pos + limit;
+}
+
+void MatchFinder_Init(CMatchFinder *p)
+{
+ UInt32 i;
+ for (i = 0; i < p->hashSizeSum; i++)
+ p->hash[i] = kEmptyHashValue;
+ p->cyclicBufferPos = 0;
+ p->buffer = p->bufferBase;
+ p->pos = p->streamPos = p->cyclicBufferSize;
+ p->result = SZ_OK;
+ p->streamEndWasReached = 0;
+ MatchFinder_ReadBlock(p);
+ MatchFinder_SetLimits(p);
+}
+
+static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
+{
+ return (p->pos - p->historySize - 1) & kNormalizeMask;
+}
+
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
+{
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 value = items[i];
+ if (value <= subValue)
+ value = kEmptyHashValue;
+ else
+ value -= subValue;
+ items[i] = value;
+ }
+}
+
+static void MatchFinder_Normalize(CMatchFinder *p)
+{
+ UInt32 subValue = MatchFinder_GetSubValue(p);
+ MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
+ MatchFinder_ReduceOffsets(p, subValue);
+}
+
+static void MatchFinder_CheckLimits(CMatchFinder *p)
+{
+ if (p->pos == kMaxValForNormalize)
+ MatchFinder_Normalize(p);
+ if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
+ MatchFinder_CheckAndMoveAndRead(p);
+ if (p->cyclicBufferPos == p->cyclicBufferSize)
+ p->cyclicBufferPos = 0;
+ MatchFinder_SetLimits(p);
+}
+
+static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *distances, UInt32 maxLen)
+{
+ son[_cyclicBufferPos] = curMatch;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ return distances;
+ {
+ const Byte *pb = cur - delta;
+ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+ if (pb[maxLen] == cur[maxLen] && *pb == *cur)
+ {
+ UInt32 len = 0;
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ return distances;
+ }
+ }
+ }
+ }
+}
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *distances, UInt32 maxLen)
+{
+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return distances;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ if (++len != lenLimit && pb[len] == cur[len])
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return distances;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ }
+}
+
+static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
+{
+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ {
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ }
+}
+
+#define MOVE_POS \
+ ++p->cyclicBufferPos; \
+ p->buffer++; \
+ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
+
+#define MOVE_POS_RET MOVE_POS return offset;
+
+static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
+
+#define GET_MATCHES_HEADER2(minLen, ret_op) \
+ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
+ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
+ cur = p->buffer;
+
+#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
+#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue)
+
+#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
+
+#define GET_MATCHES_FOOTER(offset, maxLen) \
+ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
+ distances + offset, maxLen) - distances); MOVE_POS_RET;
+
+#define SKIP_FOOTER \
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
+
+static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(2)
+ HASH2_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = 0;
+ GET_MATCHES_FOOTER(offset, 1)
+}
+
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = 0;
+ GET_MATCHES_FOOTER(offset, 2)
+}
+
+static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, delta2, maxLen, offset;
+ GET_MATCHES_HEADER(3)
+
+ HASH3_CALC;
+
+ delta2 = p->pos - p->hash[hash2Value];
+ curMatch = p->hash[kFix3HashSize + hashValue];
+
+ p->hash[hash2Value] =
+ p->hash[kFix3HashSize + hashValue] = p->pos;
+
+
+ maxLen = 2;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[0] = maxLen;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+ GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ delta2 = p->pos - p->hash[ hash2Value];
+ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+ curMatch = p->hash[kFix4HashSize + hashValue];
+
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+
+ maxLen = 1;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ }
+ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+ {
+ maxLen = 3;
+ distances[offset + 1] = delta3 - 1;
+ offset += 2;
+ delta2 = delta3;
+ }
+ if (offset != 0)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+ if (maxLen < 3)
+ maxLen = 3;
+ GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ delta2 = p->pos - p->hash[ hash2Value];
+ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+ curMatch = p->hash[kFix4HashSize + hashValue];
+
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+
+ maxLen = 1;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ }
+ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+ {
+ maxLen = 3;
+ distances[offset + 1] = delta3 - 1;
+ offset += 2;
+ delta2 = delta3;
+ }
+ if (offset != 0)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS_RET;
+ }
+ }
+ if (maxLen < 3)
+ maxLen = 3;
+ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+ distances + offset, maxLen) - (distances));
+ MOVE_POS_RET
+}
+
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+ distances, 2) - (distances));
+ MOVE_POS_RET
+}
+
+static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(2)
+ HASH2_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value;
+ SKIP_HEADER(3)
+ HASH3_CALC;
+ curMatch = p->hash[kFix3HashSize + hashValue];
+ p->hash[hash2Value] =
+ p->hash[kFix3HashSize + hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value, hash3Value;
+ SKIP_HEADER(4)
+ HASH4_CALC;
+ curMatch = p->hash[kFix4HashSize + hashValue];
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] = p->pos;
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value, hash3Value;
+ SKIP_HEADER(4)
+ HASH4_CALC;
+ curMatch = p->hash[kFix4HashSize + hashValue];
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS
+ }
+ while (--num != 0);
+}
+
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS
+ }
+ while (--num != 0);
+}
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
+{
+ vTable->Init = (Mf_Init_Func)MatchFinder_Init;
+ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
+ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+ if (!p->btMode)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+ }
+ else if (p->numHashBytes == 2)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+ }
+ else if (p->numHashBytes == 3)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+ }
+ else
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+ }
+}
diff --git a/dep/StormLib/src/lzma/C/LzFind.h b/dep/StormLib/src/lzma/C/LzFind.h
new file mode 100644
index 00000000000..010c4b92ba3
--- /dev/null
+++ b/dep/StormLib/src/lzma/C/LzFind.h
@@ -0,0 +1,115 @@
+/* LzFind.h -- Match finder for LZ algorithms
+2009-04-22 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_FIND_H
+#define __LZ_FIND_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef UInt32 CLzRef;
+
+typedef struct _CMatchFinder
+{
+ Byte *buffer;
+ UInt32 pos;
+ UInt32 posLimit;
+ UInt32 streamPos;
+ UInt32 lenLimit;
+
+ UInt32 cyclicBufferPos;
+ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
+
+ UInt32 matchMaxLen;
+ CLzRef *hash;
+ CLzRef *son;
+ UInt32 hashMask;
+ UInt32 cutValue;
+
+ Byte *bufferBase;
+ ISeqInStream *stream;
+ int streamEndWasReached;
+
+ UInt32 blockSize;
+ UInt32 keepSizeBefore;
+ UInt32 keepSizeAfter;
+
+ UInt32 numHashBytes;
+ int directInput;
+ size_t directInputRem;
+ int btMode;
+ int bigHash;
+ UInt32 historySize;
+ UInt32 fixedHashSize;
+ UInt32 hashSizeSum;
+ UInt32 numSons;
+ SRes result;
+ UInt32 crc[256];
+} CMatchFinder;
+
+#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
+#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
+
+#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+
+int MatchFinder_NeedMove(CMatchFinder *p);
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
+void MatchFinder_MoveBlock(CMatchFinder *p);
+void MatchFinder_ReadIfRequired(CMatchFinder *p);
+
+void MatchFinder_Construct(CMatchFinder *p);
+
+/* Conditions:
+ historySize <= 3 GB
+ keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
+*/
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAlloc *alloc);
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+ UInt32 *distances, UInt32 maxLen);
+
+/*
+Conditions:
+ Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
+ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
+*/
+
+typedef void (*Mf_Init_Func)(void *object);
+typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
+typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
+typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
+typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
+typedef void (*Mf_Skip_Func)(void *object, UInt32);
+
+typedef struct _IMatchFinder
+{
+ Mf_Init_Func Init;
+ Mf_GetIndexByte_Func GetIndexByte;
+ Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
+ Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
+ Mf_GetMatches_Func GetMatches;
+ Mf_Skip_Func Skip;
+} IMatchFinder;
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
+
+void MatchFinder_Init(CMatchFinder *p);
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dep/StormLib/src/lzma/C/LzFindMt.c b/dep/StormLib/src/lzma/C/LzFindMt.c
new file mode 100644
index 00000000000..aa41ed98a57
--- /dev/null
+++ b/dep/StormLib/src/lzma/C/LzFindMt.c
@@ -0,0 +1,793 @@
+/* LzFindMt.c -- multithreaded Match finder for LZ algorithms
+2009-09-20 : Igor Pavlov : Public domain */
+
+#include "LzHash.h"
+
+#include "LzFindMt.h"
+
+void MtSync_Construct(CMtSync *p)
+{
+ p->wasCreated = False;
+ p->csWasInitialized = False;
+ p->csWasEntered = False;
+ Thread_Construct(&p->thread);
+ Event_Construct(&p->canStart);
+ Event_Construct(&p->wasStarted);
+ Event_Construct(&p->wasStopped);
+ Semaphore_Construct(&p->freeSemaphore);
+ Semaphore_Construct(&p->filledSemaphore);
+}
+
+void MtSync_GetNextBlock(CMtSync *p)
+{
+ if (p->needStart)
+ {
+ p->numProcessedBlocks = 1;
+ p->needStart = False;
+ p->stopWriting = False;
+ p->exit = False;
+ Event_Reset(&p->wasStarted);
+ Event_Reset(&p->wasStopped);
+
+ Event_Set(&p->canStart);
+ Event_Wait(&p->wasStarted);
+ }
+ else
+ {
+ CriticalSection_Leave(&p->cs);
+ p->csWasEntered = False;
+ p->numProcessedBlocks++;
+ Semaphore_Release1(&p->freeSemaphore);
+ }
+ Semaphore_Wait(&p->filledSemaphore);
+ CriticalSection_Enter(&p->cs);
+ p->csWasEntered = True;
+}
+
+/* MtSync_StopWriting must be called if Writing was started */
+
+void MtSync_StopWriting(CMtSync *p)
+{
+ UInt32 myNumBlocks = p->numProcessedBlocks;
+ if (!Thread_WasCreated(&p->thread) || p->needStart)
+ return;
+ p->stopWriting = True;
+ if (p->csWasEntered)
+ {
+ CriticalSection_Leave(&p->cs);
+ p->csWasEntered = False;
+ }
+ Semaphore_Release1(&p->freeSemaphore);
+
+ Event_Wait(&p->wasStopped);
+
+ while (myNumBlocks++ != p->numProcessedBlocks)
+ {
+ Semaphore_Wait(&p->filledSemaphore);
+ Semaphore_Release1(&p->freeSemaphore);
+ }
+ p->needStart = True;
+}
+
+void MtSync_Destruct(CMtSync *p)
+{
+ if (Thread_WasCreated(&p->thread))
+ {
+ MtSync_StopWriting(p);
+ p->exit = True;
+ if (p->needStart)
+ Event_Set(&p->canStart);
+ Thread_Wait(&p->thread);
+ Thread_Close(&p->thread);
+ }
+ if (p->csWasInitialized)
+ {
+ CriticalSection_Delete(&p->cs);
+ p->csWasInitialized = False;
+ }
+
+ Event_Close(&p->canStart);
+ Event_Close(&p->wasStarted);
+ Event_Close(&p->wasStopped);
+ Semaphore_Close(&p->freeSemaphore);
+ Semaphore_Close(&p->filledSemaphore);
+
+ p->wasCreated = False;
+}
+
+#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; }
+
+static SRes MtSync_Create2(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks)
+{
+ if (p->wasCreated)
+ return SZ_OK;
+
+ RINOK_THREAD(CriticalSection_Init(&p->cs));
+ p->csWasInitialized = True;
+
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart));
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStarted));
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped));
+
+ RINOK_THREAD(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks));
+ RINOK_THREAD(Semaphore_Create(&p->filledSemaphore, 0, numBlocks));
+
+ p->needStart = True;
+
+ RINOK_THREAD(Thread_Create(&p->thread, startAddress, obj));
+ p->wasCreated = True;
+ return SZ_OK;
+}
+
+static SRes MtSync_Create(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks)
+{
+ SRes res = MtSync_Create2(p, startAddress, obj, numBlocks);
+ if (res != SZ_OK)
+ MtSync_Destruct(p);
+ return res;
+}
+
+void MtSync_Init(CMtSync *p) { p->needStart = True; }
+
+#define kMtMaxValForNormalize 0xFFFFFFFF
+
+#define DEF_GetHeads2(name, v, action) \
+static void GetHeads ## name(const Byte *p, UInt32 pos, \
+UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \
+{ action; for (; numHeads != 0; numHeads--) { \
+const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } }
+
+#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;)
+
+DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), hashMask = hashMask; crc = crc; )
+DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask)
+DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask)
+DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask)
+/* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */
+
+void HashThreadFunc(CMatchFinderMt *mt)
+{
+ CMtSync *p = &mt->hashSync;
+ for (;;)
+ {
+ UInt32 numProcessedBlocks = 0;
+ Event_Wait(&p->canStart);
+ Event_Set(&p->wasStarted);
+ for (;;)
+ {
+ if (p->exit)
+ return;
+ if (p->stopWriting)
+ {
+ p->numProcessedBlocks = numProcessedBlocks;
+ Event_Set(&p->wasStopped);
+ break;
+ }
+
+ {
+ CMatchFinder *mf = mt->MatchFinder;
+ if (MatchFinder_NeedMove(mf))
+ {
+ CriticalSection_Enter(&mt->btSync.cs);
+ CriticalSection_Enter(&mt->hashSync.cs);
+ {
+ const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf);
+ const Byte *afterPtr;
+ MatchFinder_MoveBlock(mf);
+ afterPtr = MatchFinder_GetPointerToCurrentPos(mf);
+ mt->pointerToCurPos -= beforePtr - afterPtr;
+ mt->buffer -= beforePtr - afterPtr;
+ }
+ CriticalSection_Leave(&mt->btSync.cs);
+ CriticalSection_Leave(&mt->hashSync.cs);
+ continue;
+ }
+
+ Semaphore_Wait(&p->freeSemaphore);
+
+ MatchFinder_ReadIfRequired(mf);
+ if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize))
+ {
+ UInt32 subValue = (mf->pos - mf->historySize - 1);
+ MatchFinder_ReduceOffsets(mf, subValue);
+ MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1);
+ }
+ {
+ UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize;
+ UInt32 num = mf->streamPos - mf->pos;
+ heads[0] = 2;
+ heads[1] = num;
+ if (num >= mf->numHashBytes)
+ {
+ num = num - mf->numHashBytes + 1;
+ if (num > kMtHashBlockSize - 2)
+ num = kMtHashBlockSize - 2;
+ mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc);
+ heads[0] += num;
+ }
+ mf->pos += num;
+ mf->buffer += num;
+ }
+ }
+
+ Semaphore_Release1(&p->filledSemaphore);
+ }
+ }
+}
+
+void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p)
+{
+ MtSync_GetNextBlock(&p->hashSync);
+ p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize;
+ p->hashBufPosLimit += p->hashBuf[p->hashBufPos++];
+ p->hashNumAvail = p->hashBuf[p->hashBufPos++];
+}
+
+#define kEmptyHashValue 0
+
+/* #define MFMT_GM_INLINE */
+
+#ifdef MFMT_GM_INLINE
+
+#define NO_INLINE MY_FAST_CALL
+
+Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+ UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes)
+{
+ do
+ {
+ UInt32 *distances = _distances + 1;
+ UInt32 curMatch = pos - *hash++;
+
+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ UInt32 cutValue = _cutValue;
+ UInt32 maxLen = _maxLen;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ break;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ if (++len != lenLimit && pb[len] == cur[len])
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ break;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ }
+ pos++;
+ _cyclicBufferPos++;
+ cur++;
+ {
+ UInt32 num = (UInt32)(distances - _distances);
+ *_distances = num - 1;
+ _distances += num;
+ limit -= num;
+ }
+ }
+ while (limit > 0 && --size != 0);
+ *posRes = pos;
+ return limit;
+}
+
+#endif
+
+void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
+{
+ UInt32 numProcessed = 0;
+ UInt32 curPos = 2;
+ UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2);
+ distances[1] = p->hashNumAvail;
+ while (curPos < limit)
+ {
+ if (p->hashBufPos == p->hashBufPosLimit)
+ {
+ MatchFinderMt_GetNextBlock_Hash(p);
+ distances[1] = numProcessed + p->hashNumAvail;
+ if (p->hashNumAvail >= p->numHashBytes)
+ continue;
+ for (; p->hashNumAvail != 0; p->hashNumAvail--)
+ distances[curPos++] = 0;
+ break;
+ }
+ {
+ UInt32 size = p->hashBufPosLimit - p->hashBufPos;
+ UInt32 lenLimit = p->matchMaxLen;
+ UInt32 pos = p->pos;
+ UInt32 cyclicBufferPos = p->cyclicBufferPos;
+ if (lenLimit >= p->hashNumAvail)
+ lenLimit = p->hashNumAvail;
+ {
+ UInt32 size2 = p->hashNumAvail - lenLimit + 1;
+ if (size2 < size)
+ size = size2;
+ size2 = p->cyclicBufferSize - cyclicBufferPos;
+ if (size2 < size)
+ size = size2;
+ }
+ #ifndef MFMT_GM_INLINE
+ while (curPos < limit && size-- != 0)
+ {
+ UInt32 *startDistances = distances + curPos;
+ UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++],
+ pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
+ startDistances + 1, p->numHashBytes - 1) - startDistances);
+ *startDistances = num - 1;
+ curPos += num;
+ cyclicBufferPos++;
+ pos++;
+ p->buffer++;
+ }
+ #else
+ {
+ UInt32 posRes;
+ curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
+ distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes);
+ p->hashBufPos += posRes - pos;
+ cyclicBufferPos += posRes - pos;
+ p->buffer += posRes - pos;
+ pos = posRes;
+ }
+ #endif
+
+ numProcessed += pos - p->pos;
+ p->hashNumAvail -= pos - p->pos;
+ p->pos = pos;
+ if (cyclicBufferPos == p->cyclicBufferSize)
+ cyclicBufferPos = 0;
+ p->cyclicBufferPos = cyclicBufferPos;
+ }
+ }
+ distances[0] = curPos;
+}
+
+void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)
+{
+ CMtSync *sync = &p->hashSync;
+ if (!sync->needStart)
+ {
+ CriticalSection_Enter(&sync->cs);
+ sync->csWasEntered = True;
+ }
+
+ BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize);
+
+ if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize)
+ {
+ UInt32 subValue = p->pos - p->cyclicBufferSize;
+ MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2);
+ p->pos -= subValue;
+ }
+
+ if (!sync->needStart)
+ {
+ CriticalSection_Leave(&sync->cs);
+ sync->csWasEntered = False;
+ }
+}
+
+void BtThreadFunc(CMatchFinderMt *mt)
+{
+ CMtSync *p = &mt->btSync;
+ for (;;)
+ {
+ UInt32 blockIndex = 0;
+ Event_Wait(&p->canStart);
+ Event_Set(&p->wasStarted);
+ for (;;)
+ {
+ if (p->exit)
+ return;
+ if (p->stopWriting)
+ {
+ p->numProcessedBlocks = blockIndex;
+ MtSync_StopWriting(&mt->hashSync);
+ Event_Set(&p->wasStopped);
+ break;
+ }
+ Semaphore_Wait(&p->freeSemaphore);
+ BtFillBlock(mt, blockIndex++);
+ Semaphore_Release1(&p->filledSemaphore);
+ }
+ }
+}
+
+void MatchFinderMt_Construct(CMatchFinderMt *p)
+{
+ p->hashBuf = 0;
+ MtSync_Construct(&p->hashSync);
+ MtSync_Construct(&p->btSync);
+}
+
+void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->hashBuf);
+ p->hashBuf = 0;
+}
+
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc)
+{
+ MtSync_Destruct(&p->hashSync);
+ MtSync_Destruct(&p->btSync);
+ MatchFinderMt_FreeMem(p, alloc);
+}
+
+#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks)
+#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks)
+
+static unsigned MY_STD_CALL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; }
+static unsigned MY_STD_CALL BtThreadFunc2(void *p)
+{
+ Byte allocaDummy[0x180];
+ int i = 0;
+ for (i = 0; i < 16; i++)
+ allocaDummy[i] = (Byte)i;
+ BtThreadFunc((CMatchFinderMt *)p);
+ return 0;
+}
+
+SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc)
+{
+ CMatchFinder *mf = p->MatchFinder;
+ p->historySize = historySize;
+ if (kMtBtBlockSize <= matchMaxLen * 4)
+ return SZ_ERROR_PARAM;
+ if (p->hashBuf == 0)
+ {
+ p->hashBuf = (UInt32 *)alloc->Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32));
+ if (p->hashBuf == 0)
+ return SZ_ERROR_MEM;
+ p->btBuf = p->hashBuf + kHashBufferSize;
+ }
+ keepAddBufferBefore += (kHashBufferSize + kBtBufferSize);
+ keepAddBufferAfter += kMtHashBlockSize;
+ if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc))
+ return SZ_ERROR_MEM;
+
+ RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks));
+ RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks));
+ return SZ_OK;
+}
+
+/* Call it after ReleaseStream / SetStream */
+void MatchFinderMt_Init(CMatchFinderMt *p)
+{
+ CMatchFinder *mf = p->MatchFinder;
+ p->btBufPos = p->btBufPosLimit = 0;
+ p->hashBufPos = p->hashBufPosLimit = 0;
+ MatchFinder_Init(mf);
+ p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf);
+ p->btNumAvailBytes = 0;
+ p->lzPos = p->historySize + 1;
+
+ p->hash = mf->hash;
+ p->fixedHashSize = mf->fixedHashSize;
+ p->crc = mf->crc;
+
+ p->son = mf->son;
+ p->matchMaxLen = mf->matchMaxLen;
+ p->numHashBytes = mf->numHashBytes;
+ p->pos = mf->pos;
+ p->buffer = mf->buffer;
+ p->cyclicBufferPos = mf->cyclicBufferPos;
+ p->cyclicBufferSize = mf->cyclicBufferSize;
+ p->cutValue = mf->cutValue;
+}
+
+/* ReleaseStream is required to finish multithreading */
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p)
+{
+ MtSync_StopWriting(&p->btSync);
+ /* p->MatchFinder->ReleaseStream(); */
+}
+
+void MatchFinderMt_Normalize(CMatchFinderMt *p)
+{
+ MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize);
+ p->lzPos = p->historySize + 1;
+}
+
+void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)
+{
+ UInt32 blockIndex;
+ MtSync_GetNextBlock(&p->btSync);
+ blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask);
+ p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize;
+ p->btBufPosLimit += p->btBuf[p->btBufPos++];
+ p->btNumAvailBytes = p->btBuf[p->btBufPos++];
+ if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize)
+ MatchFinderMt_Normalize(p);
+}
+
+const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)
+{
+ return p->pointerToCurPos;
+}
+
+#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
+
+UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)
+{
+ GET_NEXT_BLOCK_IF_REQUIRED;
+ return p->btNumAvailBytes;
+}
+
+Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index)
+{
+ return p->pointerToCurPos[index];
+}
+
+UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+ UInt32 hash2Value, curMatch2;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ UInt32 lzPos = p->lzPos;
+ MT_HASH2_CALC
+
+ curMatch2 = hash[hash2Value];
+ hash[hash2Value] = lzPos;
+
+ if (curMatch2 >= matchMinPos)
+ if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+ {
+ *distances++ = 2;
+ *distances++ = lzPos - curMatch2 - 1;
+ }
+ return distances;
+}
+
+UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, curMatch2, curMatch3;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ UInt32 lzPos = p->lzPos;
+ MT_HASH3_CALC
+
+ curMatch2 = hash[ hash2Value];
+ curMatch3 = hash[kFix3HashSize + hash3Value];
+
+ hash[ hash2Value] =
+ hash[kFix3HashSize + hash3Value] =
+ lzPos;
+
+ if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+ {
+ distances[1] = lzPos - curMatch2 - 1;
+ if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
+ {
+ distances[0] = 3;
+ return distances + 2;
+ }
+ distances[0] = 2;
+ distances += 2;
+ }
+ if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
+ {
+ *distances++ = 3;
+ *distances++ = lzPos - curMatch3 - 1;
+ }
+ return distances;
+}
+
+/*
+UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ UInt32 lzPos = p->lzPos;
+ MT_HASH4_CALC
+
+ curMatch2 = hash[ hash2Value];
+ curMatch3 = hash[kFix3HashSize + hash3Value];
+ curMatch4 = hash[kFix4HashSize + hash4Value];
+
+ hash[ hash2Value] =
+ hash[kFix3HashSize + hash3Value] =
+ hash[kFix4HashSize + hash4Value] =
+ lzPos;
+
+ if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+ {
+ distances[1] = lzPos - curMatch2 - 1;
+ if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
+ {
+ distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3;
+ return distances + 2;
+ }
+ distances[0] = 2;
+ distances += 2;
+ }
+ if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
+ {
+ distances[1] = lzPos - curMatch3 - 1;
+ if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3])
+ {
+ distances[0] = 4;
+ return distances + 2;
+ }
+ distances[0] = 3;
+ distances += 2;
+ }
+
+ if (curMatch4 >= matchMinPos)
+ if (
+ cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] &&
+ cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3]
+ )
+ {
+ *distances++ = 4;
+ *distances++ = lzPos - curMatch4 - 1;
+ }
+ return distances;
+}
+*/
+
+#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;
+
+UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances)
+{
+ const UInt32 *btBuf = p->btBuf + p->btBufPos;
+ UInt32 len = *btBuf++;
+ p->btBufPos += 1 + len;
+ p->btNumAvailBytes--;
+ {
+ UInt32 i;
+ for (i = 0; i < len; i += 2)
+ {
+ *distances++ = *btBuf++;
+ *distances++ = *btBuf++;
+ }
+ }
+ INCREASE_LZ_POS
+ return len;
+}
+
+UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
+{
+ const UInt32 *btBuf = p->btBuf + p->btBufPos;
+ UInt32 len = *btBuf++;
+ p->btBufPos += 1 + len;
+
+ if (len == 0)
+ {
+ if (p->btNumAvailBytes-- >= 4)
+ len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances));
+ }
+ else
+ {
+ /* Condition: there are matches in btBuf with length < p->numHashBytes */
+ UInt32 *distances2;
+ p->btNumAvailBytes--;
+ distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances);
+ do
+ {
+ *distances2++ = *btBuf++;
+ *distances2++ = *btBuf++;
+ }
+ while ((len -= 2) != 0);
+ len = (UInt32)(distances2 - (distances));
+ }
+ INCREASE_LZ_POS
+ return len;
+}
+
+#define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED
+#define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash;
+#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0);
+
+void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER2_MT { p->btNumAvailBytes--;
+ SKIP_FOOTER_MT
+}
+
+void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(2)
+ UInt32 hash2Value;
+ MT_HASH2_CALC
+ hash[hash2Value] = p->lzPos;
+ SKIP_FOOTER_MT
+}
+
+void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(3)
+ UInt32 hash2Value, hash3Value;
+ MT_HASH3_CALC
+ hash[kFix3HashSize + hash3Value] =
+ hash[ hash2Value] =
+ p->lzPos;
+ SKIP_FOOTER_MT
+}
+
+/*
+void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(4)
+ UInt32 hash2Value, hash3Value, hash4Value;
+ MT_HASH4_CALC
+ hash[kFix4HashSize + hash4Value] =
+ hash[kFix3HashSize + hash3Value] =
+ hash[ hash2Value] =
+ p->lzPos;
+ SKIP_FOOTER_MT
+}
+*/
+
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable)
+{
+ vTable->Init = (Mf_Init_Func)MatchFinderMt_Init;
+ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte;
+ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes;
+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos;
+ vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches;
+ switch(p->MatchFinder->numHashBytes)
+ {
+ case 2:
+ p->GetHeadsFunc = GetHeads2;
+ p->MixMatchesFunc = (Mf_Mix_Matches)0;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip;
+ vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches;
+ break;
+ case 3:
+ p->GetHeadsFunc = GetHeads3;
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip;
+ break;
+ default:
+ /* case 4: */
+ p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4;
+ /* p->GetHeadsFunc = GetHeads4; */
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip;
+ break;
+ /*
+ default:
+ p->GetHeadsFunc = GetHeads5;
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip;
+ break;
+ */
+ }
+}
diff --git a/dep/StormLib/src/lzma/C/LzFindMt.h b/dep/StormLib/src/lzma/C/LzFindMt.h
new file mode 100644
index 00000000000..b985af5fee2
--- /dev/null
+++ b/dep/StormLib/src/lzma/C/LzFindMt.h
@@ -0,0 +1,105 @@
+/* LzFindMt.h -- multithreaded Match finder for LZ algorithms
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_FIND_MT_H
+#define __LZ_FIND_MT_H
+
+#include "LzFind.h"
+#include "Threads.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define kMtHashBlockSize (1 << 13)
+#define kMtHashNumBlocks (1 << 3)
+#define kMtHashNumBlocksMask (kMtHashNumBlocks - 1)
+
+#define kMtBtBlockSize (1 << 14)
+#define kMtBtNumBlocks (1 << 6)
+#define kMtBtNumBlocksMask (kMtBtNumBlocks - 1)
+
+typedef struct _CMtSync
+{
+ Bool wasCreated;
+ Bool needStart;
+ Bool exit;
+ Bool stopWriting;
+
+ CThread thread;
+ CAutoResetEvent canStart;
+ CAutoResetEvent wasStarted;
+ CAutoResetEvent wasStopped;
+ CSemaphore freeSemaphore;
+ CSemaphore filledSemaphore;
+ Bool csWasInitialized;
+ Bool csWasEntered;
+ CCriticalSection cs;
+ UInt32 numProcessedBlocks;
+} CMtSync;
+
+typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances);
+
+/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */
+#define kMtCacheLineDummy 128
+
+typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos,
+ UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc);
+
+typedef struct _CMatchFinderMt
+{
+ /* LZ */
+ const Byte *pointerToCurPos;
+ UInt32 *btBuf;
+ UInt32 btBufPos;
+ UInt32 btBufPosLimit;
+ UInt32 lzPos;
+ UInt32 btNumAvailBytes;
+
+ UInt32 *hash;
+ UInt32 fixedHashSize;
+ UInt32 historySize;
+ const UInt32 *crc;
+
+ Mf_Mix_Matches MixMatchesFunc;
+
+ /* LZ + BT */
+ CMtSync btSync;
+ Byte btDummy[kMtCacheLineDummy];
+
+ /* BT */
+ UInt32 *hashBuf;
+ UInt32 hashBufPos;
+ UInt32 hashBufPosLimit;
+ UInt32 hashNumAvail;
+
+ CLzRef *son;
+ UInt32 matchMaxLen;
+ UInt32 numHashBytes;
+ UInt32 pos;
+ Byte *buffer;
+ UInt32 cyclicBufferPos;
+ UInt32 cyclicBufferSize; /* it must be historySize + 1 */
+ UInt32 cutValue;
+
+ /* BT + Hash */
+ CMtSync hashSync;
+ /* Byte hashDummy[kMtCacheLineDummy]; */
+
+ /* Hash */
+ Mf_GetHeads GetHeadsFunc;
+ CMatchFinder *MatchFinder;
+} CMatchFinderMt;
+
+void MatchFinderMt_Construct(CMatchFinderMt *p);
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc);
+SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc);
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable);
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dep/StormLib/src/lzma/C/LzHash.h b/dep/StormLib/src/lzma/C/LzHash.h
new file mode 100644
index 00000000000..f3e89966cc7
--- /dev/null
+++ b/dep/StormLib/src/lzma/C/LzHash.h
@@ -0,0 +1,54 @@
+/* LzHash.h -- HASH functions for LZ algorithms
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_HASH_H
+#define __LZ_HASH_H
+
+#define kHash2Size (1 << 10)
+#define kHash3Size (1 << 16)
+#define kHash4Size (1 << 20)
+
+#define kFix3HashSize (kHash2Size)
+#define kFix4HashSize (kHash2Size + kHash3Size)
+#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
+
+#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
+
+#define HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
+
+#define HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
+
+#define HASH5_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
+ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
+ hash4Value &= (kHash4Size - 1); }
+
+/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
+#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
+
+
+#define MT_HASH2_CALC \
+ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
+
+#define MT_HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+
+#define MT_HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
+
+#endif
diff --git a/dep/StormLib/src/lzma/C/LzmaDec.c b/dep/StormLib/src/lzma/C/LzmaDec.c
new file mode 100644
index 00000000000..2036761bf14
--- /dev/null
+++ b/dep/StormLib/src/lzma/C/LzmaDec.c
@@ -0,0 +1,999 @@
+/* LzmaDec.c -- LZMA Decoder
+2009-09-20 : Igor Pavlov : Public domain */
+
+#include "LzmaDec.h"
+
+#include <string.h>
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_INIT_SIZE 5
+
+#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
+#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
+ { UPDATE_0(p); i = (i + i); A0; } else \
+ { UPDATE_1(p); i = (i + i) + 1; A1; }
+#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
+
+#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
+#define TREE_DECODE(probs, limit, i) \
+ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
+
+/* #define _LZMA_SIZE_OPT */
+
+#ifdef _LZMA_SIZE_OPT
+#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
+#else
+#define TREE_6_DECODE(probs, i) \
+ { i = 1; \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ i -= 0x40; }
+#endif
+
+#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0_CHECK range = bound;
+#define UPDATE_1_CHECK range -= bound; code -= bound;
+#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
+ { UPDATE_0_CHECK; i = (i + i); A0; } else \
+ { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
+#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
+#define TREE_DECODE_CHECK(probs, limit, i) \
+ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+#define LZMA_DIC_MIN (1 << 12)
+
+/* First LZMA-symbol is always decoded.
+And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization
+Out:
+ Result:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Error
+ p->remainLen:
+ < kMatchSpecLenStart : normal remain
+ = kMatchSpecLenStart : finished
+ = kMatchSpecLenStart + 1 : Flush marker
+ = kMatchSpecLenStart + 2 : State Init Marker
+*/
+
+static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ CLzmaProb *probs = p->probs;
+
+ unsigned state = p->state;
+ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
+ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
+ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
+ unsigned lc = p->prop.lc;
+
+ Byte *dic = p->dic;
+ SizeT dicBufSize = p->dicBufSize;
+ SizeT dicPos = p->dicPos;
+
+ UInt32 processedPos = p->processedPos;
+ UInt32 checkDicSize = p->checkDicSize;
+ unsigned len = 0;
+
+ const Byte *buf = p->buf;
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+
+ do
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = processedPos & pbMask;
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ unsigned symbol;
+ UPDATE_0(prob);
+ prob = probs + Literal;
+ if (checkDicSize != 0 || processedPos != 0)
+ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
+ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
+
+ if (state < kNumLitStates)
+ {
+ state -= (state < 4) ? state : 3;
+ symbol = 1;
+ do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ unsigned offs = 0x100;
+ state -= (state < 10) ? 3 : 6;
+ symbol = 1;
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & offs);
+ probLit = prob + offs + bit + symbol;
+ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
+ }
+ while (symbol < 0x100);
+ }
+ dic[dicPos++] = (Byte)symbol;
+ processedPos++;
+ continue;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRep + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ state += kNumStates;
+ prob = probs + LenCoder;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ if (checkDicSize == 0 && processedPos == 0)
+ return SZ_ERROR_DATA;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dicPos++;
+ processedPos++;
+ state = state < kNumLitStates ? 9 : 11;
+ continue;
+ }
+ UPDATE_1(prob);
+ }
+ else
+ {
+ UInt32 distance;
+ UPDATE_1(prob);
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit = (1 << kLenNumLowBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit = (1 << kLenNumMidBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit = (1 << kLenNumHighBits);
+ }
+ }
+ TREE_DECODE(probLen, limit, len);
+ len += offset;
+ }
+
+ if (state >= kNumStates)
+ {
+ UInt32 distance;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
+ TREE_6_DECODE(prob, distance);
+ if (distance >= kStartPosModelIndex)
+ {
+ unsigned posSlot = (unsigned)distance;
+ int numDirectBits = (int)(((distance >> 1) - 1));
+ distance = (2 | (distance & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ distance <<= numDirectBits;
+ prob = probs + SpecPos + distance - posSlot - 1;
+ {
+ UInt32 mask = 1;
+ unsigned i = 1;
+ do
+ {
+ GET_BIT2(prob + i, i, ; , distance |= mask);
+ mask <<= 1;
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE
+ range >>= 1;
+
+ {
+ UInt32 t;
+ code -= range;
+ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
+ distance = (distance << 1) + (t + 1);
+ code += range & t;
+ }
+ /*
+ distance <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ distance |= 1;
+ }
+ */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ distance <<= kNumAlignBits;
+ {
+ unsigned i = 1;
+ GET_BIT2(prob + i, i, ; , distance |= 1);
+ GET_BIT2(prob + i, i, ; , distance |= 2);
+ GET_BIT2(prob + i, i, ; , distance |= 4);
+ GET_BIT2(prob + i, i, ; , distance |= 8);
+ }
+ if (distance == (UInt32)0xFFFFFFFF)
+ {
+ len += kMatchSpecLenStart;
+ state -= kNumStates;
+ break;
+ }
+ }
+ }
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance + 1;
+ if (checkDicSize == 0)
+ {
+ if (distance >= processedPos)
+ return SZ_ERROR_DATA;
+ }
+ else if (distance >= checkDicSize)
+ return SZ_ERROR_DATA;
+ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+ }
+
+ len += kMatchMinLen;
+
+ if (limit == dicPos)
+ return SZ_ERROR_DATA;
+ {
+ SizeT rem = limit - dicPos;
+ unsigned curLen = ((rem < len) ? (unsigned)rem : len);
+ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
+
+ processedPos += curLen;
+
+ len -= curLen;
+ if (pos + curLen <= dicBufSize)
+ {
+ Byte *dest = dic + dicPos;
+ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
+ const Byte *lim = dest + curLen;
+ dicPos += curLen;
+ do
+ *(dest) = (Byte)*(dest + src);
+ while (++dest != lim);
+ }
+ else
+ {
+ do
+ {
+ dic[dicPos++] = dic[pos];
+ if (++pos == dicBufSize)
+ pos = 0;
+ }
+ while (--curLen != 0);
+ }
+ }
+ }
+ }
+ while (dicPos < limit && buf < bufLimit);
+ NORMALIZE;
+ p->buf = buf;
+ p->range = range;
+ p->code = code;
+ p->remainLen = len;
+ p->dicPos = dicPos;
+ p->processedPos = processedPos;
+ p->reps[0] = rep0;
+ p->reps[1] = rep1;
+ p->reps[2] = rep2;
+ p->reps[3] = rep3;
+ p->state = state;
+
+ return SZ_OK;
+}
+
+static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
+{
+ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
+ {
+ Byte *dic = p->dic;
+ SizeT dicPos = p->dicPos;
+ SizeT dicBufSize = p->dicBufSize;
+ unsigned len = p->remainLen;
+ UInt32 rep0 = p->reps[0];
+ if (limit - dicPos < len)
+ len = (unsigned)(limit - dicPos);
+
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
+ p->checkDicSize = p->prop.dicSize;
+
+ p->processedPos += len;
+ p->remainLen -= len;
+ while (len-- != 0)
+ {
+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dicPos++;
+ }
+ p->dicPos = dicPos;
+ }
+}
+
+static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ do
+ {
+ SizeT limit2 = limit;
+ if (p->checkDicSize == 0)
+ {
+ UInt32 rem = p->prop.dicSize - p->processedPos;
+ if (limit - p->dicPos > rem)
+ limit2 = p->dicPos + rem;
+ }
+ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
+ if (p->processedPos >= p->prop.dicSize)
+ p->checkDicSize = p->prop.dicSize;
+ LzmaDec_WriteRem(p, limit);
+ }
+ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
+
+ if (p->remainLen > kMatchSpecLenStart)
+ {
+ p->remainLen = kMatchSpecLenStart;
+ }
+ return 0;
+}
+
+typedef enum
+{
+ DUMMY_ERROR, /* unexpected end of input stream */
+ DUMMY_LIT,
+ DUMMY_MATCH,
+ DUMMY_REP
+} ELzmaDummy;
+
+static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
+{
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+ const Byte *bufLimit = buf + inSize;
+ CLzmaProb *probs = p->probs;
+ unsigned state = p->state;
+ ELzmaDummy res;
+
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK
+
+ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
+
+ prob = probs + Literal;
+ if (p->checkDicSize != 0 || p->processedPos != 0)
+ prob += (LZMA_LIT_SIZE *
+ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
+ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
+
+ if (state < kNumLitStates)
+ {
+ unsigned symbol = 1;
+ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
+ ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
+ unsigned offs = 0x100;
+ unsigned symbol = 1;
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & offs);
+ probLit = prob + offs + bit + symbol;
+ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
+ }
+ while (symbol < 0x100);
+ }
+ res = DUMMY_LIT;
+ }
+ else
+ {
+ unsigned len;
+ UPDATE_1_CHECK;
+
+ prob = probs + IsRep + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ state = 0;
+ prob = probs + LenCoder;
+ res = DUMMY_MATCH;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ res = DUMMY_REP;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ NORMALIZE_CHECK;
+ return DUMMY_REP;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ }
+ state = kNumStates;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit = 1 << kLenNumLowBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenChoice2;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit = 1 << kLenNumMidBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit = 1 << kLenNumHighBits;
+ }
+ }
+ TREE_DECODE_CHECK(probLen, limit, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ unsigned posSlot;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+
+ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
+
+ if (posSlot < kEndPosModelIndex)
+ {
+ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE_CHECK
+ range >>= 1;
+ code -= range & (((code - range) >> 31) - 1);
+ /* if (code >= range) code -= range; */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ unsigned i = 1;
+ do
+ {
+ GET_BIT_CHECK(prob + i, i);
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ }
+ }
+ }
+ NORMALIZE_CHECK;
+ return res;
+}
+
+
+static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
+{
+ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
+ p->range = 0xFFFFFFFF;
+ p->needFlush = 0;
+}
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
+{
+ p->needFlush = 1;
+ p->remainLen = 0;
+ p->tempBufSize = 0;
+
+ if (initDic)
+ {
+ p->processedPos = 0;
+ p->checkDicSize = 0;
+ p->needInitState = 1;
+ }
+ if (initState)
+ p->needInitState = 1;
+}
+
+void LzmaDec_Init(CLzmaDec *p)
+{
+ p->dicPos = 0;
+ LzmaDec_InitDicAndState(p, True, True);
+}
+
+static void LzmaDec_InitStateReal(CLzmaDec *p)
+{
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
+ UInt32 i;
+ CLzmaProb *probs = p->probs;
+ for (i = 0; i < numProbs; i++)
+ probs[i] = kBitModelTotal >> 1;
+ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
+ p->state = 0;
+ p->needInitState = 0;
+}
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+ ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ (*srcLen) = 0;
+ LzmaDec_WriteRem(p, dicLimit);
+
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ while (p->remainLen != kMatchSpecLenStart)
+ {
+ int checkEndMarkNow;
+
+ if (p->needFlush != 0)
+ {
+ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
+ p->tempBuf[p->tempBufSize++] = *src++;
+ if (p->tempBufSize < RC_INIT_SIZE)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (p->tempBuf[0] != 0)
+ return SZ_ERROR_DATA;
+
+ LzmaDec_InitRc(p, p->tempBuf);
+ p->tempBufSize = 0;
+ }
+
+ checkEndMarkNow = 0;
+ if (p->dicPos >= dicLimit)
+ {
+ if (p->remainLen == 0 && p->code == 0)
+ {
+ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
+ return SZ_OK;
+ }
+ if (finishMode == LZMA_FINISH_ANY)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+ if (p->remainLen != 0)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ checkEndMarkNow = 1;
+ }
+
+ if (p->needInitState)
+ LzmaDec_InitStateReal(p);
+
+ if (p->tempBufSize == 0)
+ {
+ SizeT processed;
+ const Byte *bufLimit;
+ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ int dummyRes = LzmaDec_TryDummy(p, src, inSize);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ memcpy(p->tempBuf, src, inSize);
+ p->tempBufSize = (unsigned)inSize;
+ (*srcLen) += inSize;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ bufLimit = src;
+ }
+ else
+ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
+ p->buf = src;
+ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
+ return SZ_ERROR_DATA;
+ processed = (SizeT)(p->buf - src);
+ (*srcLen) += processed;
+ src += processed;
+ inSize -= processed;
+ }
+ else
+ {
+ unsigned rem = p->tempBufSize, lookAhead = 0;
+ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
+ p->tempBuf[rem++] = src[lookAhead++];
+ p->tempBufSize = rem;
+ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ (*srcLen) += lookAhead;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ }
+ p->buf = p->tempBuf;
+ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
+ return SZ_ERROR_DATA;
+ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
+ (*srcLen) += lookAhead;
+ src += lookAhead;
+ inSize -= lookAhead;
+ p->tempBufSize = 0;
+ }
+ }
+ if (p->code == 0)
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
+}
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT outSize = *destLen;
+ SizeT inSize = *srcLen;
+ *srcLen = *destLen = 0;
+ for (;;)
+ {
+ SizeT inSizeCur = inSize, outSizeCur, dicPos;
+ ELzmaFinishMode curFinishMode;
+ SRes res;
+ if (p->dicPos == p->dicBufSize)
+ p->dicPos = 0;
+ dicPos = p->dicPos;
+ if (outSize > p->dicBufSize - dicPos)
+ {
+ outSizeCur = p->dicBufSize;
+ curFinishMode = LZMA_FINISH_ANY;
+ }
+ else
+ {
+ outSizeCur = dicPos + outSize;
+ curFinishMode = finishMode;
+ }
+
+ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
+ src += inSizeCur;
+ inSize -= inSizeCur;
+ *srcLen += inSizeCur;
+ outSizeCur = p->dicPos - dicPos;
+ memcpy(dest, p->dic + dicPos, outSizeCur);
+ dest += outSizeCur;
+ outSize -= outSizeCur;
+ *destLen += outSizeCur;
+ if (res != 0)
+ return res;
+ if (outSizeCur == 0 || outSize == 0)
+ return SZ_OK;
+ }
+}
+
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->probs);
+ p->probs = 0;
+}
+
+static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->dic);
+ p->dic = 0;
+}
+
+void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
+{
+ LzmaDec_FreeProbs(p, alloc);
+ LzmaDec_FreeDict(p, alloc);
+}
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
+{
+ UInt32 dicSize;
+ Byte d;
+
+ if (size < LZMA_PROPS_SIZE)
+ return SZ_ERROR_UNSUPPORTED;
+ else
+ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
+
+ if (dicSize < LZMA_DIC_MIN)
+ dicSize = LZMA_DIC_MIN;
+ p->dicSize = dicSize;
+
+ d = data[0];
+ if (d >= (9 * 5 * 5))
+ return SZ_ERROR_UNSUPPORTED;
+
+ p->lc = d % 9;
+ d /= 9;
+ p->pb = d / 5;
+ p->lp = d % 5;
+
+ return SZ_OK;
+}
+
+static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
+{
+ UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
+ if (p->probs == 0 || numProbs != p->numProbs)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
+ p->numProbs = numProbs;
+ if (p->probs == 0)
+ return SZ_ERROR_MEM;
+ }
+ return SZ_OK;
+}
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ SizeT dicBufSize;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ dicBufSize = propNew.dicSize;
+ if (p->dic == 0 || dicBufSize != p->dicBufSize)
+ {
+ LzmaDec_FreeDict(p, alloc);
+ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
+ if (p->dic == 0)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ }
+ p->dicBufSize = dicBufSize;
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc)
+{
+ CLzmaDec p;
+ SRes res;
+ SizeT inSize = *srcLen;
+ SizeT outSize = *destLen;
+ *srcLen = *destLen = 0;
+ if (inSize < RC_INIT_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+
+ LzmaDec_Construct(&p);
+ res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc);
+ if (res != 0)
+ return res;
+ p.dic = dest;
+ p.dicBufSize = outSize;
+
+ LzmaDec_Init(&p);
+
+ *srcLen = inSize;
+ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
+
+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ res = SZ_ERROR_INPUT_EOF;
+
+ (*destLen) = p.dicPos;
+ LzmaDec_FreeProbs(&p, alloc);
+ return res;
+}
diff --git a/dep/StormLib/src/lzma/C/LzmaDec.h b/dep/StormLib/src/lzma/C/LzmaDec.h
new file mode 100644
index 00000000000..bf7f084ba3d
--- /dev/null
+++ b/dep/StormLib/src/lzma/C/LzmaDec.h
@@ -0,0 +1,231 @@
+/* LzmaDec.h -- LZMA Decoder
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_DEC_H
+#define __LZMA_DEC_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* #define _LZMA_PROB32 */
+/* _LZMA_PROB32 can increase the speed on some CPUs,
+ but memory usage for CLzmaDec::probs will be doubled in that case */
+
+#ifdef _LZMA_PROB32
+#define CLzmaProb UInt32
+#else
+#define CLzmaProb UInt16
+#endif
+
+
+/* ---------- LZMA Properties ---------- */
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaProps
+{
+ unsigned lc, lp, pb;
+ UInt32 dicSize;
+} CLzmaProps;
+
+/* LzmaProps_Decode - decodes properties
+Returns:
+ SZ_OK
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
+
+
+/* ---------- LZMA Decoder state ---------- */
+
+/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
+ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
+
+#define LZMA_REQUIRED_INPUT_MAX 20
+
+typedef struct
+{
+ CLzmaProps prop;
+ CLzmaProb *probs;
+ Byte *dic;
+ const Byte *buf;
+ UInt32 range, code;
+ SizeT dicPos;
+ SizeT dicBufSize;
+ UInt32 processedPos;
+ UInt32 checkDicSize;
+ unsigned state;
+ UInt32 reps[4];
+ unsigned remainLen;
+ int needFlush;
+ int needInitState;
+ UInt32 numProbs;
+ unsigned tempBufSize;
+ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
+} CLzmaDec;
+
+#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
+
+void LzmaDec_Init(CLzmaDec *p);
+
+/* There are two types of LZMA streams:
+ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
+ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
+
+typedef enum
+{
+ LZMA_FINISH_ANY, /* finish at any point */
+ LZMA_FINISH_END /* block must be finished at the end */
+} ELzmaFinishMode;
+
+/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
+
+ You must use LZMA_FINISH_END, when you know that current output buffer
+ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
+
+ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
+ and output value of destLen will be less than output buffer size limit.
+ You can check status result also.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+typedef enum
+{
+ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
+ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
+ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
+ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
+} ELzmaStatus;
+
+/* ELzmaStatus is used only as output value for function call */
+
+
+/* ---------- Interfaces ---------- */
+
+/* There are 3 levels of interfaces:
+ 1) Dictionary Interface
+ 2) Buffer Interface
+ 3) One Call Interface
+ You can select any of these interfaces, but don't mix functions from different
+ groups for same object. */
+
+
+/* There are two variants to allocate state for Dictionary Interface:
+ 1) LzmaDec_Allocate / LzmaDec_Free
+ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
+ You can use variant 2, if you set dictionary buffer manually.
+ For Buffer Interface you must always use variant 1.
+
+LzmaDec_Allocate* can return:
+ SZ_OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
+
+SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
+
+/* ---------- Dictionary Interface ---------- */
+
+/* You can use it, if you want to eliminate the overhead for data copying from
+ dictionary to some other external buffer.
+ You must work with CLzmaDec variables directly in this interface.
+
+ STEPS:
+ LzmaDec_Constr()
+ LzmaDec_Allocate()
+ for (each new stream)
+ {
+ LzmaDec_Init()
+ while (it needs more decompression)
+ {
+ LzmaDec_DecodeToDic()
+ use data from CLzmaDec::dic and update CLzmaDec::dicPos
+ }
+ }
+ LzmaDec_Free()
+*/
+
+/* LzmaDec_DecodeToDic
+
+ The decoding to internal dictionary buffer (CLzmaDec::dic).
+ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (dicLimit).
+ LZMA_FINISH_ANY - Decode just dicLimit bytes.
+ LZMA_FINISH_END - Stream must be finished after dicLimit.
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_NEEDS_MORE_INPUT
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+*/
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- Buffer Interface ---------- */
+
+/* It's zlib-like interface.
+ See LzmaDec_DecodeToDic description for information about STEPS and return results,
+ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
+ to work with CLzmaDec variables manually.
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+*/
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- One Call Interface ---------- */
+
+/* LzmaDecode
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+*/
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dep/StormLib/src/lzma/C/LzmaEnc.c b/dep/StormLib/src/lzma/C/LzmaEnc.c
new file mode 100644
index 00000000000..169d4f4639e
--- /dev/null
+++ b/dep/StormLib/src/lzma/C/LzmaEnc.c
@@ -0,0 +1,2268 @@
+/* LzmaEnc.c -- LZMA Encoder
+2009-11-24 : Igor Pavlov : Public domain */
+
+#include <string.h>
+
+/* #define SHOW_STAT */
+/* #define SHOW_STAT2 */
+
+#if defined(SHOW_STAT) || defined(SHOW_STAT2)
+#include <stdio.h>
+#endif
+
+#include "LzmaEnc.h"
+
+#include "LzFind.h"
+#ifndef _7ZIP_ST
+#include "LzFindMt.h"
+#endif
+
+#ifdef SHOW_STAT
+static int ttt = 0;
+#endif
+
+#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1)
+
+#define kBlockSize (9 << 10)
+#define kUnpackBlockSize (1 << 18)
+#define kMatchArraySize (1 << 21)
+#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX)
+
+#define kNumMaxDirectBits (31)
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+#define kProbInitValue (kBitModelTotal >> 1)
+
+#define kNumMoveReducingBits 4
+#define kNumBitPriceShiftBits 4
+#define kBitPrice (1 << kNumBitPriceShiftBits)
+
+void LzmaEncProps_Init(CLzmaEncProps *p)
+{
+ p->level = 5;
+ p->dictSize = p->mc = 0;
+ p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
+ p->writeEndMark = 0;
+}
+
+void LzmaEncProps_Normalize(CLzmaEncProps *p)
+{
+ int level = p->level;
+ if (level < 0) level = 5;
+ p->level = level;
+ if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26)));
+ if (p->lc < 0) p->lc = 3;
+ if (p->lp < 0) p->lp = 0;
+ if (p->pb < 0) p->pb = 2;
+ if (p->algo < 0) p->algo = (level < 5 ? 0 : 1);
+ if (p->fb < 0) p->fb = (level < 7 ? 32 : 64);
+ if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1);
+ if (p->numHashBytes < 0) p->numHashBytes = 4;
+ if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
+ if (p->numThreads < 0)
+ p->numThreads =
+ #ifndef _7ZIP_ST
+ ((p->btMode && p->algo) ? 2 : 1);
+ #else
+ 1;
+ #endif
+}
+
+UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
+{
+ CLzmaEncProps props = *props2;
+ LzmaEncProps_Normalize(&props);
+ return props.dictSize;
+}
+
+/* #define LZMA_LOG_BSR */
+/* Define it for Intel's CPU */
+
+
+#ifdef LZMA_LOG_BSR
+
+#define kDicLogSizeMaxCompress 30
+
+#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
+
+UInt32 GetPosSlot1(UInt32 pos)
+{
+ UInt32 res;
+ BSR2_RET(pos, res);
+ return res;
+}
+#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
+#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
+
+#else
+
+#define kNumLogBits (9 + (int)sizeof(size_t) / 2)
+#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
+
+void LzmaEnc_FastPosInit(Byte *g_FastPos)
+{
+ int c = 2, slotFast;
+ g_FastPos[0] = 0;
+ g_FastPos[1] = 1;
+
+ for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++)
+ {
+ UInt32 k = (1 << ((slotFast >> 1) - 1));
+ UInt32 j;
+ for (j = 0; j < k; j++, c++)
+ g_FastPos[c] = (Byte)slotFast;
+ }
+}
+
+#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \
+ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
+ res = p->g_FastPos[pos >> i] + (i * 2); }
+/*
+#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
+ p->g_FastPos[pos >> 6] + 12 : \
+ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
+*/
+
+#define GetPosSlot1(pos) p->g_FastPos[pos]
+#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
+#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); }
+
+#endif
+
+
+#define LZMA_NUM_REPS 4
+
+typedef unsigned CState;
+
+typedef struct
+{
+ UInt32 price;
+
+ CState state;
+ int prev1IsChar;
+ int prev2;
+
+ UInt32 posPrev2;
+ UInt32 backPrev2;
+
+ UInt32 posPrev;
+ UInt32 backPrev;
+ UInt32 backs[LZMA_NUM_REPS];
+} COptimal;
+
+#define kNumOpts (1 << 12)
+
+#define kNumLenToPosStates 4
+#define kNumPosSlotBits 6
+#define kDicLogSizeMin 0
+#define kDicLogSizeMax 32
+#define kDistTableSizeMax (kDicLogSizeMax * 2)
+
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+#define kAlignMask (kAlignTableSize - 1)
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex)
+
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#ifdef _LZMA_PROB32
+#define CLzmaProb UInt32
+#else
+#define CLzmaProb UInt16
+#endif
+
+#define LZMA_PB_MAX 4
+#define LZMA_LC_MAX 8
+#define LZMA_LP_MAX 4
+
+#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
+
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
+
+#define LZMA_MATCH_LEN_MIN 2
+#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
+
+#define kNumStates 12
+
+typedef struct
+{
+ CLzmaProb choice;
+ CLzmaProb choice2;
+ CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits];
+ CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits];
+ CLzmaProb high[kLenNumHighSymbols];
+} CLenEnc;
+
+typedef struct
+{
+ CLenEnc p;
+ UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
+ UInt32 tableSize;
+ UInt32 counters[LZMA_NUM_PB_STATES_MAX];
+} CLenPriceEnc;
+
+typedef struct
+{
+ UInt32 range;
+ Byte cache;
+ UInt64 low;
+ UInt64 cacheSize;
+ Byte *buf;
+ Byte *bufLim;
+ Byte *bufBase;
+ ISeqOutStream *outStream;
+ UInt64 processed;
+ SRes res;
+} CRangeEnc;
+
+typedef struct
+{
+ CLzmaProb *litProbs;
+
+ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
+ CLzmaProb isRep[kNumStates];
+ CLzmaProb isRepG0[kNumStates];
+ CLzmaProb isRepG1[kNumStates];
+ CLzmaProb isRepG2[kNumStates];
+ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
+
+ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
+ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
+ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
+
+ CLenPriceEnc lenEnc;
+ CLenPriceEnc repLenEnc;
+
+ UInt32 reps[LZMA_NUM_REPS];
+ UInt32 state;
+} CSaveState;
+
+typedef struct
+{
+ IMatchFinder matchFinder;
+ void *matchFinderObj;
+
+ #ifndef _7ZIP_ST
+ Bool mtMode;
+ CMatchFinderMt matchFinderMt;
+ #endif
+
+ CMatchFinder matchFinderBase;
+
+ #ifndef _7ZIP_ST
+ Byte pad[128];
+ #endif
+
+ UInt32 optimumEndIndex;
+ UInt32 optimumCurrentIndex;
+
+ UInt32 longestMatchLength;
+ UInt32 numPairs;
+ UInt32 numAvail;
+ COptimal opt[kNumOpts];
+
+ #ifndef LZMA_LOG_BSR
+ Byte g_FastPos[1 << kNumLogBits];
+ #endif
+
+ UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
+ UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
+ UInt32 numFastBytes;
+ UInt32 additionalOffset;
+ UInt32 reps[LZMA_NUM_REPS];
+ UInt32 state;
+
+ UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
+ UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
+ UInt32 alignPrices[kAlignTableSize];
+ UInt32 alignPriceCount;
+
+ UInt32 distTableSize;
+
+ unsigned lc, lp, pb;
+ unsigned lpMask, pbMask;
+
+ CLzmaProb *litProbs;
+
+ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
+ CLzmaProb isRep[kNumStates];
+ CLzmaProb isRepG0[kNumStates];
+ CLzmaProb isRepG1[kNumStates];
+ CLzmaProb isRepG2[kNumStates];
+ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
+
+ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
+ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
+ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
+
+ CLenPriceEnc lenEnc;
+ CLenPriceEnc repLenEnc;
+
+ unsigned lclp;
+
+ Bool fastMode;
+
+ CRangeEnc rc;
+
+ Bool writeEndMark;
+ UInt64 nowPos64;
+ UInt32 matchPriceCount;
+ Bool finished;
+ Bool multiThread;
+
+ SRes result;
+ UInt32 dictSize;
+ UInt32 matchFinderCycles;
+
+ int needInit;
+
+ CSaveState saveState;
+} CLzmaEnc;
+
+void LzmaEnc_SaveState(CLzmaEncHandle pp)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ CSaveState *dest = &p->saveState;
+ int i;
+ dest->lenEnc = p->lenEnc;
+ dest->repLenEnc = p->repLenEnc;
+ dest->state = p->state;
+
+ for (i = 0; i < kNumStates; i++)
+ {
+ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+ }
+ for (i = 0; i < kNumLenToPosStates; i++)
+ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+ memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+ memcpy(dest->reps, p->reps, sizeof(p->reps));
+ memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
+}
+
+void LzmaEnc_RestoreState(CLzmaEncHandle pp)
+{
+ CLzmaEnc *dest = (CLzmaEnc *)pp;
+ const CSaveState *p = &dest->saveState;
+ int i;
+ dest->lenEnc = p->lenEnc;
+ dest->repLenEnc = p->repLenEnc;
+ dest->state = p->state;
+
+ for (i = 0; i < kNumStates; i++)
+ {
+ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+ }
+ for (i = 0; i < kNumLenToPosStates; i++)
+ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+ memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+ memcpy(dest->reps, p->reps, sizeof(p->reps));
+ memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
+}
+
+SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ CLzmaEncProps props = *props2;
+ LzmaEncProps_Normalize(&props);
+
+ if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX ||
+ props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30))
+ return SZ_ERROR_PARAM;
+ p->dictSize = props.dictSize;
+ p->matchFinderCycles = props.mc;
+ {
+ unsigned fb = props.fb;
+ if (fb < 5)
+ fb = 5;
+ if (fb > LZMA_MATCH_LEN_MAX)
+ fb = LZMA_MATCH_LEN_MAX;
+ p->numFastBytes = fb;
+ }
+ p->lc = props.lc;
+ p->lp = props.lp;
+ p->pb = props.pb;
+ p->fastMode = (props.algo == 0);
+ p->matchFinderBase.btMode = props.btMode;
+ {
+ UInt32 numHashBytes = 4;
+ if (props.btMode)
+ {
+ if (props.numHashBytes < 2)
+ numHashBytes = 2;
+ else if (props.numHashBytes < 4)
+ numHashBytes = props.numHashBytes;
+ }
+ p->matchFinderBase.numHashBytes = numHashBytes;
+ }
+
+ p->matchFinderBase.cutValue = props.mc;
+
+ p->writeEndMark = props.writeEndMark;
+
+ #ifndef _7ZIP_ST
+ /*
+ if (newMultiThread != _multiThread)
+ {
+ ReleaseMatchFinder();
+ _multiThread = newMultiThread;
+ }
+ */
+ p->multiThread = (props.numThreads > 1);
+ #endif
+
+ return SZ_OK;
+}
+
+static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
+static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
+static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
+static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
+
+#define IsCharState(s) ((s) < 7)
+
+#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
+
+#define kInfinityPrice (1 << 30)
+
+static void RangeEnc_Construct(CRangeEnc *p)
+{
+ p->outStream = 0;
+ p->bufBase = 0;
+}
+
+#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
+
+#define RC_BUF_SIZE (1 << 16)
+static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc)
+{
+ if (p->bufBase == 0)
+ {
+ p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE);
+ if (p->bufBase == 0)
+ return 0;
+ p->bufLim = p->bufBase + RC_BUF_SIZE;
+ }
+ return 1;
+}
+
+static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->bufBase);
+ p->bufBase = 0;
+}
+
+static void RangeEnc_Init(CRangeEnc *p)
+{
+ /* Stream.Init(); */
+ p->low = 0;
+ p->range = 0xFFFFFFFF;
+ p->cacheSize = 1;
+ p->cache = 0;
+
+ p->buf = p->bufBase;
+
+ p->processed = 0;
+ p->res = SZ_OK;
+}
+
+static void RangeEnc_FlushStream(CRangeEnc *p)
+{
+ size_t num;
+ if (p->res != SZ_OK)
+ return;
+ num = p->buf - p->bufBase;
+ if (num != p->outStream->Write(p->outStream, p->bufBase, num))
+ p->res = SZ_ERROR_WRITE;
+ p->processed += num;
+ p->buf = p->bufBase;
+}
+
+static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
+{
+ if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0)
+ {
+ Byte temp = p->cache;
+ do
+ {
+ Byte *buf = p->buf;
+ *buf++ = (Byte)(temp + (Byte)(p->low >> 32));
+ p->buf = buf;
+ if (buf == p->bufLim)
+ RangeEnc_FlushStream(p);
+ temp = 0xFF;
+ }
+ while (--p->cacheSize != 0);
+ p->cache = (Byte)((UInt32)p->low >> 24);
+ }
+ p->cacheSize++;
+ p->low = (UInt32)p->low << 8;
+}
+
+static void RangeEnc_FlushData(CRangeEnc *p)
+{
+ int i;
+ for (i = 0; i < 5; i++)
+ RangeEnc_ShiftLow(p);
+}
+
+static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits)
+{
+ do
+ {
+ p->range >>= 1;
+ p->low += p->range & (0 - ((value >> --numBits) & 1));
+ if (p->range < kTopValue)
+ {
+ p->range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+ }
+ while (numBits != 0);
+}
+
+static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol)
+{
+ UInt32 ttt = *prob;
+ UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt;
+ if (symbol == 0)
+ {
+ p->range = newBound;
+ ttt += (kBitModelTotal - ttt) >> kNumMoveBits;
+ }
+ else
+ {
+ p->low += newBound;
+ p->range -= newBound;
+ ttt -= ttt >> kNumMoveBits;
+ }
+ *prob = (CLzmaProb)ttt;
+ if (p->range < kTopValue)
+ {
+ p->range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+}
+
+static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol)
+{
+ symbol |= 0x100;
+ do
+ {
+ RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1);
+ symbol <<= 1;
+ }
+ while (symbol < 0x10000);
+}
+
+static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte)
+{
+ UInt32 offs = 0x100;
+ symbol |= 0x100;
+ do
+ {
+ matchByte <<= 1;
+ RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1);
+ symbol <<= 1;
+ offs &= ~(matchByte ^ symbol);
+ }
+ while (symbol < 0x10000);
+}
+
+void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
+{
+ UInt32 i;
+ for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
+ {
+ const int kCyclesBits = kNumBitPriceShiftBits;
+ UInt32 w = i;
+ UInt32 bitCount = 0;
+ int j;
+ for (j = 0; j < kCyclesBits; j++)
+ {
+ w = w * w;
+ bitCount <<= 1;
+ while (w >= ((UInt32)1 << 16))
+ {
+ w >>= 1;
+ bitCount++;
+ }
+ }
+ ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
+ }
+}
+
+
+#define GET_PRICE(prob, symbol) \
+ p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
+
+#define GET_PRICEa(prob, symbol) \
+ ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
+
+#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
+#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
+
+#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
+#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
+
+static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ symbol |= 0x100;
+ do
+ {
+ price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1);
+ symbol <<= 1;
+ }
+ while (symbol < 0x10000);
+ return price;
+}
+
+static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ UInt32 offs = 0x100;
+ symbol |= 0x100;
+ do
+ {
+ matchByte <<= 1;
+ price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1);
+ symbol <<= 1;
+ offs &= ~(matchByte ^ symbol);
+ }
+ while (symbol < 0x10000);
+ return price;
+}
+
+
+static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
+{
+ UInt32 m = 1;
+ int i;
+ for (i = numBitLevels; i != 0;)
+ {
+ UInt32 bit;
+ i--;
+ bit = (symbol >> i) & 1;
+ RangeEnc_EncodeBit(rc, probs + m, bit);
+ m = (m << 1) | bit;
+ }
+}
+
+static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
+{
+ UInt32 m = 1;
+ int i;
+ for (i = 0; i < numBitLevels; i++)
+ {
+ UInt32 bit = symbol & 1;
+ RangeEnc_EncodeBit(rc, probs + m, bit);
+ m = (m << 1) | bit;
+ symbol >>= 1;
+ }
+}
+
+static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ symbol |= (1 << numBitLevels);
+ while (symbol != 1)
+ {
+ price += GET_PRICEa(probs[symbol >> 1], symbol & 1);
+ symbol >>= 1;
+ }
+ return price;
+}
+
+static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ UInt32 m = 1;
+ int i;
+ for (i = numBitLevels; i != 0; i--)
+ {
+ UInt32 bit = symbol & 1;
+ symbol >>= 1;
+ price += GET_PRICEa(probs[m], bit);
+ m = (m << 1) | bit;
+ }
+ return price;
+}
+
+
+static void LenEnc_Init(CLenEnc *p)
+{
+ unsigned i;
+ p->choice = p->choice2 = kProbInitValue;
+ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++)
+ p->low[i] = kProbInitValue;
+ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++)
+ p->mid[i] = kProbInitValue;
+ for (i = 0; i < kLenNumHighSymbols; i++)
+ p->high[i] = kProbInitValue;
+}
+
+static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState)
+{
+ if (symbol < kLenNumLowSymbols)
+ {
+ RangeEnc_EncodeBit(rc, &p->choice, 0);
+ RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol);
+ }
+ else
+ {
+ RangeEnc_EncodeBit(rc, &p->choice, 1);
+ if (symbol < kLenNumLowSymbols + kLenNumMidSymbols)
+ {
+ RangeEnc_EncodeBit(rc, &p->choice2, 0);
+ RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols);
+ }
+ else
+ {
+ RangeEnc_EncodeBit(rc, &p->choice2, 1);
+ RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols);
+ }
+ }
+}
+
+static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices)
+{
+ UInt32 a0 = GET_PRICE_0a(p->choice);
+ UInt32 a1 = GET_PRICE_1a(p->choice);
+ UInt32 b0 = a1 + GET_PRICE_0a(p->choice2);
+ UInt32 b1 = a1 + GET_PRICE_1a(p->choice2);
+ UInt32 i = 0;
+ for (i = 0; i < kLenNumLowSymbols; i++)
+ {
+ if (i >= numSymbols)
+ return;
+ prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices);
+ }
+ for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++)
+ {
+ if (i >= numSymbols)
+ return;
+ prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices);
+ }
+ for (; i < numSymbols; i++)
+ prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices);
+}
+
+static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices)
+{
+ LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices);
+ p->counters[posState] = p->tableSize;
+}
+
+static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices)
+{
+ UInt32 posState;
+ for (posState = 0; posState < numPosStates; posState++)
+ LenPriceEnc_UpdateTable(p, posState, ProbPrices);
+}
+
+static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices)
+{
+ LenEnc_Encode(&p->p, rc, symbol, posState);
+ if (updatePrice)
+ if (--p->counters[posState] == 0)
+ LenPriceEnc_UpdateTable(p, posState, ProbPrices);
+}
+
+
+
+
+static void MovePos(CLzmaEnc *p, UInt32 num)
+{
+ #ifdef SHOW_STAT
+ ttt += num;
+ printf("\n MovePos %d", num);
+ #endif
+ if (num != 0)
+ {
+ p->additionalOffset += num;
+ p->matchFinder.Skip(p->matchFinderObj, num);
+ }
+}
+
+static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes)
+{
+ UInt32 lenRes = 0, numPairs;
+ p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+ numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches);
+ #ifdef SHOW_STAT
+ printf("\n i = %d numPairs = %d ", ttt, numPairs / 2);
+ ttt++;
+ {
+ UInt32 i;
+ for (i = 0; i < numPairs; i += 2)
+ printf("%2d %6d | ", p->matches[i], p->matches[i + 1]);
+ }
+ #endif
+ if (numPairs > 0)
+ {
+ lenRes = p->matches[numPairs - 2];
+ if (lenRes == p->numFastBytes)
+ {
+ const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ UInt32 distance = p->matches[numPairs - 1] + 1;
+ UInt32 numAvail = p->numAvail;
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+ {
+ const Byte *pby2 = pby - distance;
+ for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
+ }
+ }
+ }
+ p->additionalOffset++;
+ *numDistancePairsRes = numPairs;
+ return lenRes;
+}
+
+
+#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False;
+#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False;
+#define IsShortRep(p) ((p)->backPrev == 0)
+
+static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState)
+{
+ return
+ GET_PRICE_0(p->isRepG0[state]) +
+ GET_PRICE_0(p->isRep0Long[state][posState]);
+}
+
+static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState)
+{
+ UInt32 price;
+ if (repIndex == 0)
+ {
+ price = GET_PRICE_0(p->isRepG0[state]);
+ price += GET_PRICE_1(p->isRep0Long[state][posState]);
+ }
+ else
+ {
+ price = GET_PRICE_1(p->isRepG0[state]);
+ if (repIndex == 1)
+ price += GET_PRICE_0(p->isRepG1[state]);
+ else
+ {
+ price += GET_PRICE_1(p->isRepG1[state]);
+ price += GET_PRICE(p->isRepG2[state], repIndex - 2);
+ }
+ }
+ return price;
+}
+
+static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState)
+{
+ return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] +
+ GetPureRepPrice(p, repIndex, state, posState);
+}
+
+static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur)
+{
+ UInt32 posMem = p->opt[cur].posPrev;
+ UInt32 backMem = p->opt[cur].backPrev;
+ p->optimumEndIndex = cur;
+ do
+ {
+ if (p->opt[cur].prev1IsChar)
+ {
+ MakeAsChar(&p->opt[posMem])
+ p->opt[posMem].posPrev = posMem - 1;
+ if (p->opt[cur].prev2)
+ {
+ p->opt[posMem - 1].prev1IsChar = False;
+ p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2;
+ p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2;
+ }
+ }
+ {
+ UInt32 posPrev = posMem;
+ UInt32 backCur = backMem;
+
+ backMem = p->opt[posPrev].backPrev;
+ posMem = p->opt[posPrev].posPrev;
+
+ p->opt[posPrev].backPrev = backCur;
+ p->opt[posPrev].posPrev = cur;
+ cur = posPrev;
+ }
+ }
+ while (cur != 0);
+ *backRes = p->opt[0].backPrev;
+ p->optimumCurrentIndex = p->opt[0].posPrev;
+ return p->optimumCurrentIndex;
+}
+
+#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300)
+
+static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
+{
+ UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur;
+ UInt32 matchPrice, repMatchPrice, normalMatchPrice;
+ UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS];
+ UInt32 *matches;
+ const Byte *data;
+ Byte curByte, matchByte;
+ if (p->optimumEndIndex != p->optimumCurrentIndex)
+ {
+ const COptimal *opt = &p->opt[p->optimumCurrentIndex];
+ UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex;
+ *backRes = opt->backPrev;
+ p->optimumCurrentIndex = opt->posPrev;
+ return lenRes;
+ }
+ p->optimumCurrentIndex = p->optimumEndIndex = 0;
+
+ if (p->additionalOffset == 0)
+ mainLen = ReadMatchDistances(p, &numPairs);
+ else
+ {
+ mainLen = p->longestMatchLength;
+ numPairs = p->numPairs;
+ }
+
+ numAvail = p->numAvail;
+ if (numAvail < 2)
+ {
+ *backRes = (UInt32)(-1);
+ return 1;
+ }
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ repMaxIndex = 0;
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ UInt32 lenTest;
+ const Byte *data2;
+ reps[i] = p->reps[i];
+ data2 = data - (reps[i] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ {
+ repLens[i] = 0;
+ continue;
+ }
+ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
+ repLens[i] = lenTest;
+ if (lenTest > repLens[repMaxIndex])
+ repMaxIndex = i;
+ }
+ if (repLens[repMaxIndex] >= p->numFastBytes)
+ {
+ UInt32 lenRes;
+ *backRes = repMaxIndex;
+ lenRes = repLens[repMaxIndex];
+ MovePos(p, lenRes - 1);
+ return lenRes;
+ }
+
+ matches = p->matches;
+ if (mainLen >= p->numFastBytes)
+ {
+ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
+ MovePos(p, mainLen - 1);
+ return mainLen;
+ }
+ curByte = *data;
+ matchByte = *(data - (reps[0] + 1));
+
+ if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2)
+ {
+ *backRes = (UInt32)-1;
+ return 1;
+ }
+
+ p->opt[0].state = (CState)p->state;
+
+ posState = (position & p->pbMask);
+
+ {
+ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
+ p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) +
+ (!IsCharState(p->state) ?
+ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
+ LitEnc_GetPrice(probs, curByte, p->ProbPrices));
+ }
+
+ MakeAsChar(&p->opt[1]);
+
+ matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
+ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
+
+ if (matchByte == curByte)
+ {
+ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState);
+ if (shortRepPrice < p->opt[1].price)
+ {
+ p->opt[1].price = shortRepPrice;
+ MakeAsShortRep(&p->opt[1]);
+ }
+ }
+ lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]);
+
+ if (lenEnd < 2)
+ {
+ *backRes = p->opt[1].backPrev;
+ return 1;
+ }
+
+ p->opt[1].posPrev = 0;
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ p->opt[0].backs[i] = reps[i];
+
+ len = lenEnd;
+ do
+ p->opt[len--].price = kInfinityPrice;
+ while (len >= 2);
+
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ UInt32 repLen = repLens[i];
+ UInt32 price;
+ if (repLen < 2)
+ continue;
+ price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState);
+ do
+ {
+ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2];
+ COptimal *opt = &p->opt[repLen];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = 0;
+ opt->backPrev = i;
+ opt->prev1IsChar = False;
+ }
+ }
+ while (--repLen >= 2);
+ }
+
+ normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
+
+ len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
+ if (len <= mainLen)
+ {
+ UInt32 offs = 0;
+ while (len > matches[offs])
+ offs += 2;
+ for (; ; len++)
+ {
+ COptimal *opt;
+ UInt32 distance = matches[offs + 1];
+
+ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN];
+ UInt32 lenToPosState = GetLenToPosState(len);
+ if (distance < kNumFullDistances)
+ curAndLenPrice += p->distancesPrices[lenToPosState][distance];
+ else
+ {
+ UInt32 slot;
+ GetPosSlot2(distance, slot);
+ curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot];
+ }
+ opt = &p->opt[len];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = 0;
+ opt->backPrev = distance + LZMA_NUM_REPS;
+ opt->prev1IsChar = False;
+ }
+ if (len == matches[offs])
+ {
+ offs += 2;
+ if (offs == numPairs)
+ break;
+ }
+ }
+ }
+
+ cur = 0;
+
+ #ifdef SHOW_STAT2
+ if (position >= 0)
+ {
+ unsigned i;
+ printf("\n pos = %4X", position);
+ for (i = cur; i <= lenEnd; i++)
+ printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price);
+ }
+ #endif
+
+ for (;;)
+ {
+ UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen;
+ UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice;
+ Bool nextIsChar;
+ Byte curByte, matchByte;
+ const Byte *data;
+ COptimal *curOpt;
+ COptimal *nextOpt;
+
+ cur++;
+ if (cur == lenEnd)
+ return Backward(p, backRes, cur);
+
+ newLen = ReadMatchDistances(p, &numPairs);
+ if (newLen >= p->numFastBytes)
+ {
+ p->numPairs = numPairs;
+ p->longestMatchLength = newLen;
+ return Backward(p, backRes, cur);
+ }
+ position++;
+ curOpt = &p->opt[cur];
+ posPrev = curOpt->posPrev;
+ if (curOpt->prev1IsChar)
+ {
+ posPrev--;
+ if (curOpt->prev2)
+ {
+ state = p->opt[curOpt->posPrev2].state;
+ if (curOpt->backPrev2 < LZMA_NUM_REPS)
+ state = kRepNextStates[state];
+ else
+ state = kMatchNextStates[state];
+ }
+ else
+ state = p->opt[posPrev].state;
+ state = kLiteralNextStates[state];
+ }
+ else
+ state = p->opt[posPrev].state;
+ if (posPrev == cur - 1)
+ {
+ if (IsShortRep(curOpt))
+ state = kShortRepNextStates[state];
+ else
+ state = kLiteralNextStates[state];
+ }
+ else
+ {
+ UInt32 pos;
+ const COptimal *prevOpt;
+ if (curOpt->prev1IsChar && curOpt->prev2)
+ {
+ posPrev = curOpt->posPrev2;
+ pos = curOpt->backPrev2;
+ state = kRepNextStates[state];
+ }
+ else
+ {
+ pos = curOpt->backPrev;
+ if (pos < LZMA_NUM_REPS)
+ state = kRepNextStates[state];
+ else
+ state = kMatchNextStates[state];
+ }
+ prevOpt = &p->opt[posPrev];
+ if (pos < LZMA_NUM_REPS)
+ {
+ UInt32 i;
+ reps[0] = prevOpt->backs[pos];
+ for (i = 1; i <= pos; i++)
+ reps[i] = prevOpt->backs[i - 1];
+ for (; i < LZMA_NUM_REPS; i++)
+ reps[i] = prevOpt->backs[i];
+ }
+ else
+ {
+ UInt32 i;
+ reps[0] = (pos - LZMA_NUM_REPS);
+ for (i = 1; i < LZMA_NUM_REPS; i++)
+ reps[i] = prevOpt->backs[i - 1];
+ }
+ }
+ curOpt->state = (CState)state;
+
+ curOpt->backs[0] = reps[0];
+ curOpt->backs[1] = reps[1];
+ curOpt->backs[2] = reps[2];
+ curOpt->backs[3] = reps[3];
+
+ curPrice = curOpt->price;
+ nextIsChar = False;
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ curByte = *data;
+ matchByte = *(data - (reps[0] + 1));
+
+ posState = (position & p->pbMask);
+
+ curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]);
+ {
+ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
+ curAnd1Price +=
+ (!IsCharState(state) ?
+ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
+ LitEnc_GetPrice(probs, curByte, p->ProbPrices));
+ }
+
+ nextOpt = &p->opt[cur + 1];
+
+ if (curAnd1Price < nextOpt->price)
+ {
+ nextOpt->price = curAnd1Price;
+ nextOpt->posPrev = cur;
+ MakeAsChar(nextOpt);
+ nextIsChar = True;
+ }
+
+ matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]);
+ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
+
+ if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0))
+ {
+ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState);
+ if (shortRepPrice <= nextOpt->price)
+ {
+ nextOpt->price = shortRepPrice;
+ nextOpt->posPrev = cur;
+ MakeAsShortRep(nextOpt);
+ nextIsChar = True;
+ }
+ }
+ numAvailFull = p->numAvail;
+ {
+ UInt32 temp = kNumOpts - 1 - cur;
+ if (temp < numAvailFull)
+ numAvailFull = temp;
+ }
+
+ if (numAvailFull < 2)
+ continue;
+ numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes);
+
+ if (!nextIsChar && matchByte != curByte) /* speed optimization */
+ {
+ /* try Literal + rep0 */
+ UInt32 temp;
+ UInt32 lenTest2;
+ const Byte *data2 = data - (reps[0] + 1);
+ UInt32 limit = p->numFastBytes + 1;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+
+ for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
+ lenTest2 = temp - 1;
+ if (lenTest2 >= 2)
+ {
+ UInt32 state2 = kLiteralNextStates[state];
+ UInt32 posStateNext = (position + 1) & p->pbMask;
+ UInt32 nextRepMatchPrice = curAnd1Price +
+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
+ GET_PRICE_1(p->isRep[state2]);
+ /* for (; lenTest2 >= 2; lenTest2--) */
+ {
+ UInt32 curAndLenPrice;
+ COptimal *opt;
+ UInt32 offset = cur + 1 + lenTest2;
+ while (lenEnd < offset)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
+ opt = &p->opt[offset];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur + 1;
+ opt->backPrev = 0;
+ opt->prev1IsChar = True;
+ opt->prev2 = False;
+ }
+ }
+ }
+ }
+
+ startLen = 2; /* speed optimization */
+ {
+ UInt32 repIndex;
+ for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++)
+ {
+ UInt32 lenTest;
+ UInt32 lenTestTemp;
+ UInt32 price;
+ const Byte *data2 = data - (reps[repIndex] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
+ while (lenEnd < cur + lenTest)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ lenTestTemp = lenTest;
+ price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState);
+ do
+ {
+ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2];
+ COptimal *opt = &p->opt[cur + lenTest];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur;
+ opt->backPrev = repIndex;
+ opt->prev1IsChar = False;
+ }
+ }
+ while (--lenTest >= 2);
+ lenTest = lenTestTemp;
+
+ if (repIndex == 0)
+ startLen = lenTest + 1;
+
+ /* if (_maxMode) */
+ {
+ UInt32 lenTest2 = lenTest + 1;
+ UInt32 limit = lenTest2 + p->numFastBytes;
+ UInt32 nextRepMatchPrice;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
+ lenTest2 -= lenTest + 1;
+ if (lenTest2 >= 2)
+ {
+ UInt32 state2 = kRepNextStates[state];
+ UInt32 posStateNext = (position + lenTest) & p->pbMask;
+ UInt32 curAndLenCharPrice =
+ price + p->repLenEnc.prices[posState][lenTest - 2] +
+ GET_PRICE_0(p->isMatch[state2][posStateNext]) +
+ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
+ data[lenTest], data2[lenTest], p->ProbPrices);
+ state2 = kLiteralNextStates[state2];
+ posStateNext = (position + lenTest + 1) & p->pbMask;
+ nextRepMatchPrice = curAndLenCharPrice +
+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
+ GET_PRICE_1(p->isRep[state2]);
+
+ /* for (; lenTest2 >= 2; lenTest2--) */
+ {
+ UInt32 curAndLenPrice;
+ COptimal *opt;
+ UInt32 offset = cur + lenTest + 1 + lenTest2;
+ while (lenEnd < offset)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
+ opt = &p->opt[offset];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur + lenTest + 1;
+ opt->backPrev = 0;
+ opt->prev1IsChar = True;
+ opt->prev2 = True;
+ opt->posPrev2 = cur;
+ opt->backPrev2 = repIndex;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */
+ if (newLen > numAvail)
+ {
+ newLen = numAvail;
+ for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2);
+ matches[numPairs] = newLen;
+ numPairs += 2;
+ }
+ if (newLen >= startLen)
+ {
+ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
+ UInt32 offs, curBack, posSlot;
+ UInt32 lenTest;
+ while (lenEnd < cur + newLen)
+ p->opt[++lenEnd].price = kInfinityPrice;
+
+ offs = 0;
+ while (startLen > matches[offs])
+ offs += 2;
+ curBack = matches[offs + 1];
+ GetPosSlot2(curBack, posSlot);
+ for (lenTest = /*2*/ startLen; ; lenTest++)
+ {
+ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN];
+ UInt32 lenToPosState = GetLenToPosState(lenTest);
+ COptimal *opt;
+ if (curBack < kNumFullDistances)
+ curAndLenPrice += p->distancesPrices[lenToPosState][curBack];
+ else
+ curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask];
+
+ opt = &p->opt[cur + lenTest];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur;
+ opt->backPrev = curBack + LZMA_NUM_REPS;
+ opt->prev1IsChar = False;
+ }
+
+ if (/*_maxMode && */lenTest == matches[offs])
+ {
+ /* Try Match + Literal + Rep0 */
+ const Byte *data2 = data - (curBack + 1);
+ UInt32 lenTest2 = lenTest + 1;
+ UInt32 limit = lenTest2 + p->numFastBytes;
+ UInt32 nextRepMatchPrice;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
+ lenTest2 -= lenTest + 1;
+ if (lenTest2 >= 2)
+ {
+ UInt32 state2 = kMatchNextStates[state];
+ UInt32 posStateNext = (position + lenTest) & p->pbMask;
+ UInt32 curAndLenCharPrice = curAndLenPrice +
+ GET_PRICE_0(p->isMatch[state2][posStateNext]) +
+ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
+ data[lenTest], data2[lenTest], p->ProbPrices);
+ state2 = kLiteralNextStates[state2];
+ posStateNext = (posStateNext + 1) & p->pbMask;
+ nextRepMatchPrice = curAndLenCharPrice +
+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
+ GET_PRICE_1(p->isRep[state2]);
+
+ /* for (; lenTest2 >= 2; lenTest2--) */
+ {
+ UInt32 offset = cur + lenTest + 1 + lenTest2;
+ UInt32 curAndLenPrice;
+ COptimal *opt;
+ while (lenEnd < offset)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
+ opt = &p->opt[offset];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur + lenTest + 1;
+ opt->backPrev = 0;
+ opt->prev1IsChar = True;
+ opt->prev2 = True;
+ opt->posPrev2 = cur;
+ opt->backPrev2 = curBack + LZMA_NUM_REPS;
+ }
+ }
+ }
+ offs += 2;
+ if (offs == numPairs)
+ break;
+ curBack = matches[offs + 1];
+ if (curBack >= kNumFullDistances)
+ GetPosSlot2(curBack, posSlot);
+ }
+ }
+ }
+ }
+}
+
+#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
+
+static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes)
+{
+ UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i;
+ const Byte *data;
+ const UInt32 *matches;
+
+ if (p->additionalOffset == 0)
+ mainLen = ReadMatchDistances(p, &numPairs);
+ else
+ {
+ mainLen = p->longestMatchLength;
+ numPairs = p->numPairs;
+ }
+
+ numAvail = p->numAvail;
+ *backRes = (UInt32)-1;
+ if (numAvail < 2)
+ return 1;
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+
+ repLen = repIndex = 0;
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ UInt32 len;
+ const Byte *data2 = data - (p->reps[i] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ for (len = 2; len < numAvail && data[len] == data2[len]; len++);
+ if (len >= p->numFastBytes)
+ {
+ *backRes = i;
+ MovePos(p, len - 1);
+ return len;
+ }
+ if (len > repLen)
+ {
+ repIndex = i;
+ repLen = len;
+ }
+ }
+
+ matches = p->matches;
+ if (mainLen >= p->numFastBytes)
+ {
+ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
+ MovePos(p, mainLen - 1);
+ return mainLen;
+ }
+
+ mainDist = 0; /* for GCC */
+ if (mainLen >= 2)
+ {
+ mainDist = matches[numPairs - 1];
+ while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1)
+ {
+ if (!ChangePair(matches[numPairs - 3], mainDist))
+ break;
+ numPairs -= 2;
+ mainLen = matches[numPairs - 2];
+ mainDist = matches[numPairs - 1];
+ }
+ if (mainLen == 2 && mainDist >= 0x80)
+ mainLen = 1;
+ }
+
+ if (repLen >= 2 && (
+ (repLen + 1 >= mainLen) ||
+ (repLen + 2 >= mainLen && mainDist >= (1 << 9)) ||
+ (repLen + 3 >= mainLen && mainDist >= (1 << 15))))
+ {
+ *backRes = repIndex;
+ MovePos(p, repLen - 1);
+ return repLen;
+ }
+
+ if (mainLen < 2 || numAvail <= 2)
+ return 1;
+
+ p->longestMatchLength = ReadMatchDistances(p, &p->numPairs);
+ if (p->longestMatchLength >= 2)
+ {
+ UInt32 newDistance = matches[p->numPairs - 1];
+ if ((p->longestMatchLength >= mainLen && newDistance < mainDist) ||
+ (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) ||
+ (p->longestMatchLength > mainLen + 1) ||
+ (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist)))
+ return 1;
+ }
+
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ UInt32 len, limit;
+ const Byte *data2 = data - (p->reps[i] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ limit = mainLen - 1;
+ for (len = 2; len < limit && data[len] == data2[len]; len++);
+ if (len >= limit)
+ return 1;
+ }
+ *backRes = mainDist + LZMA_NUM_REPS;
+ MovePos(p, mainLen - 2);
+ return mainLen;
+}
+
+static void WriteEndMarker(CLzmaEnc *p, UInt32 posState)
+{
+ UInt32 len;
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
+ p->state = kMatchNextStates[p->state];
+ len = LZMA_MATCH_LEN_MIN;
+ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
+ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1);
+ RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits);
+ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
+}
+
+static SRes CheckErrors(CLzmaEnc *p)
+{
+ if (p->result != SZ_OK)
+ return p->result;
+ if (p->rc.res != SZ_OK)
+ p->result = SZ_ERROR_WRITE;
+ if (p->matchFinderBase.result != SZ_OK)
+ p->result = SZ_ERROR_READ;
+ if (p->result != SZ_OK)
+ p->finished = True;
+ return p->result;
+}
+
+static SRes Flush(CLzmaEnc *p, UInt32 nowPos)
+{
+ /* ReleaseMFStream(); */
+ p->finished = True;
+ if (p->writeEndMark)
+ WriteEndMarker(p, nowPos & p->pbMask);
+ RangeEnc_FlushData(&p->rc);
+ RangeEnc_FlushStream(&p->rc);
+ return CheckErrors(p);
+}
+
+static void FillAlignPrices(CLzmaEnc *p)
+{
+ UInt32 i;
+ for (i = 0; i < kAlignTableSize; i++)
+ p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
+ p->alignPriceCount = 0;
+}
+
+static void FillDistancesPrices(CLzmaEnc *p)
+{
+ UInt32 tempPrices[kNumFullDistances];
+ UInt32 i, lenToPosState;
+ for (i = kStartPosModelIndex; i < kNumFullDistances; i++)
+ {
+ UInt32 posSlot = GetPosSlot1(i);
+ UInt32 footerBits = ((posSlot >> 1) - 1);
+ UInt32 base = ((2 | (posSlot & 1)) << footerBits);
+ tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices);
+ }
+
+ for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
+ {
+ UInt32 posSlot;
+ const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState];
+ UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState];
+ for (posSlot = 0; posSlot < p->distTableSize; posSlot++)
+ posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices);
+ for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++)
+ posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
+
+ {
+ UInt32 *distancesPrices = p->distancesPrices[lenToPosState];
+ UInt32 i;
+ for (i = 0; i < kStartPosModelIndex; i++)
+ distancesPrices[i] = posSlotPrices[i];
+ for (; i < kNumFullDistances; i++)
+ distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i];
+ }
+ }
+ p->matchPriceCount = 0;
+}
+
+void LzmaEnc_Construct(CLzmaEnc *p)
+{
+ RangeEnc_Construct(&p->rc);
+ MatchFinder_Construct(&p->matchFinderBase);
+ #ifndef _7ZIP_ST
+ MatchFinderMt_Construct(&p->matchFinderMt);
+ p->matchFinderMt.MatchFinder = &p->matchFinderBase;
+ #endif
+
+ {
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+ LzmaEnc_SetProps(p, &props);
+ }
+
+ #ifndef LZMA_LOG_BSR
+ LzmaEnc_FastPosInit(p->g_FastPos);
+ #endif
+
+ LzmaEnc_InitPriceTables(p->ProbPrices);
+ p->litProbs = 0;
+ p->saveState.litProbs = 0;
+}
+
+CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc)
+{
+ void *p;
+ p = alloc->Alloc(alloc, sizeof(CLzmaEnc));
+ if (p != 0)
+ LzmaEnc_Construct((CLzmaEnc *)p);
+ return p;
+}
+
+void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->litProbs);
+ alloc->Free(alloc, p->saveState.litProbs);
+ p->litProbs = 0;
+ p->saveState.litProbs = 0;
+}
+
+void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ #ifndef _7ZIP_ST
+ MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
+ #endif
+ MatchFinder_Free(&p->matchFinderBase, allocBig);
+ LzmaEnc_FreeLits(p, alloc);
+ RangeEnc_Free(&p->rc, alloc);
+}
+
+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
+ alloc->Free(alloc, p);
+}
+
+static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize)
+{
+ UInt32 nowPos32, startPos32;
+ if (p->needInit)
+ {
+ p->matchFinder.Init(p->matchFinderObj);
+ p->needInit = 0;
+ }
+
+ if (p->finished)
+ return p->result;
+ RINOK(CheckErrors(p));
+
+ nowPos32 = (UInt32)p->nowPos64;
+ startPos32 = nowPos32;
+
+ if (p->nowPos64 == 0)
+ {
+ UInt32 numPairs;
+ Byte curByte;
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
+ return Flush(p, nowPos32);
+ ReadMatchDistances(p, &numPairs);
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0);
+ p->state = kLiteralNextStates[p->state];
+ curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset);
+ LitEnc_Encode(&p->rc, p->litProbs, curByte);
+ p->additionalOffset--;
+ nowPos32++;
+ }
+
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
+ for (;;)
+ {
+ UInt32 pos, len, posState;
+
+ if (p->fastMode)
+ len = GetOptimumFast(p, &pos);
+ else
+ len = GetOptimum(p, nowPos32, &pos);
+
+ #ifdef SHOW_STAT2
+ printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos);
+ #endif
+
+ posState = nowPos32 & p->pbMask;
+ if (len == 1 && pos == (UInt32)-1)
+ {
+ Byte curByte;
+ CLzmaProb *probs;
+ const Byte *data;
+
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0);
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+ curByte = *data;
+ probs = LIT_PROBS(nowPos32, *(data - 1));
+ if (IsCharState(p->state))
+ LitEnc_Encode(&p->rc, probs, curByte);
+ else
+ LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1));
+ p->state = kLiteralNextStates[p->state];
+ }
+ else
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
+ if (pos < LZMA_NUM_REPS)
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1);
+ if (pos == 0)
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0);
+ RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1));
+ }
+ else
+ {
+ UInt32 distance = p->reps[pos];
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1);
+ if (pos == 1)
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0);
+ else
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1);
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2);
+ if (pos == 3)
+ p->reps[3] = p->reps[2];
+ p->reps[2] = p->reps[1];
+ }
+ p->reps[1] = p->reps[0];
+ p->reps[0] = distance;
+ }
+ if (len == 1)
+ p->state = kShortRepNextStates[p->state];
+ else
+ {
+ LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
+ p->state = kRepNextStates[p->state];
+ }
+ }
+ else
+ {
+ UInt32 posSlot;
+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
+ p->state = kMatchNextStates[p->state];
+ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
+ pos -= LZMA_NUM_REPS;
+ GetPosSlot(pos, posSlot);
+ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot);
+
+ if (posSlot >= kStartPosModelIndex)
+ {
+ UInt32 footerBits = ((posSlot >> 1) - 1);
+ UInt32 base = ((2 | (posSlot & 1)) << footerBits);
+ UInt32 posReduced = pos - base;
+
+ if (posSlot < kEndPosModelIndex)
+ RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced);
+ else
+ {
+ RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
+ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
+ p->alignPriceCount++;
+ }
+ }
+ p->reps[3] = p->reps[2];
+ p->reps[2] = p->reps[1];
+ p->reps[1] = p->reps[0];
+ p->reps[0] = pos;
+ p->matchPriceCount++;
+ }
+ }
+ p->additionalOffset -= len;
+ nowPos32 += len;
+ if (p->additionalOffset == 0)
+ {
+ UInt32 processed;
+ if (!p->fastMode)
+ {
+ if (p->matchPriceCount >= (1 << 7))
+ FillDistancesPrices(p);
+ if (p->alignPriceCount >= kAlignTableSize)
+ FillAlignPrices(p);
+ }
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
+ break;
+ processed = nowPos32 - startPos32;
+ if (useLimits)
+ {
+ if (processed + kNumOpts + 300 >= maxUnpackSize ||
+ RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize)
+ break;
+ }
+ else if (processed >= (1 << 15))
+ {
+ p->nowPos64 += nowPos32 - startPos32;
+ return CheckErrors(p);
+ }
+ }
+ }
+ p->nowPos64 += nowPos32 - startPos32;
+ return Flush(p, nowPos32);
+}
+
+#define kBigHashDicLimit ((UInt32)1 << 24)
+
+static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ UInt32 beforeSize = kNumOpts;
+ Bool btMode;
+ if (!RangeEnc_Alloc(&p->rc, alloc))
+ return SZ_ERROR_MEM;
+ btMode = (p->matchFinderBase.btMode != 0);
+ #ifndef _7ZIP_ST
+ p->mtMode = (p->multiThread && !p->fastMode && btMode);
+ #endif
+
+ {
+ unsigned lclp = p->lc + p->lp;
+ if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp)
+ {
+ LzmaEnc_FreeLits(p, alloc);
+ p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
+ p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
+ if (p->litProbs == 0 || p->saveState.litProbs == 0)
+ {
+ LzmaEnc_FreeLits(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ p->lclp = lclp;
+ }
+ }
+
+ p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit);
+
+ if (beforeSize + p->dictSize < keepWindowSize)
+ beforeSize = keepWindowSize - p->dictSize;
+
+ #ifndef _7ZIP_ST
+ if (p->mtMode)
+ {
+ RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig));
+ p->matchFinderObj = &p->matchFinderMt;
+ MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
+ }
+ else
+ #endif
+ {
+ if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig))
+ return SZ_ERROR_MEM;
+ p->matchFinderObj = &p->matchFinderBase;
+ MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);
+ }
+ return SZ_OK;
+}
+
+void LzmaEnc_Init(CLzmaEnc *p)
+{
+ UInt32 i;
+ p->state = 0;
+ for (i = 0 ; i < LZMA_NUM_REPS; i++)
+ p->reps[i] = 0;
+
+ RangeEnc_Init(&p->rc);
+
+
+ for (i = 0; i < kNumStates; i++)
+ {
+ UInt32 j;
+ for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
+ {
+ p->isMatch[i][j] = kProbInitValue;
+ p->isRep0Long[i][j] = kProbInitValue;
+ }
+ p->isRep[i] = kProbInitValue;
+ p->isRepG0[i] = kProbInitValue;
+ p->isRepG1[i] = kProbInitValue;
+ p->isRepG2[i] = kProbInitValue;
+ }
+
+ {
+ UInt32 num = 0x300 << (p->lp + p->lc);
+ for (i = 0; i < num; i++)
+ p->litProbs[i] = kProbInitValue;
+ }
+
+ {
+ for (i = 0; i < kNumLenToPosStates; i++)
+ {
+ CLzmaProb *probs = p->posSlotEncoder[i];
+ UInt32 j;
+ for (j = 0; j < (1 << kNumPosSlotBits); j++)
+ probs[j] = kProbInitValue;
+ }
+ }
+ {
+ for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
+ p->posEncoders[i] = kProbInitValue;
+ }
+
+ LenEnc_Init(&p->lenEnc.p);
+ LenEnc_Init(&p->repLenEnc.p);
+
+ for (i = 0; i < (1 << kNumAlignBits); i++)
+ p->posAlignEncoder[i] = kProbInitValue;
+
+ p->optimumEndIndex = 0;
+ p->optimumCurrentIndex = 0;
+ p->additionalOffset = 0;
+
+ p->pbMask = (1 << p->pb) - 1;
+ p->lpMask = (1 << p->lp) - 1;
+}
+
+void LzmaEnc_InitPrices(CLzmaEnc *p)
+{
+ if (!p->fastMode)
+ {
+ FillDistancesPrices(p);
+ FillAlignPrices(p);
+ }
+
+ p->lenEnc.tableSize =
+ p->repLenEnc.tableSize =
+ p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
+ LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices);
+ LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices);
+}
+
+static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ UInt32 i;
+ for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++)
+ if (p->dictSize <= ((UInt32)1 << i))
+ break;
+ p->distTableSize = i * 2;
+
+ p->finished = False;
+ p->result = SZ_OK;
+ RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig));
+ LzmaEnc_Init(p);
+ LzmaEnc_InitPrices(p);
+ p->nowPos64 = 0;
+ return SZ_OK;
+}
+
+static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
+ ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ p->matchFinderBase.stream = inStream;
+ p->needInit = 1;
+ p->rc.outStream = outStream;
+ return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
+}
+
+SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
+ ISeqInStream *inStream, UInt32 keepWindowSize,
+ ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ p->matchFinderBase.stream = inStream;
+ p->needInit = 1;
+ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+}
+
+static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
+{
+ p->matchFinderBase.directInput = 1;
+ p->matchFinderBase.bufferBase = (Byte *)src;
+ p->matchFinderBase.directInputRem = srcLen;
+}
+
+SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
+ UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ LzmaEnc_SetInputBuf(p, src, srcLen);
+ p->needInit = 1;
+
+ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+}
+
+void LzmaEnc_Finish(CLzmaEncHandle pp)
+{
+ #ifndef _7ZIP_ST
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ if (p->mtMode)
+ MatchFinderMt_ReleaseStream(&p->matchFinderMt);
+ #else
+ pp = pp;
+ #endif
+}
+
+typedef struct
+{
+ ISeqOutStream funcTable;
+ Byte *data;
+ SizeT rem;
+ Bool overflow;
+} CSeqOutStreamBuf;
+
+static size_t MyWrite(void *pp, const void *data, size_t size)
+{
+ CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp;
+ if (p->rem < size)
+ {
+ size = p->rem;
+ p->overflow = True;
+ }
+ memcpy(p->data, data, size);
+ p->rem -= size;
+ p->data += size;
+ return size;
+}
+
+
+UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
+{
+ const CLzmaEnc *p = (CLzmaEnc *)pp;
+ return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+}
+
+const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
+{
+ const CLzmaEnc *p = (CLzmaEnc *)pp;
+ return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+}
+
+SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
+ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ UInt64 nowPos64;
+ SRes res;
+ CSeqOutStreamBuf outStream;
+
+ outStream.funcTable.Write = MyWrite;
+ outStream.data = dest;
+ outStream.rem = *destLen;
+ outStream.overflow = False;
+
+ p->writeEndMark = False;
+ p->finished = False;
+ p->result = SZ_OK;
+
+ if (reInit)
+ LzmaEnc_Init(p);
+ LzmaEnc_InitPrices(p);
+ nowPos64 = p->nowPos64;
+ RangeEnc_Init(&p->rc);
+ p->rc.outStream = &outStream.funcTable;
+
+ res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize);
+
+ *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
+ *destLen -= outStream.rem;
+ if (outStream.overflow)
+ return SZ_ERROR_OUTPUT_EOF;
+
+ return res;
+}
+
+static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
+{
+ SRes res = SZ_OK;
+
+ #ifndef _7ZIP_ST
+ Byte allocaDummy[0x300];
+ int i = 0;
+ for (i = 0; i < 16; i++)
+ allocaDummy[i] = (Byte)i;
+ #endif
+
+ for (;;)
+ {
+ res = LzmaEnc_CodeOneBlock(p, False, 0, 0);
+ if (res != SZ_OK || p->finished != 0)
+ break;
+ if (progress != 0)
+ {
+ res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
+ if (res != SZ_OK)
+ {
+ res = SZ_ERROR_PROGRESS;
+ break;
+ }
+ }
+ }
+ LzmaEnc_Finish(p);
+ return res;
+}
+
+SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
+ ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
+ return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
+}
+
+SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ int i;
+ UInt32 dictSize = p->dictSize;
+ if (*size < LZMA_PROPS_SIZE)
+ return SZ_ERROR_PARAM;
+ *size = LZMA_PROPS_SIZE;
+ props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
+
+ for (i = 11; i <= 30; i++)
+ {
+ if (dictSize <= ((UInt32)2 << i))
+ {
+ dictSize = (2 << i);
+ break;
+ }
+ if (dictSize <= ((UInt32)3 << i))
+ {
+ dictSize = (3 << i);
+ break;
+ }
+ }
+
+ for (i = 0; i < 4; i++)
+ props[1 + i] = (Byte)(dictSize >> (8 * i));
+ return SZ_OK;
+}
+
+SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ SRes res;
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+
+ CSeqOutStreamBuf outStream;
+
+ LzmaEnc_SetInputBuf(p, src, srcLen);
+
+ outStream.funcTable.Write = MyWrite;
+ outStream.data = dest;
+ outStream.rem = *destLen;
+ outStream.overflow = False;
+
+ p->writeEndMark = writeEndMark;
+
+ p->rc.outStream = &outStream.funcTable;
+ res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
+ if (res == SZ_OK)
+ res = LzmaEnc_Encode2(p, progress);
+
+ *destLen -= outStream.rem;
+ if (outStream.overflow)
+ return SZ_ERROR_OUTPUT_EOF;
+ return res;
+}
+
+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
+ SRes res;
+ if (p == 0)
+ return SZ_ERROR_MEM;
+
+ res = LzmaEnc_SetProps(p, props);
+ if (res == SZ_OK)
+ {
+ res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
+ if (res == SZ_OK)
+ res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
+ writeEndMark, progress, alloc, allocBig);
+ }
+
+ LzmaEnc_Destroy(p, alloc, allocBig);
+ return res;
+}
diff --git a/dep/StormLib/src/lzma/C/LzmaEnc.h b/dep/StormLib/src/lzma/C/LzmaEnc.h
new file mode 100644
index 00000000000..200d60eb83c
--- /dev/null
+++ b/dep/StormLib/src/lzma/C/LzmaEnc.h
@@ -0,0 +1,80 @@
+/* LzmaEnc.h -- LZMA Encoder
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_ENC_H
+#define __LZMA_ENC_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaEncProps
+{
+ int level; /* 0 <= level <= 9 */
+ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
+ (1 << 12) <= dictSize <= (1 << 30) for 64-bit version
+ default = (1 << 24) */
+ int lc; /* 0 <= lc <= 8, default = 3 */
+ int lp; /* 0 <= lp <= 4, default = 0 */
+ int pb; /* 0 <= pb <= 4, default = 2 */
+ int algo; /* 0 - fast, 1 - normal, default = 1 */
+ int fb; /* 5 <= fb <= 273, default = 32 */
+ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
+ int numHashBytes; /* 2, 3 or 4, default = 4 */
+ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */
+ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
+ int numThreads; /* 1 or 2, default = 2 */
+} CLzmaEncProps;
+
+void LzmaEncProps_Init(CLzmaEncProps *p);
+void LzmaEncProps_Normalize(CLzmaEncProps *p);
+UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
+
+
+/* ---------- CLzmaEncHandle Interface ---------- */
+
+/* LzmaEnc_* functions can return the following exit codes:
+Returns:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater in props
+ SZ_ERROR_WRITE - Write callback error.
+ SZ_ERROR_PROGRESS - some break from progress callback
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+typedef void * CLzmaEncHandle;
+
+CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
+SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
+SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
+SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+
+/* ---------- One Call Interface ---------- */
+
+/* LzmaEncode
+Return code:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dep/StormLib/src/lzma/C/Threads.c b/dep/StormLib/src/lzma/C/Threads.c
new file mode 100644
index 00000000000..7af1da2e26e
--- /dev/null
+++ b/dep/StormLib/src/lzma/C/Threads.c
@@ -0,0 +1,84 @@
+/* Threads.c -- multithreading library
+2009-09-20 : Igor Pavlov : Public domain */
+
+#ifndef _WIN32_WCE
+#include <process.h>
+#endif
+
+#include "Threads.h"
+
+static WRes GetError()
+{
+ DWORD res = GetLastError();
+ return (res) ? (WRes)(res) : 1;
+}
+
+WRes HandleToWRes(HANDLE h) { return (h != 0) ? 0 : GetError(); }
+WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); }
+
+WRes HandlePtr_Close(HANDLE *p)
+{
+ if (*p != NULL)
+ if (!CloseHandle(*p))
+ return GetError();
+ *p = NULL;
+ return 0;
+}
+
+WRes Handle_WaitObject(HANDLE h) { return (WRes)WaitForSingleObject(h, INFINITE); }
+
+WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
+{
+ unsigned threadId; /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
+ *p =
+ #ifdef UNDER_CE
+ CreateThread(0, 0, func, param, 0, &threadId);
+ #else
+ (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId);
+ #endif
+ /* maybe we must use errno here, but probably GetLastError() is also OK. */
+ return HandleToWRes(*p);
+}
+
+WRes Event_Create(CEvent *p, BOOL manualReset, int signaled)
+{
+ *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL);
+ return HandleToWRes(*p);
+}
+
+WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); }
+WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); }
+
+WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); }
+WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); }
+WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); }
+WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); }
+
+
+WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
+{
+ *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL);
+ return HandleToWRes(*p);
+}
+
+static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount)
+ { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); }
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num)
+ { return Semaphore_Release(p, (LONG)num, NULL); }
+WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); }
+
+WRes CriticalSection_Init(CCriticalSection *p)
+{
+ /* InitializeCriticalSection can raise only STATUS_NO_MEMORY exception */
+ #ifdef _MSC_VER
+ __try
+ #endif
+ {
+ InitializeCriticalSection(p);
+ /* InitializeCriticalSectionAndSpinCount(p, 0); */
+ }
+ #ifdef _MSC_VER
+ __except (EXCEPTION_EXECUTE_HANDLER) { return 1; }
+ #endif
+ return 0;
+}
diff --git a/dep/StormLib/src/lzma/C/Threads.h b/dep/StormLib/src/lzma/C/Threads.h
new file mode 100644
index 00000000000..d0ddd80e227
--- /dev/null
+++ b/dep/StormLib/src/lzma/C/Threads.h
@@ -0,0 +1,59 @@
+/* Threads.h -- multithreading library
+2009-03-27 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_THREADS_H
+#define __7Z_THREADS_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+WRes HandlePtr_Close(HANDLE *h);
+WRes Handle_WaitObject(HANDLE h);
+
+typedef HANDLE CThread;
+#define Thread_Construct(p) *(p) = NULL
+#define Thread_WasCreated(p) (*(p) != NULL)
+#define Thread_Close(p) HandlePtr_Close(p)
+#define Thread_Wait(p) Handle_WaitObject(*(p))
+typedef unsigned THREAD_FUNC_RET_TYPE;
+#define THREAD_FUNC_CALL_TYPE MY_STD_CALL
+#define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
+typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *);
+WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param);
+
+typedef HANDLE CEvent;
+typedef CEvent CAutoResetEvent;
+typedef CEvent CManualResetEvent;
+#define Event_Construct(p) *(p) = NULL
+#define Event_IsCreated(p) (*(p) != NULL)
+#define Event_Close(p) HandlePtr_Close(p)
+#define Event_Wait(p) Handle_WaitObject(*(p))
+WRes Event_Set(CEvent *p);
+WRes Event_Reset(CEvent *p);
+WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled);
+WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p);
+WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled);
+WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p);
+
+typedef HANDLE CSemaphore;
+#define Semaphore_Construct(p) (*p) = NULL
+#define Semaphore_Close(p) HandlePtr_Close(p)
+#define Semaphore_Wait(p) Handle_WaitObject(*(p))
+WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
+WRes Semaphore_Release1(CSemaphore *p);
+
+typedef CRITICAL_SECTION CCriticalSection;
+WRes CriticalSection_Init(CCriticalSection *p);
+#define CriticalSection_Delete(p) DeleteCriticalSection(p)
+#define CriticalSection_Enter(p) EnterCriticalSection(p)
+#define CriticalSection_Leave(p) LeaveCriticalSection(p)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dep/StormLib/src/lzma/C/Types.h b/dep/StormLib/src/lzma/C/Types.h
new file mode 100644
index 00000000000..0526cb47b6e
--- /dev/null
+++ b/dep/StormLib/src/lzma/C/Types.h
@@ -0,0 +1,236 @@
+/* Types.h -- Basic types
+2010-03-11 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_TYPES_H
+#define __7Z_TYPES_H
+
+#include <stddef.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#ifndef EXTERN_C_BEGIN
+#ifdef __cplusplus
+#define EXTERN_C_BEGIN extern "C" {
+#define EXTERN_C_END }
+#else
+#define EXTERN_C_BEGIN
+#define EXTERN_C_END
+#endif
+#endif
+
+EXTERN_C_BEGIN
+
+#define SZ_OK 0
+
+#define SZ_ERROR_DATA 1
+#define SZ_ERROR_MEM 2
+#define SZ_ERROR_CRC 3
+#define SZ_ERROR_UNSUPPORTED 4
+#define SZ_ERROR_PARAM 5
+#define SZ_ERROR_INPUT_EOF 6
+#define SZ_ERROR_OUTPUT_EOF 7
+#define SZ_ERROR_READ 8
+#define SZ_ERROR_WRITE 9
+#define SZ_ERROR_PROGRESS 10
+#define SZ_ERROR_FAIL 11
+#define SZ_ERROR_THREAD 12
+
+#define SZ_ERROR_ARCHIVE 16
+#define SZ_ERROR_NO_ARCHIVE 17
+
+typedef int SRes;
+
+#ifdef _WIN32
+typedef DWORD WRes;
+#else
+typedef int WRes;
+#endif
+
+#ifndef RINOK
+#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
+#endif
+
+typedef unsigned char Byte;
+typedef short Int16;
+typedef unsigned short UInt16;
+
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef long Int32;
+typedef unsigned long UInt32;
+#else
+typedef int Int32;
+typedef unsigned int UInt32;
+#endif
+
+#ifdef _SZ_NO_INT_64
+
+/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
+ NOTES: Some code will work incorrectly in that case! */
+
+typedef long Int64;
+typedef unsigned long UInt64;
+
+#else
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#endif
+
+#endif
+
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+typedef size_t SizeT;
+#endif
+
+typedef int Bool;
+#define True 1
+#define False 0
+
+
+#ifdef _WIN32
+#define MY_STD_CALL __stdcall
+#else
+#define MY_STD_CALL
+#endif
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1300
+#define MY_NO_INLINE __declspec(noinline)
+#else
+#define MY_NO_INLINE
+#endif
+
+#define MY_CDECL __cdecl
+#define MY_FAST_CALL __fastcall
+
+#else
+
+#define MY_CDECL
+#define MY_FAST_CALL
+
+#endif
+
+
+/* The following interfaces use first parameter as pointer to structure */
+
+typedef struct
+{
+ Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */
+} IByteIn;
+
+typedef struct
+{
+ void (*Write)(void *p, Byte b);
+} IByteOut;
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) < input(*size)) is allowed */
+} ISeqInStream;
+
+/* it can return SZ_ERROR_INPUT_EOF */
+SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
+SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
+SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
+
+typedef struct
+{
+ size_t (*Write)(void *p, const void *buf, size_t size);
+ /* Returns: result - the number of actually written bytes.
+ (result < size) means error */
+} ISeqOutStream;
+
+typedef enum
+{
+ SZ_SEEK_SET = 0,
+ SZ_SEEK_CUR = 1,
+ SZ_SEEK_END = 2
+} ESzSeek;
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ISeekInStream;
+
+typedef struct
+{
+ SRes (*Look)(void *p, const void **buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) > input(*size)) is not allowed
+ (output(*size) < input(*size)) is allowed */
+ SRes (*Skip)(void *p, size_t offset);
+ /* offset must be <= output(*size) of Look */
+
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* reads directly (without buffer). It's same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ILookInStream;
+
+SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
+SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
+
+/* reads via ILookInStream::Read */
+SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
+SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
+
+#define LookToRead_BUF_SIZE (1 << 14)
+
+typedef struct
+{
+ ILookInStream s;
+ ISeekInStream *realStream;
+ size_t pos;
+ size_t size;
+ Byte buf[LookToRead_BUF_SIZE];
+} CLookToRead;
+
+void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
+void LookToRead_Init(CLookToRead *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToLook;
+
+void SecToLook_CreateVTable(CSecToLook *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToRead;
+
+void SecToRead_CreateVTable(CSecToRead *p);
+
+typedef struct
+{
+ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
+ /* Returns: result. (result != SZ_OK) means break.
+ Value (UInt64)(Int64)-1 for size means unknown value. */
+} ICompressProgress;
+
+typedef struct
+{
+ void *(*Alloc)(void *p, size_t size);
+ void (*Free)(void *p, void *address); /* address can be 0 */
+} ISzAlloc;
+
+#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
+#define IAlloc_Free(p, a) (p)->Free((p), a)
+
+EXTERN_C_END
+
+#endif
diff --git a/dep/StormLib/src/lzma/info.txt b/dep/StormLib/src/lzma/info.txt
new file mode 100644
index 00000000000..4cee86e3542
--- /dev/null
+++ b/dep/StormLib/src/lzma/info.txt
@@ -0,0 +1 @@
+Taken from LZMA SDK v 9.11 \ No newline at end of file
diff --git a/dep/StormLib/src/pklib/crc32.c b/dep/StormLib/src/pklib/crc32.c
new file mode 100644
index 00000000000..cd47b1d4a9b
--- /dev/null
+++ b/dep/StormLib/src/pklib/crc32.c
@@ -0,0 +1,66 @@
+/*****************************************************************************/
+/* crc32.c Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Pkware Data Compression Library Version 1.11 */
+/* Dissassembled method crc32 - cdecl version */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 09.04.03 1.00 Lad The first version of crc32.c */
+/* 02.05.03 1.00 Lad Stress test done */
+/*****************************************************************************/
+
+#include "pklib.h"
+
+static unsigned long crc_table[] =
+{
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+
+
+unsigned long PKEXPORT crc32_pklib(char * buffer, unsigned int * psize, unsigned long * old_crc)
+{
+ unsigned int size = *psize;
+ unsigned long ch;
+ unsigned long crc_value = *old_crc;
+
+ while(size-- != 0)
+ {
+ ch = *buffer++ ^ (char)crc_value;
+ crc_value >>= 8;
+
+ crc_value = crc_table[ch & 0x0FF] ^ crc_value;
+ }
+ return crc_value;
+}
diff --git a/dep/StormLib/src/pklib/explode.c b/dep/StormLib/src/pklib/explode.c
new file mode 100644
index 00000000000..0d327a5da84
--- /dev/null
+++ b/dep/StormLib/src/pklib/explode.c
@@ -0,0 +1,522 @@
+/*****************************************************************************/
+/* explode.c Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Implode function of PKWARE Data Compression library */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 11.03.03 1.00 Lad Splitted from Pkware.cpp */
+/* 08.04.03 1.01 Lad Renamed to explode.c to be compatible with pklib */
+/* 02.05.03 1.01 Lad Stress test done */
+/* 22.04.10 1.01 Lad Documented */
+/*****************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+
+#include "pklib.h"
+
+#define PKDCL_OK 0
+#define PKDCL_STREAM_END 1 // All data from the input stream is read
+#define PKDCL_NEED_DICT 2 // Need more data (dictionary)
+#define PKDCL_CONTINUE 10 // Internal flag, not returned to user
+#define PKDCL_GET_INPUT 11 // Internal flag, not returned to user
+
+char CopyrightPkware[] = "PKWARE Data Compression Library for Win32\r\n"
+ "Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n"
+ "Patent No. 5,051,745\r\n"
+ "PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n"
+ "Version 1.11\r\n";
+
+//-----------------------------------------------------------------------------
+// Tables
+
+static unsigned char DistBits[] =
+{
+ 0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
+};
+
+static unsigned char DistCode[] =
+{
+ 0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A,
+ 0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C,
+ 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
+ 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00
+};
+
+static unsigned char ExLenBits[] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
+};
+
+static unsigned short LenBase[] =
+{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x000A, 0x000E, 0x0016, 0x0026, 0x0046, 0x0086, 0x0106
+};
+
+static unsigned char LenBits[] =
+{
+ 0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07
+};
+
+static unsigned char LenCode[] =
+{
+ 0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00
+};
+
+static unsigned char ChBitsAsc[] =
+{
+ 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08,
+ 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B,
+ 0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06,
+ 0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08,
+ 0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05,
+ 0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C,
+ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D,
+ 0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D
+};
+
+static unsigned short ChCodeAsc[] =
+{
+ 0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0,
+ 0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0,
+ 0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360,
+ 0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60,
+ 0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8,
+ 0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098,
+ 0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C,
+ 0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710,
+ 0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8,
+ 0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E,
+ 0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8,
+ 0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088,
+ 0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A,
+ 0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D,
+ 0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078,
+ 0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0,
+ 0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040,
+ 0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380,
+ 0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180,
+ 0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280,
+ 0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080,
+ 0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300,
+ 0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0,
+ 0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320,
+ 0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220,
+ 0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0,
+ 0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0,
+ 0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340,
+ 0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900,
+ 0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600,
+ 0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200,
+ 0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000
+};
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static void GenDecodeTabs(
+ unsigned char * positions, // [out] Table of positions
+ unsigned char * start_indexes, // [in] Table of start indexes
+ unsigned char * length_bits, // [in] Table of lengths. Each length is stored as number of bits
+ size_t elements) // [in] Number of elements in start_indexes and length_bits
+{
+ unsigned long index;
+ unsigned long length;
+ size_t i;
+
+ for(i = 0; i < elements; i++)
+ {
+ length = 1 << length_bits[i]; // Get the length in bytes
+
+ for(index = start_indexes[i]; index < 0x100; index += length)
+ {
+ positions[index] = (unsigned char)i;
+ }
+ }
+}
+
+static void GenAscTabs(TDcmpStruct * pWork)
+{
+ unsigned short * pChCodeAsc = &ChCodeAsc[0xFF];
+ unsigned long acc, add;
+ unsigned short count;
+
+ for(count = 0x00FF; pChCodeAsc >= ChCodeAsc; pChCodeAsc--, count--)
+ {
+ unsigned char * pChBitsAsc = pWork->ChBitsAsc + count;
+ unsigned char bits_asc = *pChBitsAsc;
+
+ if(bits_asc <= 8)
+ {
+ add = (1 << bits_asc);
+ acc = *pChCodeAsc;
+
+ do
+ {
+ pWork->offs2C34[acc] = (unsigned char)count;
+ acc += add;
+ }
+ while(acc < 0x100);
+ }
+ else if((acc = (*pChCodeAsc & 0xFF)) != 0)
+ {
+ pWork->offs2C34[acc] = 0xFF;
+
+ if(*pChCodeAsc & 0x3F)
+ {
+ bits_asc -= 4;
+ *pChBitsAsc = bits_asc;
+
+ add = (1 << bits_asc);
+ acc = *pChCodeAsc >> 4;
+ do
+ {
+ pWork->offs2D34[acc] = (unsigned char)count;
+ acc += add;
+ }
+ while(acc < 0x100);
+ }
+ else
+ {
+ bits_asc -= 6;
+ *pChBitsAsc = bits_asc;
+
+ add = (1 << bits_asc);
+ acc = *pChCodeAsc >> 6;
+ do
+ {
+ pWork->offs2E34[acc] = (unsigned char)count;
+ acc += add;
+ }
+ while(acc < 0x80);
+ }
+ }
+ else
+ {
+ bits_asc -= 8;
+ *pChBitsAsc = bits_asc;
+
+ add = (1 << bits_asc);
+ acc = *pChCodeAsc >> 8;
+ do
+ {
+ pWork->offs2EB4[acc] = (unsigned char)count;
+ acc += add;
+ }
+ while(acc < 0x100);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Removes given number of bits in the bit buffer. New bits are reloaded from
+// the input buffer, if needed.
+// Returns: PKDCL_OK: Operation was successful
+// PKDCL_STREAM_END: There are no more bits in the input buffer
+
+static int WasteBits(TDcmpStruct * pWork, unsigned long nBits)
+{
+ // If number of bits required is less than number of (bits in the buffer) ?
+ if(nBits <= pWork->extra_bits)
+ {
+ pWork->extra_bits -= nBits;
+ pWork->bit_buff >>= nBits;
+ return PKDCL_OK;
+ }
+
+ // Load input buffer if necessary
+ pWork->bit_buff >>= pWork->extra_bits;
+ if(pWork->in_pos == pWork->in_bytes)
+ {
+ pWork->in_pos = sizeof(pWork->in_buff);
+ if((pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param)) == 0)
+ return PKDCL_STREAM_END;
+ pWork->in_pos = 0;
+ }
+
+ // Update bit buffer
+ pWork->bit_buff |= (pWork->in_buff[pWork->in_pos++] << 8);
+ pWork->bit_buff >>= (nBits - pWork->extra_bits);
+ pWork->extra_bits = (pWork->extra_bits - nBits) + 8;
+ return PKDCL_OK;
+}
+
+//-----------------------------------------------------------------------------
+// Decodes next literal from the input (compressed) data.
+// Returns : 0x000: One byte 0x00
+// 0x001: One byte 0x01
+// ...
+// 0x0FF: One byte 0xFF
+// 0x100: Repetition, length of 0x02 bytes
+// 0x101: Repetition, length of 0x03 bytes
+// ...
+// 0x304: Repetition, length of 0x206 bytes
+// 0x305: End of stream
+// 0x306: Error
+
+static unsigned long DecodeLit(TDcmpStruct * pWork)
+{
+ unsigned long extra_length_bits; // Number of bits of extra literal length
+ unsigned long length_code; // Length code
+ unsigned long value;
+
+ // Test the current bit in byte buffer. If is not set, simply return the next 8 bits.
+ if(pWork->bit_buff & 1)
+ {
+ // Remove one bit from the input data
+ if(WasteBits(pWork, 1))
+ return 0x306;
+
+ // The next 8 bits hold the index to the length code table
+ length_code = pWork->LengthCodes[pWork->bit_buff & 0xFF];
+
+ // Remove the apropriate number of bits
+ if(WasteBits(pWork, pWork->LenBits[length_code]))
+ return 0x306;
+
+ // Are there some extra bits for the obtained length code ?
+ if((extra_length_bits = pWork->ExLenBits[length_code]) != 0)
+ {
+ unsigned long extra_length = pWork->bit_buff & ((1 << extra_length_bits) - 1);
+
+ if(WasteBits(pWork, extra_length_bits))
+ {
+ if((length_code + extra_length) != 0x10E)
+ return 0x306;
+ }
+ length_code = pWork->LenBase[length_code] + extra_length;
+ }
+
+ // In order to distinguish uncompressed byte from repetition length,
+ // we have to add 0x100 to the length.
+ return length_code + 0x100;
+ }
+
+ // Remove one bit from the input data
+ if(WasteBits(pWork, 1))
+ return 0x306;
+
+ // If the binary compression type, read 8 bits and return them as one byte.
+ if(pWork->ctype == CMP_BINARY)
+ {
+ unsigned long uncompressed_byte = pWork->bit_buff & 0xFF;
+
+ if(WasteBits(pWork, 8))
+ return 0x306;
+ return uncompressed_byte;
+ }
+
+ // When ASCII compression ...
+ if(pWork->bit_buff & 0xFF)
+ {
+ value = pWork->offs2C34[pWork->bit_buff & 0xFF];
+
+ if(value == 0xFF)
+ {
+ if(pWork->bit_buff & 0x3F)
+ {
+ if(WasteBits(pWork, 4))
+ return 0x306;
+
+ value = pWork->offs2D34[pWork->bit_buff & 0xFF];
+ }
+ else
+ {
+ if(WasteBits(pWork, 6))
+ return 0x306;
+
+ value = pWork->offs2E34[pWork->bit_buff & 0x7F];
+ }
+ }
+ }
+ else
+ {
+ if(WasteBits(pWork, 8))
+ return 0x306;
+
+ value = pWork->offs2EB4[pWork->bit_buff & 0xFF];
+ }
+
+ return WasteBits(pWork, pWork->ChBitsAsc[value]) ? 0x306 : value;
+}
+
+//-----------------------------------------------------------------------------
+// Decodes the distance of the repetition, backwards relative to the
+// current output buffer position
+
+static unsigned long DecodeDist(TDcmpStruct * pWork, unsigned long rep_length)
+{
+ unsigned long dist_pos_code; // Distance position code
+ unsigned long dist_pos_bits; // Number of bits of distance position
+ unsigned long distance; // Distance position
+
+ // Next 2-8 bits in the input buffer is the distance position code
+ dist_pos_code = pWork->DistPosCodes[pWork->bit_buff & 0xFF];
+ dist_pos_bits = pWork->DistBits[dist_pos_code];
+ if(WasteBits(pWork, dist_pos_bits))
+ return 0;
+
+ if(rep_length == 2)
+ {
+ // If the repetition is only 2 bytes length,
+ // then take 2 bits from the stream in order to get the distance
+ distance = (dist_pos_code << 2) | (pWork->bit_buff & 0x03);
+ if(WasteBits(pWork, 2))
+ return 0;
+ }
+ else
+ {
+ // If the repetition is more than 2 bytes length,
+ // then take "dsize_bits" bits in order to get the distance
+ distance = (dist_pos_code << pWork->dsize_bits) | (pWork->bit_buff & pWork->dsize_mask);
+ if(WasteBits(pWork, pWork->dsize_bits))
+ return 0;
+ }
+ return distance + 1;
+}
+
+static unsigned long Expand(TDcmpStruct * pWork)
+{
+ unsigned long next_literal; // Literal decoded from the compressed data
+ unsigned long result; // Value to be returned
+ unsigned int copyBytes; // Number of bytes to copy to the output buffer
+
+ pWork->outputPos = 0x1000; // Initialize output buffer position
+
+ // Decode the next literal from the input data.
+ // The returned literal can either be an uncompressed byte (next_literal < 0x100)
+ // or an encoded length of the repeating byte sequence that
+ // is to be copied to the current buffer position
+ while((result = next_literal = DecodeLit(pWork)) < 0x305)
+ {
+ // If the literal is greater than 0x100, it holds length
+ // of repeating byte sequence
+ // literal of 0x100 means repeating sequence of 0x2 bytes
+ // literal of 0x101 means repeating sequence of 0x3 bytes
+ // ...
+ // literal of 0x305 means repeating sequence of 0x207 bytes
+ if(next_literal >= 0x100)
+ {
+ unsigned char * source;
+ unsigned char * target;
+ unsigned long rep_length; // Length of the repetition, in bytes
+ unsigned long minus_dist; // Backward distance to the repetition, relative to the current buffer position
+
+ // Get the length of the repeating sequence.
+ // Note that the repeating block may overlap the current output position,
+ // for example if there was a sequence of equal bytes
+ rep_length = next_literal - 0xFE;
+
+ // Get backward distance to the repetition
+ if((minus_dist = DecodeDist(pWork, rep_length)) == 0)
+ {
+ result = 0x306;
+ break;
+ }
+
+ // Target and source pointer
+ target = &pWork->out_buff[pWork->outputPos];
+ source = target - minus_dist;
+
+ // Update buffer output position
+ pWork->outputPos += rep_length;
+
+ // Copy the repeating sequence
+ while(rep_length-- > 0)
+ *target++ = *source++;
+ }
+ else
+ {
+ pWork->out_buff[pWork->outputPos++] = (unsigned char)next_literal;
+ }
+
+ // Flush the output buffer, if number of extracted bytes has reached the end
+ if(pWork->outputPos >= 0x2000)
+ {
+ // Copy decompressed data into user buffer
+ copyBytes = 0x1000;
+ pWork->write_buf((char *)&pWork->out_buff[0x1000], &copyBytes, pWork->param);
+
+ // Now copy the decompressed data to the first half of the buffer.
+ // This is needed because the decompression might reuse them as repetitions.
+ // Note that if the output buffer overflowed previously, the extra decompressed bytes
+ // are stored in "out_buff_overflow", and they will now be
+ // within decompressed part of the output buffer.
+ memcpy(pWork->out_buff, &pWork->out_buff[0x1000], pWork->outputPos - 0x1000);
+ pWork->outputPos -= 0x1000;
+ }
+ }
+
+ // Flush any remaining decompressed bytes
+ copyBytes = pWork->outputPos - 0x1000;
+ pWork->write_buf((char *)&pWork->out_buff[0x1000], &copyBytes, pWork->param);
+ return result;
+}
+
+
+//-----------------------------------------------------------------------------
+// Main exploding function.
+
+unsigned int explode(
+ unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
+ void (*write_buf)(char *buf, unsigned int *size, void *param),
+ char *work_buf,
+ void *param)
+{
+ TDcmpStruct * pWork = (TDcmpStruct *)work_buf;
+
+ // Initialize work struct and load compressed data
+ // Note: The caller must zero the "work_buff" before passing it to explode
+ pWork->read_buf = read_buf;
+ pWork->write_buf = write_buf;
+ pWork->param = param;
+ pWork->in_pos = sizeof(pWork->in_buff);
+ pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param);
+ if(pWork->in_bytes <= 4)
+ return CMP_BAD_DATA;
+
+ pWork->ctype = pWork->in_buff[0]; // Get the compression type (CMP_BINARY or CMP_ASCII)
+ pWork->dsize_bits = pWork->in_buff[1]; // Get the dictionary size
+ pWork->bit_buff = pWork->in_buff[2]; // Initialize 16-bit bit buffer
+ pWork->extra_bits = 0; // Extra (over 8) bits
+ pWork->in_pos = 3; // Position in input buffer
+
+ // Test for the valid dictionary size
+ if(4 > pWork->dsize_bits || pWork->dsize_bits > 6)
+ return CMP_INVALID_DICTSIZE;
+
+ pWork->dsize_mask = 0xFFFF >> (0x10 - pWork->dsize_bits); // Shifted by 'sar' instruction
+
+ if(pWork->ctype != CMP_BINARY)
+ {
+ if(pWork->ctype != CMP_ASCII)
+ return CMP_INVALID_MODE;
+
+ memcpy(pWork->ChBitsAsc, ChBitsAsc, sizeof(pWork->ChBitsAsc));
+ GenAscTabs(pWork);
+ }
+
+ memcpy(pWork->LenBits, LenBits, sizeof(pWork->LenBits));
+ GenDecodeTabs(pWork->LengthCodes, LenCode, pWork->LenBits, sizeof(pWork->LenBits));
+ memcpy(pWork->ExLenBits, ExLenBits, sizeof(pWork->ExLenBits));
+ memcpy(pWork->LenBase, LenBase, sizeof(pWork->LenBase));
+ memcpy(pWork->DistBits, DistBits, sizeof(pWork->DistBits));
+ GenDecodeTabs(pWork->DistPosCodes, DistCode, pWork->DistBits, sizeof(pWork->DistBits));
+ if(Expand(pWork) != 0x306)
+ return CMP_NO_ERROR;
+
+ return CMP_ABORT;
+}
diff --git a/dep/StormLib/src/pklib/implode.c b/dep/StormLib/src/pklib/implode.c
new file mode 100644
index 00000000000..1771b1862a0
--- /dev/null
+++ b/dep/StormLib/src/pklib/implode.c
@@ -0,0 +1,769 @@
+/*****************************************************************************/
+/* implode.c Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Implode function of PKWARE Data Compression library */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 11.04.03 1.00 Lad First version of implode.c */
+/* 02.05.03 1.00 Lad Stress test done */
+/* 22.04.10 1.01 Lad Documented */
+/*****************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+
+#include "pklib.h"
+
+#if ((1200 < _MSC_VER) && (_MSC_VER < 1400))
+#pragma optimize("", off) // Fucking Microsoft VS.NET 2003 compiler !!! (_MSC_VER=1310)
+#endif
+
+//-----------------------------------------------------------------------------
+// Defines
+
+#define MAX_REP_LENGTH 0x204 // The longest allowed repetition
+
+//-----------------------------------------------------------------------------
+// Tables
+
+static unsigned char DistBits[] =
+{
+ 0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
+};
+
+static unsigned char DistCode[] =
+{
+ 0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A,
+ 0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C,
+ 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
+ 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00
+};
+
+static unsigned char ExLenBits[] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
+};
+
+static unsigned char LenBits[] =
+{
+ 0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07
+};
+
+static unsigned char LenCode[] =
+{
+ 0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00
+};
+
+static unsigned char ChBitsAsc[] =
+{
+ 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08,
+ 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B,
+ 0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06,
+ 0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08,
+ 0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05,
+ 0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C,
+ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D,
+ 0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D
+};
+
+static unsigned short ChCodeAsc[] =
+{
+ 0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0,
+ 0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0,
+ 0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360,
+ 0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60,
+ 0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8,
+ 0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098,
+ 0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C,
+ 0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710,
+ 0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8,
+ 0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E,
+ 0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8,
+ 0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088,
+ 0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A,
+ 0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D,
+ 0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078,
+ 0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0,
+ 0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040,
+ 0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380,
+ 0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180,
+ 0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280,
+ 0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080,
+ 0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300,
+ 0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0,
+ 0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320,
+ 0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220,
+ 0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0,
+ 0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0,
+ 0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340,
+ 0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900,
+ 0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600,
+ 0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200,
+ 0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000
+};
+
+//-----------------------------------------------------------------------------
+// Macros
+
+// Macro for calculating hash of the current byte pair.
+// Note that most exact byte pair hash would be buffer[0] + buffer[1] << 0x08,
+// but even this way gives nice indication of equal byte pairs, with significantly
+// smaller size of the array that holds numbers of those hashes
+#define BYTE_PAIR_HASH(buffer) ((buffer[0] * 4) + (buffer[1] * 5))
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+// Builds the "hash_to_index" table and "pair_hash_offsets" table.
+// Every element of "hash_to_index" will contain lowest index to the
+// "pair_hash_offsets" table, effectively giving offset of the first
+// occurence of the given PAIR_HASH in the input data.
+static void SortBuffer(TCmpStruct * pWork, unsigned char * buffer_begin, unsigned char * buffer_end)
+{
+ unsigned short * phash_to_index;
+ unsigned char * buffer_ptr;
+ unsigned short total_sum = 0;
+ unsigned long byte_pair_hash; // Hash value of the byte pair
+ unsigned short byte_pair_offs; // Offset of the byte pair, relative to "work_buff"
+
+ // Zero the entire "phash_to_index" table
+ memset(pWork->phash_to_index, 0, sizeof(pWork->phash_to_index));
+
+ // Step 1: Count amount of each PAIR_HASH in the input buffer
+ // The table will look like this:
+ // offs 0x000: Number of occurences of PAIR_HASH 0
+ // offs 0x001: Number of occurences of PAIR_HASH 1
+ // ...
+ // offs 0x8F7: Number of occurences of PAIR_HASH 0x8F7 (the highest hash value)
+ for(buffer_ptr = buffer_begin; buffer_ptr < buffer_end; buffer_ptr++)
+ pWork->phash_to_index[BYTE_PAIR_HASH(buffer_ptr)]++;
+
+ // Step 2: Convert the table to the array of PAIR_HASH amounts.
+ // Each element contains count of PAIR_HASHes that is less or equal
+ // to element index
+ // The table will look like this:
+ // offs 0x000: Number of occurences of PAIR_HASH 0 or lower
+ // offs 0x001: Number of occurences of PAIR_HASH 1 or lower
+ // ...
+ // offs 0x8F7: Number of occurences of PAIR_HASH 0x8F7 or lower
+ for(phash_to_index = pWork->phash_to_index; phash_to_index < &pWork->phash_to_index_end; phash_to_index++)
+ {
+ total_sum = total_sum + phash_to_index[0];
+ phash_to_index[0] = total_sum;
+ }
+
+ // Step 3: Convert the table to the array of indexes.
+ // Now, each element contains index to the first occurence of given PAIR_HASH
+ for(buffer_end--; buffer_end >= buffer_begin; buffer_end--)
+ {
+ byte_pair_hash = BYTE_PAIR_HASH(buffer_end);
+ byte_pair_offs = (unsigned short)(buffer_end - pWork->work_buff);
+
+ pWork->phash_to_index[byte_pair_hash]--;
+ pWork->phash_offs[pWork->phash_to_index[byte_pair_hash]] = byte_pair_offs;
+ }
+}
+
+static void FlushBuf(TCmpStruct * pWork)
+{
+ unsigned char save_ch1;
+ unsigned char save_ch2;
+ unsigned int size = 0x800;
+
+ pWork->write_buf(pWork->out_buff, &size, pWork->param);
+
+ save_ch1 = pWork->out_buff[0x800];
+ save_ch2 = pWork->out_buff[pWork->out_bytes];
+ pWork->out_bytes -= 0x800;
+
+ memset(pWork->out_buff, 0, sizeof(pWork->out_buff));
+
+ if(pWork->out_bytes != 0)
+ pWork->out_buff[0] = save_ch1;
+ if(pWork->out_bits != 0)
+ pWork->out_buff[pWork->out_bytes] = save_ch2;
+}
+
+static void OutputBits(TCmpStruct * pWork, unsigned int nbits, unsigned long bit_buff)
+{
+ unsigned int out_bits;
+
+ // If more than 8 bits to output, do recursion
+ if(nbits > 8)
+ {
+ OutputBits(pWork, 8, bit_buff);
+ bit_buff >>= 8;
+ nbits -= 8;
+ }
+
+ // Add bits to the last out byte in out_buff;
+ out_bits = pWork->out_bits;
+ pWork->out_buff[pWork->out_bytes] |= (unsigned char)(bit_buff << out_bits);
+ pWork->out_bits += nbits;
+
+ // If 8 or more bits, increment number of bytes
+ if(pWork->out_bits > 8)
+ {
+ pWork->out_bytes++;
+ bit_buff >>= (8 - out_bits);
+
+ pWork->out_buff[pWork->out_bytes] = (unsigned char)bit_buff;
+ pWork->out_bits &= 7;
+ }
+ else
+ {
+ pWork->out_bits &= 7;
+ if(pWork->out_bits == 0)
+ pWork->out_bytes++;
+ }
+
+ // If there is enough compressed bytes, flush them
+ if(pWork->out_bytes >= 0x800)
+ FlushBuf(pWork);
+}
+
+// This function searches for a repetition
+// (a previous occurence of the current byte sequence)
+// Returns length of the repetition, and stores the backward distance
+// to pWork structure.
+static unsigned int FindRep(TCmpStruct * pWork, unsigned char * input_data)
+{
+ unsigned short * phash_to_index; // Pointer into pWork->phash_to_index table
+ unsigned short * phash_offs; // Pointer to the table containing offsets of each PAIR_HASH
+ unsigned char * repetition_limit; // An eventual repetition must be at position below this pointer
+ unsigned char * prev_repetition; // Pointer to the previous occurence of the current PAIR_HASH
+ unsigned char * prev_rep_end; // End of the previous repetition
+ unsigned char * input_data_ptr;
+ unsigned short phash_offs_index; // Index to the table with PAIR_HASH positions
+ unsigned short min_phash_offs; // The lowest allowed hash offset
+ unsigned short offs_in_rep; // Offset within found repetition
+ unsigned int equal_byte_count; // Number of bytes that are equal to the previous occurence
+ unsigned int rep_length = 1; // Length of the found repetition
+ unsigned int rep_length2; // Secondary repetition
+ unsigned char pre_last_byte; // Last but one byte from a repetion
+ unsigned short di_val;
+
+ // Calculate the previous position of the PAIR_HASH
+ phash_to_index = pWork->phash_to_index + BYTE_PAIR_HASH(input_data);
+ min_phash_offs = (unsigned short)((input_data - pWork->work_buff) - pWork->dsize_bytes + 1);
+ phash_offs_index = phash_to_index[0];
+
+ // If the PAIR_HASH offset is below the limit, find a next one
+ phash_offs = pWork->phash_offs + phash_offs_index;
+ if(*phash_offs < min_phash_offs)
+ {
+ while(*phash_offs < min_phash_offs)
+ {
+ phash_offs_index++;
+ phash_offs++;
+ }
+ *phash_to_index = phash_offs_index;
+ }
+
+ // Get the first location of the PAIR_HASH,
+ // and thus the first eventual location of byte repetition
+ phash_offs = pWork->phash_offs + phash_offs_index;
+ prev_repetition = pWork->work_buff + phash_offs[0];
+ repetition_limit = input_data - 1;
+
+ // If the current PAIR_HASH was not encountered before,
+ // we haven't found a repetition.
+ if(prev_repetition >= repetition_limit)
+ return 0;
+
+ // We have found a match of a PAIR_HASH. Now we have to make sure
+ // that it is also a byte match, because PAIR_HASH is not unique.
+ // We compare the bytes and count the length of the repetition
+ input_data_ptr = input_data;
+ for(;;)
+ {
+ // If the first byte of the repetition and the so-far-last byte
+ // of the repetition are equal, we will compare the blocks.
+ if(*input_data_ptr == *prev_repetition && input_data_ptr[rep_length-1] == prev_repetition[rep_length-1])
+ {
+ // Skip the current byte
+ prev_repetition++;
+ input_data_ptr++;
+ equal_byte_count = 2;
+
+ // Now count how many more bytes are equal
+ while(equal_byte_count < MAX_REP_LENGTH)
+ {
+ prev_repetition++;
+ input_data_ptr++;
+
+ // Are the bytes different ?
+ if(*prev_repetition != *input_data_ptr)
+ break;
+
+ equal_byte_count++;
+ }
+
+ // If we found a repetition of at least the same length, take it.
+ // If there are multiple repetitions in the input buffer, this will
+ // make sure that we find the most recent one, which in turn allows
+ // us to store backward length in less amount of bits
+ input_data_ptr = input_data;
+ if(equal_byte_count >= rep_length)
+ {
+ // Calculate the backward distance of the repetition.
+ // Note that the distance is stored as decremented by 1
+ pWork->distance = (unsigned int)(input_data - prev_repetition + equal_byte_count - 1);
+
+ // Repetitions longer than 10 bytes will be stored in more bits,
+ // so they need a bit different handling
+ if((rep_length = equal_byte_count) > 10)
+ break;
+ }
+ }
+
+ // Move forward in the table of PAIR_HASH repetitions.
+ // There might be a more recent occurence of the same repetition.
+ phash_offs_index++;
+ phash_offs++;
+ prev_repetition = pWork->work_buff + phash_offs[0];
+
+ // If the next repetition is beyond the minimum allowed repetition, we are done.
+ if(prev_repetition >= repetition_limit)
+ {
+ // A repetition must have at least 2 bytes, otherwise it's not worth it
+ return (rep_length >= 2) ? rep_length : 0;
+ }
+ }
+
+ // If the repetition has max length of 0x204 bytes, we can't go any fuhrter
+ if(equal_byte_count == MAX_REP_LENGTH)
+ {
+ pWork->distance--;
+ return equal_byte_count;
+ }
+
+ // Check for possibility of a repetition that occurs at more recent position
+ phash_offs = pWork->phash_offs + phash_offs_index;
+ if(pWork->work_buff + phash_offs[1] >= repetition_limit)
+ return rep_length;
+
+ //
+ // The following part checks if there isn't a longer repetition at
+ // a latter offset, that would lead to better compression.
+ //
+ // Example of data that can trigger this optimization:
+ //
+ // "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEQQQQQQQQQQQQ"
+ // "XYZ"
+ // "EEEEEEEEEEEEEEEEQQQQQQQQQQQQ";
+ //
+ // Description of data in this buffer
+ // [0x00] Single byte "E"
+ // [0x01] Single byte "E"
+ // [0x02] Repeat 0x1E bytes from [0x00]
+ // [0x20] Single byte "X"
+ // [0x21] Single byte "Y"
+ // [0x22] Single byte "Z"
+ // [0x23] 17 possible previous repetitions of length at least 0x10 bytes:
+ // - Repetition of 0x10 bytes from [0x00] "EEEEEEEEEEEEEEEE"
+ // - Repetition of 0x10 bytes from [0x01] "EEEEEEEEEEEEEEEE"
+ // - Repetition of 0x10 bytes from [0x02] "EEEEEEEEEEEEEEEE"
+ // ...
+ // - Repetition of 0x10 bytes from [0x0F] "EEEEEEEEEEEEEEEE"
+ // - Repetition of 0x1C bytes from [0x10] "EEEEEEEEEEEEEEEEQQQQQQQQQQQQ"
+ // The last repetition is the best one.
+ //
+
+ pWork->offs09BC[0] = 0xFFFF;
+ pWork->offs09BC[1] = 0x0000;
+ di_val = 0;
+
+ // Note: I failed to figure out what does the table "offs09BC" mean.
+ // If anyone has an idea, let me know to zezula_at_volny_dot_cz
+ for(offs_in_rep = 1; offs_in_rep < rep_length; )
+ {
+ if(input_data[offs_in_rep] != input_data[di_val])
+ {
+ di_val = pWork->offs09BC[di_val];
+ if(di_val != 0xFFFF)
+ continue;
+ }
+ pWork->offs09BC[++offs_in_rep] = ++di_val;
+ }
+
+ //
+ // Now go through all the repetitions from the first found one
+ // to the current input data, and check if any of them migh be
+ // a start of a greater sequence match.
+ //
+
+ prev_repetition = pWork->work_buff + phash_offs[0];
+ prev_rep_end = prev_repetition + rep_length;
+ rep_length2 = rep_length;
+
+ for(;;)
+ {
+ rep_length2 = pWork->offs09BC[rep_length2];
+ if(rep_length2 == 0xFFFF)
+ rep_length2 = 0;
+
+ // Get the pointer to the previous repetition
+ phash_offs = pWork->phash_offs + phash_offs_index;
+
+ // Skip those repetitions that don't reach the end
+ // of the first found repetition
+ do
+ {
+ phash_offs++;
+ phash_offs_index++;
+ prev_repetition = pWork->work_buff + *phash_offs;
+ if(prev_repetition >= repetition_limit)
+ return rep_length;
+ }
+ while(prev_repetition + rep_length2 < prev_rep_end);
+
+ // Verify if the last but one byte from the repetition matches
+ // the last but one byte from the input data.
+ // If not, find a next repetition
+ pre_last_byte = input_data[rep_length - 2];
+ if(pre_last_byte == prev_repetition[rep_length - 2])
+ {
+ // If the new repetition reaches beyond the end
+ // of previously found repetition, reset the repetition length to zero.
+ if(prev_repetition + rep_length2 != prev_rep_end)
+ {
+ prev_rep_end = prev_repetition;
+ rep_length2 = 0;
+ }
+ }
+ else
+ {
+ phash_offs = pWork->phash_offs + phash_offs_index;
+ do
+ {
+ phash_offs++;
+ phash_offs_index++;
+ prev_repetition = pWork->work_buff + *phash_offs;
+ if(prev_repetition >= repetition_limit)
+ return rep_length;
+ }
+ while(prev_repetition[rep_length - 2] != pre_last_byte || prev_repetition[0] != input_data[0]);
+
+ // Reset the length of the repetition to 2 bytes only
+ prev_rep_end = prev_repetition + 2;
+ rep_length2 = 2;
+ }
+
+ // Find out how many more characters are equal to the first repetition.
+ while(*prev_rep_end == input_data[rep_length2])
+ {
+ if(++rep_length2 >= 0x204)
+ break;
+ prev_rep_end++;
+ }
+
+ // Is the newly found repetion at least as long as the previous one ?
+ if(rep_length2 >= rep_length)
+ {
+ // Calculate the distance of the new repetition
+ pWork->distance = (unsigned int)(input_data - prev_repetition - 1);
+ if((rep_length = rep_length2) == 0x204)
+ return rep_length;
+
+ // Update the additional elements in the "offs09BC" table
+ // to reflect new rep length
+ while(offs_in_rep < rep_length2)
+ {
+ if(input_data[offs_in_rep] != input_data[di_val])
+ {
+ di_val = pWork->offs09BC[di_val];
+ if(di_val != 0xFFFF)
+ continue;
+ }
+ pWork->offs09BC[++offs_in_rep] = ++di_val;
+ }
+ }
+ }
+}
+
+static void WriteCmpData(TCmpStruct * pWork)
+{
+ unsigned char * input_data_end; // Pointer to the end of the input data
+ unsigned char * input_data = pWork->work_buff + pWork->dsize_bytes + 0x204;
+ unsigned int input_data_ended = 0; // If 1, then all data from the input stream have been already loaded
+ unsigned int save_rep_length; // Saved length of current repetition
+ unsigned int save_distance = 0; // Saved distance of current repetition
+ unsigned int rep_length; // Length of the found repetition
+ unsigned int phase = 0; //
+
+ // Store the compression type and dictionary size
+ pWork->out_buff[0] = (char)pWork->ctype;
+ pWork->out_buff[1] = (char)pWork->dsize_bits;
+ pWork->out_bytes = 2;
+
+ // Reset output buffer to zero
+ memset(&pWork->out_buff[2], 0, sizeof(pWork->out_buff) - 2);
+ pWork->out_bits = 0;
+
+ while(input_data_ended == 0)
+ {
+ unsigned int bytes_to_load = 0x1000;
+ int total_loaded = 0;
+ int bytes_loaded;
+
+ // Load the bytes from the input stream, up to 0x1000 bytes
+ while(bytes_to_load != 0)
+ {
+ bytes_loaded = pWork->read_buf((char *)pWork->work_buff + pWork->dsize_bytes + 0x204 + total_loaded,
+ &bytes_to_load,
+ pWork->param);
+ if(bytes_loaded == 0)
+ {
+ if(total_loaded == 0 && phase == 0)
+ goto __Exit;
+ input_data_ended = 1;
+ break;
+ }
+ else
+ {
+ bytes_to_load -= bytes_loaded;
+ total_loaded += bytes_loaded;
+ }
+ }
+
+ input_data_end = pWork->work_buff + pWork->dsize_bytes + total_loaded;
+ if(input_data_ended)
+ input_data_end += 0x204;
+
+ //
+ // Warning: The end of the buffer passed to "SortBuffer" is actually 2 bytes beyond
+ // valid data. It is questionable if this is actually a bug or not,
+ // but it might cause the compressed data output to be dependent on random bytes
+ // that are in the buffer.
+ // To prevent that, the calling application must always zero the compression
+ // buffer before passing it to "implode"
+ //
+
+ // Search the PAIR_HASHes of the loaded blocks. Also, include
+ // previously compressed data, if any.
+ switch(phase)
+ {
+ case 0:
+ SortBuffer(pWork, input_data, input_data_end + 1);
+ phase++;
+ if(pWork->dsize_bytes != 0x1000)
+ phase++;
+ break;
+
+ case 1:
+ SortBuffer(pWork, input_data - pWork->dsize_bytes + 0x204, input_data_end + 1);
+ phase++;
+ break;
+
+ default:
+ SortBuffer(pWork, input_data - pWork->dsize_bytes, input_data_end + 1);
+ break;
+ }
+
+ // Perform the compression of the current block
+ while(input_data < input_data_end)
+ {
+ // Find if the current byte sequence wasn't there before.
+ rep_length = FindRep(pWork, input_data);
+ while(rep_length != 0)
+ {
+ // If we found repetition of 2 bytes, that is 0x100 or fuhrter back,
+ // don't bother. Storing the distance of 0x100 bytes would actually
+ // take more space than storing the 2 bytes as-is.
+ if(rep_length == 2 && pWork->distance >= 0x100)
+ break;
+
+ // When we are at the end of the input data, we cannot allow
+ // the repetition to go past the end of the input data.
+ if(input_data_ended && input_data + rep_length > input_data_end)
+ {
+ // Shorten the repetition length so that it only covers valid data
+ rep_length = (unsigned long)(input_data_end - input_data);
+ if(rep_length < 2)
+ break;
+
+ // If we got repetition of 2 bytes, that is 0x100 or more backward, don't bother
+ if(rep_length == 2 && pWork->distance >= 0x100)
+ break;
+ goto __FlushRepetition;
+ }
+
+ if(rep_length >= 8 || input_data + 1 >= input_data_end)
+ goto __FlushRepetition;
+
+ // Try to find better repetition 1 byte later.
+ // Example: "ARROCKFORT" "AROCKFORT"
+ // When "input_data" points to the second string, FindRep
+ // returns the occurence of "AR". But there is longer repetition "ROCKFORT",
+ // beginning 1 byte after.
+ save_rep_length = rep_length;
+ save_distance = pWork->distance;
+ rep_length = FindRep(pWork, input_data + 1);
+
+ // Only use the new repetition if it's length is greater than the previous one
+ if(rep_length > save_rep_length)
+ {
+ // If the new repetition if only 1 byte better
+ // and the previous distance is less than 0x80 bytes, use the previous repetition
+ if(rep_length > save_rep_length + 1 || save_distance > 0x80)
+ {
+ // Flush one byte, so that input_data will point to the secondary repetition
+ OutputBits(pWork, pWork->nChBits[*input_data], pWork->nChCodes[*input_data]);
+ input_data++;
+ continue;
+ }
+ }
+
+ // Revert to the previous repetition
+ rep_length = save_rep_length;
+ pWork->distance = save_distance;
+
+ __FlushRepetition:
+
+ OutputBits(pWork, pWork->nChBits[rep_length + 0xFE], pWork->nChCodes[rep_length + 0xFE]);
+ if(rep_length == 2)
+ {
+ OutputBits(pWork, pWork->dist_bits[pWork->distance >> 2],
+ pWork->dist_codes[pWork->distance >> 2]);
+ OutputBits(pWork, 2, pWork->distance & 3);
+ }
+ else
+ {
+ OutputBits(pWork, pWork->dist_bits[pWork->distance >> pWork->dsize_bits],
+ pWork->dist_codes[pWork->distance >> pWork->dsize_bits]);
+ OutputBits(pWork, pWork->dsize_bits, pWork->dsize_mask & pWork->distance);
+ }
+
+ // Move the begin of the input data by the length of the repetition
+ input_data += rep_length;
+ goto _00402252;
+ }
+
+ // If there was no previous repetition for the current position in the input data,
+ // just output the 9-bit literal for the one character
+ OutputBits(pWork, pWork->nChBits[*input_data], pWork->nChCodes[*input_data]);
+ input_data++;
+_00402252:;
+ }
+
+ if(input_data_ended == 0)
+ {
+ input_data -= 0x1000;
+ memcpy(pWork->work_buff, pWork->work_buff + 0x1000, pWork->dsize_bytes + 0x204);
+ }
+ }
+
+__Exit:
+
+ // Write the termination literal
+ OutputBits(pWork, pWork->nChBits[0x305], pWork->nChCodes[0x305]);
+ if(pWork->out_bits != 0)
+ pWork->out_bytes++;
+ pWork->write_buf(pWork->out_buff, &pWork->out_bytes, pWork->param);
+ return;
+}
+
+//-----------------------------------------------------------------------------
+// Main imploding function
+
+unsigned int PKEXPORT implode(
+ unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
+ void (*write_buf)(char *buf, unsigned int *size, void *param),
+ char *work_buf,
+ void *param,
+ unsigned int *type,
+ unsigned int *dsize)
+{
+ TCmpStruct * pWork = (TCmpStruct *)work_buf;
+ unsigned int nChCode;
+ unsigned int nCount;
+ unsigned int i;
+ int nCount2;
+
+ // Fill the work buffer information
+ // Note: The caller must zero the "work_buff" before passing it to implode
+ pWork->read_buf = read_buf;
+ pWork->write_buf = write_buf;
+ pWork->dsize_bytes = *dsize;
+ pWork->ctype = *type;
+ pWork->param = param;
+ pWork->dsize_bits = 4;
+ pWork->dsize_mask = 0x0F;
+
+ // Test dictionary size
+ switch(*dsize)
+ {
+ case CMP_IMPLODE_DICT_SIZE3: // 0x1000 bytes
+ pWork->dsize_bits++;
+ pWork->dsize_mask |= 0x20;
+ // No break here !!!
+
+ case CMP_IMPLODE_DICT_SIZE2: // 0x800 bytes
+ pWork->dsize_bits++;
+ pWork->dsize_mask |= 0x10;
+ // No break here !!!
+
+ case CMP_IMPLODE_DICT_SIZE1: // 0x400
+ break;
+
+ default:
+ return CMP_INVALID_DICTSIZE;
+ }
+
+ // Test the compression type
+ switch(*type)
+ {
+ case CMP_BINARY: // We will compress data with binary compression type
+ for(nChCode = 0, nCount = 0; nCount < 0x100; nCount++)
+ {
+ pWork->nChBits[nCount] = 9;
+ pWork->nChCodes[nCount] = (unsigned short)nChCode;
+ nChCode = (nChCode & 0x0000FFFF) + 2;
+ }
+ break;
+
+
+ case CMP_ASCII: // We will compress data with ASCII compression type
+ for(nCount = 0; nCount < 0x100; nCount++)
+ {
+ pWork->nChBits[nCount] = (unsigned char )(ChBitsAsc[nCount] + 1);
+ pWork->nChCodes[nCount] = (unsigned short)(ChCodeAsc[nCount] * 2);
+ }
+ break;
+
+ default:
+ return CMP_INVALID_MODE;
+ }
+
+ for(i = 0; i < 0x10; i++)
+ {
+ if(1 << ExLenBits[i])
+ {
+ for(nCount2 = 0; nCount2 < (1 << ExLenBits[i]); nCount2++)
+ {
+ pWork->nChBits[nCount] = (unsigned char)(ExLenBits[i] + LenBits[i] + 1);
+ pWork->nChCodes[nCount] = (unsigned short)((nCount2 << (LenBits[i] + 1)) | ((LenCode[i] & 0xFFFF00FF) * 2) | 1);
+ nCount++;
+ }
+ }
+ }
+
+ // Copy the distance codes and distance bits and perform the compression
+ memcpy(&pWork->dist_codes, DistCode, sizeof(DistCode));
+ memcpy(&pWork->dist_bits, DistBits, sizeof(DistBits));
+ WriteCmpData(pWork);
+ return CMP_NO_ERROR;
+}
diff --git a/dep/StormLib/src/pklib/pklib.h b/dep/StormLib/src/pklib/pklib.h
new file mode 100644
index 00000000000..f43da153be6
--- /dev/null
+++ b/dep/StormLib/src/pklib/pklib.h
@@ -0,0 +1,148 @@
+/*****************************************************************************/
+/* pklib.h Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Header file for PKWARE Data Compression Library */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 31.03.03 1.00 Lad The first version of pkware.h */
+/*****************************************************************************/
+
+#ifndef __PKLIB_H__
+#define __PKLIB_H__
+
+#include "../StormPort.h"
+
+//-----------------------------------------------------------------------------
+// Defines
+
+#define CMP_BINARY 0 // Binary compression
+#define CMP_ASCII 1 // Ascii compression
+
+#define CMP_NO_ERROR 0
+#define CMP_INVALID_DICTSIZE 1
+#define CMP_INVALID_MODE 2
+#define CMP_BAD_DATA 3
+#define CMP_ABORT 4
+
+#define CMP_IMPLODE_DICT_SIZE1 1024 // Dictionary size of 1024
+#define CMP_IMPLODE_DICT_SIZE2 2048 // Dictionary size of 2048
+#define CMP_IMPLODE_DICT_SIZE3 4096 // Dictionary size of 4096
+
+//-----------------------------------------------------------------------------
+// Define calling convention
+
+#ifndef PKEXPORT
+#ifdef WIN32
+#define PKEXPORT __cdecl // Use for normal __cdecl calling
+#else
+#define PKEXPORT
+#endif
+#endif
+
+//-----------------------------------------------------------------------------
+// Internal structures
+
+// Compression structure
+typedef struct
+{
+ unsigned int distance; // 0000: Backward distance of the currently found repetition, decreased by 1
+ unsigned int out_bytes; // 0004: # bytes available in out_buff
+ unsigned int out_bits; // 0008: # of bits available in the last out byte
+ unsigned int dsize_bits; // 000C: Number of bits needed for dictionary size. 4 = 0x400, 5 = 0x800, 6 = 0x1000
+ unsigned int dsize_mask; // 0010: Bit mask for dictionary. 0x0F = 0x400, 0x1F = 0x800, 0x3F = 0x1000
+ unsigned int ctype; // 0014: Compression type (CMP_ASCII or CMP_BINARY)
+ unsigned int dsize_bytes; // 0018: Dictionary size in bytes
+ unsigned char dist_bits[0x40]; // 001C: Distance bits
+ unsigned char dist_codes[0x40]; // 005C: Distance codes
+ unsigned char nChBits[0x306]; // 009C: Table of literal bit lengths to be put to the output stream
+ unsigned short nChCodes[0x306]; // 03A2: Table of literal codes to be put to the output stream
+ unsigned short offs09AE; // 09AE:
+
+ void * param; // 09B0: User parameter
+ unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); // 9B4
+ void (*write_buf)(char *buf, unsigned int *size, void *param); // 9B8
+
+ unsigned short offs09BC[0x204]; // 09BC:
+ unsigned long offs0DC4; // 0DC4:
+ unsigned short phash_to_index[0x900]; // 0DC8: Array of indexes (one for each PAIR_HASH) to the "pair_hash_offsets" table
+ unsigned short phash_to_index_end; // 1FC8: End marker for "phash_to_index" table
+ char out_buff[0x802]; // 1FCA: Compressed data
+ unsigned char work_buff[0x2204]; // 27CC: Work buffer
+ // + DICT_OFFSET => Dictionary
+ // + UNCMP_OFFSET => Uncompressed data
+ unsigned short phash_offs[0x2204]; // 49D0: Table of offsets for each PAIR_HASH
+} TCmpStruct;
+
+#define CMP_BUFFER_SIZE sizeof(TCmpStruct) // Size of compression structure.
+ // Defined as 36312 in pkware header file
+
+
+// Decompression structure
+typedef struct
+{
+ unsigned long offs0000; // 0000
+ unsigned long ctype; // 0004: Compression type (CMP_BINARY or CMP_ASCII)
+ unsigned long outputPos; // 0008: Position in output buffer
+ unsigned long dsize_bits; // 000C: Dict size (4, 5, 6 for 0x400, 0x800, 0x1000)
+ unsigned long dsize_mask; // 0010: Dict size bitmask (0x0F, 0x1F, 0x3F for 0x400, 0x800, 0x1000)
+ unsigned long bit_buff; // 0014: 16-bit buffer for processing input data
+ unsigned long extra_bits; // 0018: Number of extra (above 8) bits in bit buffer
+ unsigned int in_pos; // 001C: Position in in_buff
+ unsigned long in_bytes; // 0020: Number of bytes in input buffer
+ void * param; // 0024: Custom parameter
+ unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); // Pointer to function that reads data from the input stream
+ void (*write_buf)(char *buf, unsigned int *size, void *param);// Pointer to function that writes data to the output stream
+
+ unsigned char out_buff[0x2204]; // 0030: Output circle buffer.
+ // 0x0000 - 0x0FFF: Previous uncompressed data, kept for repetitions
+ // 0x1000 - 0x1FFF: Currently decompressed data
+ // 0x2000 - 0x2203: Reserve space for the longest possible repetition
+ unsigned char in_buff[0x800]; // 2234: Buffer for data to be decompressed
+ unsigned char DistPosCodes[0x100]; // 2A34: Table of distance position codes
+ unsigned char LengthCodes[0x100]; // 2B34: Table of length codes
+ unsigned char offs2C34[0x100]; // 2C34: Buffer for
+ unsigned char offs2D34[0x100]; // 2D34: Buffer for
+ unsigned char offs2E34[0x80]; // 2EB4: Buffer for
+ unsigned char offs2EB4[0x100]; // 2EB4: Buffer for
+ unsigned char ChBitsAsc[0x100]; // 2FB4: Buffer for
+ unsigned char DistBits[0x40]; // 30B4: Numbers of bytes to skip copied block length
+ unsigned char LenBits[0x10]; // 30F4: Numbers of bits for skip copied block length
+ unsigned char ExLenBits[0x10]; // 3104: Number of valid bits for copied block
+ unsigned short LenBase[0x10]; // 3114: Buffer for
+} TDcmpStruct;
+
+#define EXP_BUFFER_SIZE sizeof(TDcmpStruct) // Size of decompression structure
+ // Defined as 12596 in pkware headers
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+unsigned int PKEXPORT implode(
+ unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
+ void (*write_buf)(char *buf, unsigned int *size, void *param),
+ char *work_buf,
+ void *param,
+ unsigned int *type,
+ unsigned int *dsize);
+
+
+unsigned int PKEXPORT explode(
+ unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
+ void (*write_buf)(char *buf, unsigned int *size, void *param),
+ char *work_buf,
+ void *param);
+
+// The original name "crc32" was changed to "crc32pk" due
+// to compatibility with zlib
+unsigned long PKEXPORT crc32_pklib(char *buffer, unsigned int *size, unsigned long *old_crc);
+
+#ifdef __cplusplus
+ } // End of 'extern "C"' declaration
+#endif
+
+#endif // __PKLIB_H__
diff --git a/dep/StormLib/src/sparse/sparse.cpp b/dep/StormLib/src/sparse/sparse.cpp
new file mode 100644
index 00000000000..6df7021fc8a
--- /dev/null
+++ b/dep/StormLib/src/sparse/sparse.cpp
@@ -0,0 +1,292 @@
+/*****************************************************************************/
+/* huffman.cpp Copyright (c) Ladislav Zezula 1998-2003 */
+/*---------------------------------------------------------------------------*/
+/* This module contains Huffmann (de)compression methods */
+/* */
+/* Authors : Ladislav Zezula (ladik.zezula.net) */
+/* ShadowFlare (BlakFlare@hotmail.com) */
+/* */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* xx.xx.xx 1.00 Lad The first version of dcmp.cpp */
+/* 03.05.03 1.00 Lad Added compression methods */
+/* 19.11.03 1.01 Dan Big endian handling */
+/* 08.12.03 2.01 Dan High-memory handling (> 0x80000000) */
+/*****************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+
+#include "sparse.h"
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+void CompressSparse(unsigned char * pbOutBuffer, int * pcbOutBuffer, unsigned char * pbInBuffer, int cbInBuffer)
+{
+ unsigned char * pbOutBufferEnd = pbOutBuffer + *pcbOutBuffer;
+ unsigned char * pbInBufferEnd = pbInBuffer + cbInBuffer;
+ unsigned char * pbLastNonZero = pbInBuffer;
+ unsigned char * pbOutBuffer0 = pbOutBuffer;
+ unsigned char * pbInBuffPtr = pbInBuffer;
+ size_t NumberOfNonZeros;
+ size_t NumberOfZeros;
+
+ // There must be at least 4 bytes of free space in the output buffer now
+ if((pbInBuffer + 4) >= pbInBufferEnd)
+ return;
+
+ // Put the original data length (in little endian)
+ *pbOutBuffer++ = (unsigned char)(cbInBuffer >> 0x18);
+ *pbOutBuffer++ = (unsigned char)(cbInBuffer >> 0x10);
+ *pbOutBuffer++ = (unsigned char)(cbInBuffer >> 0x08);
+ *pbOutBuffer++ = (unsigned char)(cbInBuffer >> 0x00);
+
+ // If there is at least 3 bytes in the input buffer, do this loop
+ while(pbInBuffer < (pbInBufferEnd - 3))
+ {
+ // Reset the zero count and frontal pointer
+ pbLastNonZero = pbInBuffer;
+ pbInBuffPtr = pbInBuffer;
+ NumberOfZeros = 0;
+
+ if(pbInBuffPtr < pbInBufferEnd)
+ {
+ do
+ {
+ // Count number of zeros
+ if(*pbInBuffPtr == 0)
+ {
+ NumberOfZeros++;
+ }
+ else
+ {
+ // Were there at least 3 zeros before? If yes, we need to flush the data
+ if(NumberOfZeros >= 3)
+ break;
+ pbLastNonZero = pbInBuffPtr + 1;
+ NumberOfZeros = 0;
+ }
+ }
+ while(++pbInBuffPtr < pbInBufferEnd);
+ }
+
+ // Get number of nonzeros that we found so far and flush them
+ NumberOfNonZeros = pbLastNonZero - pbInBuffer;
+ if(NumberOfNonZeros != 0)
+ {
+ // Process blocks that are longer than 0x81 nonzero bytes
+ while(NumberOfNonZeros > 0x81)
+ {
+ // Verify if we still have enough space in output buffer
+ if((pbOutBuffer + 0x81) >= pbOutBufferEnd)
+ return;
+
+ // Put marker that means "0x80 of nonzeros"
+ *pbOutBuffer++ = 0xFF;
+ memcpy(pbOutBuffer, pbInBuffer, 0x80);
+
+ // Adjust counter of nonzeros and both pointers
+ NumberOfNonZeros -= 0x80;
+ pbOutBuffer += 0x80;
+ pbInBuffer += 0x80;
+ }
+
+ // BUGBUG: The following code will be triggered if the NumberOfNonZeros
+ // was 0x81 before. It will copy just one byte. This seems like a bug to me,
+ // but since I want StormLib to be exact like Blizzard code is, I will keep
+ // it that way here
+ if(NumberOfNonZeros > 0x80)
+ {
+ // Verify if we still have enough space in output buffer
+ if((pbOutBuffer + 2) >= pbOutBufferEnd)
+ return;
+
+ // Put marker that means "1 nonzero byte"
+ *pbOutBuffer++ = 0x80;
+ memcpy(pbOutBuffer, pbInBuffer, 1);
+
+ // Adjust counter of nonzeros and both pointers
+ NumberOfNonZeros--;
+ pbOutBuffer++;
+ pbInBuffer++;
+ }
+
+ // If there is 1 nonzero or more, put the block
+ if(NumberOfNonZeros >= 0x01)
+ {
+ // Verify if we still have enough space in output buffer
+ if((pbOutBuffer + NumberOfNonZeros + 1) >= pbOutBufferEnd)
+ return;
+
+ // Put marker that means "Several nonzero bytes"
+ *pbOutBuffer++ = (unsigned char)(0x80 | (NumberOfNonZeros - 1));
+ memcpy(pbOutBuffer, pbInBuffer, NumberOfNonZeros);
+
+ // Adjust pointers
+ pbOutBuffer += NumberOfNonZeros;
+ pbInBuffer += NumberOfNonZeros;
+ }
+ else
+ {
+ // Verify if we still have enough space in output buffer
+ if((pbOutBuffer + 2) >= pbOutBufferEnd)
+ return;
+
+ // Put marker that means "1 nonzero byte"
+ *pbOutBuffer++ = 0x80;
+ memcpy(pbOutBuffer, pbInBuffer, 1);
+
+ // Adjust pointers
+ pbOutBuffer++;
+ pbInBuffer++;
+ }
+ }
+
+ // Now flush all zero bytes
+ while(NumberOfZeros > 0x85)
+ {
+ // Do we have at least 2 bytes in the output buffer ?
+ if((pbOutBuffer + 1) >= pbOutBufferEnd)
+ return;
+
+ // Put marker that means "0x82 zeros"
+ *pbOutBuffer++ = 0x7F;
+
+ // Adjust zero counter and input pointer
+ NumberOfZeros -= 0x82;
+ pbInBuffer += 0x82;
+ }
+
+ // If we got more than 0x82 zeros, flush 3 of them now
+ if(NumberOfZeros > 0x82)
+ {
+ // Do we have at least 2 bytes in the output buffer ?
+ if((pbOutBuffer + 1) >= pbOutBufferEnd)
+ return;
+
+ // Put marker that means "0x03 zeros"
+ *pbOutBuffer++ = 0;
+
+ // Adjust zero counter and input pointer
+ NumberOfZeros -= 0x03;
+ pbInBuffer += 0x03;
+ }
+
+ // Is there at least three zeros ?
+ if(NumberOfZeros >= 3)
+ {
+ // Do we have at least 2 bytes in the output buffer ?
+ if((pbOutBuffer + 1) >= pbOutBufferEnd)
+ return;
+
+ // Put marker that means "Several zeros"
+ *pbOutBuffer++ = (unsigned char)(NumberOfZeros - 3);
+
+ // Adjust pointer
+ pbInBuffer += NumberOfZeros;
+ }
+ }
+
+ // Flush last three bytes
+ if(pbInBuffer < pbInBufferEnd)
+ {
+ pbInBuffPtr = pbInBuffer;
+
+ for(;;)
+ {
+ if(*pbInBuffPtr++ != 0)
+ {
+ // Get number of bytes remaining
+ NumberOfNonZeros = (pbInBufferEnd - pbInBuffer);
+
+ // Not enough space in the output buffer ==> exit
+ if((pbOutBuffer + NumberOfNonZeros + 1) >= pbOutBufferEnd)
+ return;
+
+ // Terminate with a marker that means "0x80 of nonzeros"
+ *pbOutBuffer++ = 0xFF;
+ memcpy(pbOutBuffer, pbInBuffer, NumberOfNonZeros);
+
+ // Adjust pointer
+ pbOutBuffer += NumberOfNonZeros;
+ break;
+ }
+ else
+ {
+ // Is there are more chars in the input buffer
+ if(pbInBuffPtr < pbInBufferEnd)
+ continue;
+
+ // If the compression will not compress it by even 1 byte, do nothing
+ if((pbOutBuffer + 1) >= pbOutBufferEnd)
+ return;
+
+ // Terminate with a chunk that means "0x82 of zeros"
+ *pbOutBuffer++ = 0x7F;
+ break;
+ }
+ }
+ }
+
+ // Out the length of the output buffer
+ *pcbOutBuffer = (int)(pbOutBuffer - pbOutBuffer0);
+}
+
+int DecompressSparse(unsigned char * pbOutBuffer, int * pcbOutBuffer, unsigned char * pbInBuffer, int cbInBuffer)
+{
+ unsigned char * pbInBufferEnd = pbInBuffer + cbInBuffer;
+ unsigned int cbChunkSize;
+ unsigned int cbOutBuffer = 0;
+ unsigned int OneByte;
+
+ // Don't decompress anything that is shorter than 5 bytes
+ if(cbInBuffer < 5)
+ return 0;
+
+ // Get the 32-bits from the input stream
+ OneByte = *pbInBuffer++;
+ cbOutBuffer |= (OneByte << 0x18);
+ OneByte = *pbInBuffer++;
+ cbOutBuffer |= (OneByte << 0x10);
+ OneByte = *pbInBuffer++;
+ cbOutBuffer |= (OneByte << 0x08);
+ OneByte = *pbInBuffer++;
+ cbOutBuffer |= (OneByte << 0x00);
+
+ // Verify the size of the stream against the output buffer size
+ if(cbOutBuffer > *pcbOutBuffer)
+ return 0;
+
+ // Put the output size to the buffer
+ *pcbOutBuffer = cbOutBuffer;
+
+ // Process the input buffer
+ while(pbInBuffer < pbInBufferEnd)
+ {
+ // Get (next) byte from the stream
+ OneByte = *pbInBuffer++;
+
+ // If highest bit, it means that that normal data follow
+ if(OneByte & 0x80)
+ {
+ cbChunkSize = (OneByte & 0x7F) + 1;
+ cbChunkSize = (cbChunkSize < cbOutBuffer) ? cbChunkSize : cbOutBuffer;
+ memcpy(pbOutBuffer, pbInBuffer, cbChunkSize);
+ pbInBuffer += cbChunkSize;
+ }
+ else
+ {
+ cbChunkSize = (OneByte & 0x7F) + 3;
+ cbChunkSize = (cbChunkSize < cbOutBuffer) ? cbChunkSize : cbOutBuffer;
+ memset(pbOutBuffer, 0, cbChunkSize);
+ }
+
+ // Increment output buffer pointer
+ pbOutBuffer += cbChunkSize;
+ cbOutBuffer -= cbChunkSize;
+ }
+
+ return 1;
+}
diff --git a/dep/StormLib/src/sparse/sparse.h b/dep/StormLib/src/sparse/sparse.h
new file mode 100644
index 00000000000..032395f0b94
--- /dev/null
+++ b/dep/StormLib/src/sparse/sparse.h
@@ -0,0 +1,19 @@
+/*****************************************************************************/
+/* sparse.h Copyright (c) Ladislav Zezula 2010 */
+/*---------------------------------------------------------------------------*/
+/* implementation of Sparse compression, used in Starcraft II */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 05.03.10 1.00 Lad The first version of sparse.h */
+/*****************************************************************************/
+
+#ifndef __SPARSE_H__
+#define __SPARSE_H__
+
+#include "../StormPort.h"
+
+void CompressSparse(unsigned char * pbOutBuffer, int * pcbOutLength, unsigned char * pbInBuffer, int cbInLength);
+int DecompressSparse(unsigned char * pbOutBuffer, int * pcbOutLength, unsigned char * pbInBuffer, int cbInLength);
+
+#endif // __SPARSE_H__
diff --git a/dep/StormLib/src/zlib/adler32.c b/dep/StormLib/src/zlib/adler32.c
new file mode 100644
index 00000000000..007ba26277c
--- /dev/null
+++ b/dep/StormLib/src/zlib/adler32.c
@@ -0,0 +1,149 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#define BASE 65521UL /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+# define MOD(a) \
+ do { \
+ if (a >= (BASE << 16)) a -= (BASE << 16); \
+ if (a >= (BASE << 15)) a -= (BASE << 15); \
+ if (a >= (BASE << 14)) a -= (BASE << 14); \
+ if (a >= (BASE << 13)) a -= (BASE << 13); \
+ if (a >= (BASE << 12)) a -= (BASE << 12); \
+ if (a >= (BASE << 11)) a -= (BASE << 11); \
+ if (a >= (BASE << 10)) a -= (BASE << 10); \
+ if (a >= (BASE << 9)) a -= (BASE << 9); \
+ if (a >= (BASE << 8)) a -= (BASE << 8); \
+ if (a >= (BASE << 7)) a -= (BASE << 7); \
+ if (a >= (BASE << 6)) a -= (BASE << 6); \
+ if (a >= (BASE << 5)) a -= (BASE << 5); \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+# define MOD4(a) \
+ do { \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+#else
+# define MOD(a) a %= BASE
+# define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long sum2;
+ unsigned n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == Z_NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD4(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off_t len2;
+{
+ unsigned long sum1;
+ unsigned long sum2;
+ unsigned rem;
+
+ /* the derivation of this formula is left as an exercise for the reader */
+ rem = (unsigned)(len2 % BASE);
+ sum1 = adler1 & 0xffff;
+ sum2 = rem * sum1;
+ MOD(sum2);
+ sum1 += (adler2 & 0xffff) + BASE - 1;
+ sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+ if (sum1 > BASE) sum1 -= BASE;
+ if (sum1 > BASE) sum1 -= BASE;
+ if (sum2 > (BASE << 1)) sum2 -= (BASE << 1);
+ if (sum2 > BASE) sum2 -= BASE;
+ return sum1 | (sum2 << 16);
+}
diff --git a/dep/StormLib/src/zlib/compress2.c b/dep/StormLib/src/zlib/compress2.c
new file mode 100644
index 00000000000..df04f0148e6
--- /dev/null
+++ b/dep/StormLib/src/zlib/compress2.c
@@ -0,0 +1,79 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+ int level;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+ stream.opaque = (voidpf)0;
+
+ err = deflateInit(&stream, level);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+ If the default memLevel or windowBits for deflateInit() is changed, then
+ this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+ uLong sourceLen;
+{
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11;
+}
diff --git a/dep/StormLib/src/zlib/crc32.c b/dep/StormLib/src/zlib/crc32.c
new file mode 100644
index 00000000000..f658a9ef55e
--- /dev/null
+++ b/dep/StormLib/src/zlib/crc32.c
@@ -0,0 +1,423 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+ Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+ protection on the static variables used to control the first-use generation
+ of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+ first call get_crc_table() to initialize the tables before allowing more than
+ one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+# include <stdio.h>
+# ifndef DYNAMIC_CRC_TABLE
+# define DYNAMIC_CRC_TABLE
+# endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h" /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+# ifdef STDC /* need ANSI C limits.h to determine sizes */
+# include <limits.h>
+# define BYFOUR
+# if (UINT_MAX == 0xffffffffUL)
+ typedef unsigned int u4;
+# else
+# if (ULONG_MAX == 0xffffffffUL)
+ typedef unsigned long u4;
+# else
+# if (USHRT_MAX == 0xffffffffUL)
+ typedef unsigned short u4;
+# else
+# undef BYFOUR /* can't find a four-byte integer type! */
+# endif
+# endif
+# endif
+# endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+ (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+ local unsigned long crc32_little OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+ local unsigned long crc32_big OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+# define TBLS 8
+#else
+# define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+ unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+ local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+ Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The first table is simply the CRC of all possible eight bit values. This is
+ all the information needed to generate CRCs on data a byte at a time for all
+ combinations of CRC register values and incoming bytes. The remaining tables
+ allow for word-at-a-time CRC calculation for both big-endian and little-
+ endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+ unsigned long c;
+ int n, k;
+ unsigned long poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static volatile int first = 1; /* flag to limit concurrent making */
+ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* See if another task is already doing this (not thread-safe, but better
+ than nothing -- significantly reduces duration of vulnerability in
+ case the advice about DYNAMIC_CRC_TABLE is ignored) */
+ if (first) {
+ first = 0;
+
+ /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+ poly = 0UL;
+ for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+ poly |= 1UL << (31 - p[n]);
+
+ /* generate a crc for every 8-bit value */
+ for (n = 0; n < 256; n++) {
+ c = (unsigned long)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[0][n] = c;
+ }
+
+#ifdef BYFOUR
+ /* generate crc for each value followed by one, two, and three zeros,
+ and then the byte reversal of those as well as the first table */
+ for (n = 0; n < 256; n++) {
+ c = crc_table[0][n];
+ crc_table[4][n] = REV(c);
+ for (k = 1; k < 4; k++) {
+ c = crc_table[0][c & 0xff] ^ (c >> 8);
+ crc_table[k][n] = c;
+ crc_table[k + 4][n] = REV(c);
+ }
+ }
+#endif /* BYFOUR */
+
+ crc_table_empty = 0;
+ }
+ else { /* not first */
+ /* wait for the other guy to finish (not efficient, but rare) */
+ while (crc_table_empty)
+ ;
+ }
+
+#ifdef MAKECRCH
+ /* write out CRC tables to crc32.h */
+ {
+ FILE *out;
+
+ out = fopen("crc32.h", "w");
+ if (out == NULL) return;
+ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+ fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+ fprintf(out, "local const unsigned long FAR ");
+ fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
+ write_table(out, crc_table[0]);
+# ifdef BYFOUR
+ fprintf(out, "#ifdef BYFOUR\n");
+ for (k = 1; k < 8; k++) {
+ fprintf(out, " },\n {\n");
+ write_table(out, crc_table[k]);
+ }
+ fprintf(out, "#endif\n");
+# endif /* BYFOUR */
+ fprintf(out, " }\n};\n");
+ fclose(out);
+ }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+ FILE *out;
+ const unsigned long FAR *table;
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n],
+ n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+ return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+ if (sizeof(void *) == sizeof(ptrdiff_t)) {
+ u4 endian;
+
+ endian = 1;
+ if (*((unsigned char *)(&endian)))
+ return crc32_little(crc, buf, len);
+ else
+ return crc32_big(crc, buf, len);
+ }
+#endif /* BYFOUR */
+ crc = crc ^ 0xffffffffUL;
+ while (len >= 8) {
+ DO8;
+ len -= 8;
+ }
+ if (len) do {
+ DO1;
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = (u4)crc;
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = REV((u4)crc);
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ buf4--;
+ while (len >= 32) {
+ DOBIG32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOBIG4;
+ len -= 4;
+ }
+ buf4++;
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+ unsigned long *mat;
+ unsigned long vec;
+{
+ unsigned long sum;
+
+ sum = 0;
+ while (vec) {
+ if (vec & 1)
+ sum ^= *mat;
+ vec >>= 1;
+ mat++;
+ }
+ return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+ unsigned long *square;
+ unsigned long *mat;
+{
+ int n;
+
+ for (n = 0; n < GF2_DIM; n++)
+ square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off_t len2;
+{
+ int n;
+ unsigned long row;
+ unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */
+ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */
+
+ /* degenerate case */
+ if (len2 == 0)
+ return crc1;
+
+ /* put operator for one zero bit in odd */
+ odd[0] = 0xedb88320L; /* CRC-32 polynomial */
+ row = 1;
+ for (n = 1; n < GF2_DIM; n++) {
+ odd[n] = row;
+ row <<= 1;
+ }
+
+ /* put operator for two zero bits in even */
+ gf2_matrix_square(even, odd);
+
+ /* put operator for four zero bits in odd */
+ gf2_matrix_square(odd, even);
+
+ /* apply len2 zeros to crc1 (first square will put the operator for one
+ zero byte, eight zero bits, in even) */
+ do {
+ /* apply zeros operator for this bit of len2 */
+ gf2_matrix_square(even, odd);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(even, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ if (len2 == 0)
+ break;
+
+ /* another iteration of the loop with odd and even swapped */
+ gf2_matrix_square(odd, even);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(odd, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ } while (len2 != 0);
+
+ /* return combined crc */
+ crc1 ^= crc2;
+ return crc1;
+}
diff --git a/dep/StormLib/src/zlib/crc32.h b/dep/StormLib/src/zlib/crc32.h
new file mode 100644
index 00000000000..8053b6117c0
--- /dev/null
+++ b/dep/StormLib/src/zlib/crc32.h
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+ {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+#ifdef BYFOUR
+ },
+ {
+ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+ 0x9324fd72UL
+ },
+ {
+ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+ 0xbe9834edUL
+ },
+ {
+ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+ 0xde0506f1UL
+ },
+ {
+ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+ 0x8def022dUL
+ },
+ {
+ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+ 0x72fd2493UL
+ },
+ {
+ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+ 0xed3498beUL
+ },
+ {
+ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+ 0xf10605deUL
+#endif
+ }
+};
diff --git a/dep/StormLib/src/zlib/deflate.c b/dep/StormLib/src/zlib/deflate.c
new file mode 100644
index 00000000000..29ce1f64a57
--- /dev/null
+++ b/dep/StormLib/src/zlib/deflate.c
@@ -0,0 +1,1736 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+ " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow OF((deflate_state *s, int flush));
+#endif
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifndef FASTEST
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+#endif
+local uInt longest_match_fast OF((deflate_state *s, IPos cur_match));
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int wrap = 1;
+ static const char my_version[] = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+ if (windowBits < 0) { /* suppress zlib wrapper */
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+#ifdef GZIP
+ else if (windowBits > 15) {
+ wrap = 2; /* write gzip wrapper instead */
+ windowBits -= 16;
+ }
+#endif
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->wrap = wrap;
+ s->gzhead = Z_NULL;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ s->status = FINISH_STATE;
+ strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt length = dictLength;
+ uInt n;
+ IPos hash_head = 0;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+ strm->state->wrap == 2 ||
+ (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+ return Z_STREAM_ERROR;
+
+ s = strm->state;
+ if (s->wrap)
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) return Z_OK;
+ if (length > MAX_DIST(s)) {
+ length = MAX_DIST(s);
+ dictionary += dictLength - length; /* use the tail of the dictionary */
+ }
+ zmemcpy(s->window, dictionary, length);
+ s->strstart = length;
+ s->block_start = (long)length;
+
+ /* Insert all strings in the hash table (except for the last two bytes).
+ * s->lookahead stays null, so s->ins_h will be recomputed at the next
+ * call of fill_window.
+ */
+ s->ins_h = s->window[0];
+ UPDATE_HASH(s, s->ins_h, s->window[1]);
+ for (n = 0; n <= length - MIN_MATCH; n++) {
+ INSERT_STRING(s, n, hash_head);
+ }
+ if (hash_head) hash_head = 0; /* to make compiler happy */
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+ return Z_STREAM_ERROR;
+ }
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->wrap < 0) {
+ s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+ }
+ s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+ strm->adler =
+#ifdef GZIP
+ s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+ adler32(0L, Z_NULL, 0);
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+ lm_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+ z_streamp strm;
+ gz_headerp head;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+ strm->state->gzhead = head;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+ z_streamp strm;
+ int bits;
+ int value;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ strm->state->bi_valid = bits;
+ strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if (func != configuration_table[level].func && strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_PARTIAL_FLUSH);
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+ z_streamp strm;
+ int good_length;
+ int max_lazy;
+ int nice_length;
+ int max_chain;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+ s->good_match = good_length;
+ s->max_lazy_match = max_lazy;
+ s->nice_match = nice_length;
+ s->max_chain_length = max_chain;
+ return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well. The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds
+ * for every combination of windowBits and memLevel, as well as wrap.
+ * But even the conservative upper bound of about 14% expansion does not
+ * seem onerous for output buffer allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+ z_streamp strm;
+ uLong sourceLen;
+{
+ deflate_state *s;
+ uLong destLen;
+
+ /* conservative upper bound */
+ destLen = sourceLen +
+ ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11;
+
+ /* if can't get parameters, return conservative bound */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return destLen;
+
+ /* if not default parameters, return conservative bound */
+ s = strm->state;
+ if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+ return destLen;
+
+ /* default settings: return tight bound for that case */
+ return compressBound(sourceLen);
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len = strm->state->pending;
+
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, strm->state->pending_out, len);
+ strm->next_out += len;
+ strm->state->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ strm->state->pending -= len;
+ if (strm->state->pending == 0) {
+ strm->state->pending_out = strm->state->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_FINISH || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the header */
+ if (s->status == INIT_STATE) {
+#ifdef GZIP
+ if (s->wrap == 2) {
+ strm->adler = crc32(0L, Z_NULL, 0);
+ put_byte(s, 31);
+ put_byte(s, 139);
+ put_byte(s, 8);
+ if (s->gzhead == NULL) {
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, OS_CODE);
+ s->status = BUSY_STATE;
+ }
+ else {
+ put_byte(s, (s->gzhead->text ? 1 : 0) +
+ (s->gzhead->hcrc ? 2 : 0) +
+ (s->gzhead->extra == Z_NULL ? 0 : 4) +
+ (s->gzhead->name == Z_NULL ? 0 : 8) +
+ (s->gzhead->comment == Z_NULL ? 0 : 16)
+ );
+ put_byte(s, (Byte)(s->gzhead->time & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, s->gzhead->os & 0xff);
+ if (s->gzhead->extra != NULL) {
+ put_byte(s, s->gzhead->extra_len & 0xff);
+ put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+ }
+ if (s->gzhead->hcrc)
+ strm->adler = crc32(strm->adler, s->pending_buf,
+ s->pending);
+ s->gzindex = 0;
+ s->status = EXTRA_STATE;
+ }
+ }
+ else
+#endif
+ {
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags;
+
+ if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+ level_flags = 0;
+ else if (s->level < 6)
+ level_flags = 1;
+ else if (s->level == 6)
+ level_flags = 2;
+ else
+ level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = adler32(0L, Z_NULL, 0);
+ }
+ }
+#ifdef GZIP
+ if (s->status == EXTRA_STATE) {
+ if (s->gzhead->extra != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+
+ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size)
+ break;
+ }
+ put_byte(s, s->gzhead->extra[s->gzindex]);
+ s->gzindex++;
+ }
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (s->gzindex == s->gzhead->extra_len) {
+ s->gzindex = 0;
+ s->status = NAME_STATE;
+ }
+ }
+ else
+ s->status = NAME_STATE;
+ }
+ if (s->status == NAME_STATE) {
+ if (s->gzhead->name != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->name[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0) {
+ s->gzindex = 0;
+ s->status = COMMENT_STATE;
+ }
+ }
+ else
+ s->status = COMMENT_STATE;
+ }
+ if (s->status == COMMENT_STATE) {
+ if (s->gzhead->comment != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->comment[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0)
+ s->status = HCRC_STATE;
+ }
+ else
+ s->status = HCRC_STATE;
+ }
+ if (s->status == HCRC_STATE) {
+ if (s->gzhead->hcrc) {
+ if (s->pending + 2 > s->pending_buf_size)
+ flush_pending(strm);
+ if (s->pending + 2 <= s->pending_buf_size) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ strm->adler = crc32(0L, Z_NULL, 0);
+ s->status = BUSY_STATE;
+ }
+ }
+ else
+ s->status = BUSY_STATE;
+ }
+#endif
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = (*(configuration_table[s->level].func))(s, flush);
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->wrap <= 0) return Z_STREAM_END;
+
+ /* Write the trailer */
+#ifdef GZIP
+ if (s->wrap == 2) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+ put_byte(s, (Byte)(strm->total_in & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+ }
+ else
+#endif
+ {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ status = strm->state->status;
+ if (status != INIT_STATE &&
+ status != EXTRA_STATE &&
+ status != NAME_STATE &&
+ status != COMMENT_STATE &&
+ status != HCRC_STATE &&
+ status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+#ifdef MAXSEG_64K
+ return Z_STREAM_ERROR;
+#else
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+
+ ss = source->state;
+
+ zmemcpy(dest, source, sizeof(z_stream));
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ zmemcpy(ds, ss, sizeof(deflate_state));
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* following zmemcpy do not work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ Bytef *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ if (strm->state->wrap == 1) {
+ strm->adler = adler32(strm->adler, strm->next_in, len);
+ }
+#ifdef GZIP
+ else if (strm->state->wrap == 2) {
+ strm->adler = crc32(strm->adler, strm->next_in, len);
+ }
+#endif
+ zmemcpy(buf, strm->next_in, len);
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2. Note that the checks below
+ * for insufficient lookahead only occur occasionally for performance
+ * reasons. Therefore uninitialized memory will be accessed, and
+ * conditional jumps will be made that depend on those values.
+ * However the length of the match is limited to the lookahead, so
+ * the output of deflate is not affected by the uninitialized values.
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+#endif /* ASMV */
+#endif /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 or strategy == Z_RLE only
+ */
+local uInt longest_match_fast(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp(s->window + match,
+ s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (sizeof(int) <= 2) {
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if
+ * strstart == 0 && lookahead == 1 (input done a byte at time)
+ */
+ more--;
+ }
+ }
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ /* %%% avoid this when Z_RLE */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead >= MIN_MATCH) {
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (eof)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+ FLUSH_BLOCK_ONLY(s, eof); \
+ if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+#ifdef FASTEST
+ if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) ||
+ (s->strategy == Z_RLE && s->strstart - hash_head == 1)) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+#else
+ if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+ s->match_length = longest_match (s, hash_head);
+ } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+#endif
+ /* longest_match() or longest_match_fast() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else
+#endif
+ {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+ s->match_length = longest_match (s, hash_head);
+ } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+ /* longest_match() or longest_match_fast() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+ || (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR)
+#endif
+ )) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ if (bflush) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ s->match_available = 0;
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
+
+#if 0
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one. Do not maintain a hash table. (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+ uInt run; /* length of run */
+ uInt max; /* maximum length of run */
+ uInt prev; /* byte at distance one to match */
+ Bytef *scan; /* scan for end of run */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the longest encodable run.
+ */
+ if (s->lookahead < MAX_MATCH) {
+ fill_window(s);
+ if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* See how many times the previous byte repeats */
+ run = 0;
+ if (s->strstart > 0) { /* if there is a previous byte, that is */
+ max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH;
+ scan = s->window + s->strstart - 1;
+ prev = *scan++;
+ do {
+ if (*scan++ != prev)
+ break;
+ } while (++run < max);
+ }
+
+ /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+ if (run >= MIN_MATCH) {
+ check_match(s, s->strstart, s->strstart - 1, run);
+ _tr_tally_dist(s, 1, run - MIN_MATCH, bflush);
+ s->lookahead -= run;
+ s->strstart += run;
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif
diff --git a/dep/StormLib/src/zlib/deflate.h b/dep/StormLib/src/zlib/deflate.h
new file mode 100644
index 00000000000..05a5ab3a2c1
--- /dev/null
+++ b/dep/StormLib/src/zlib/deflate.h
@@ -0,0 +1,331 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2004 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer creation by deflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip encoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define EXTRA_STATE 69
+#define NAME_STATE 73
+#define COMMENT_STATE 91
+#define HCRC_STATE 103
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ uInt pending; /* nb of bytes in the pending buffer */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ gz_headerp gzhead; /* gzip header information to write */
+ uInt gzindex; /* where in extra, name, or comment */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+ /* in trees.c */
+void _tr_init OF((deflate_state *s));
+int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+void _tr_align OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch _length_code[];
+ extern uch _dist_code[];
+#else
+ extern const uch _length_code[];
+ extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/dep/StormLib/src/zlib/inffast.c b/dep/StormLib/src/zlib/inffast.c
new file mode 100644
index 00000000000..bbee92ed1e6
--- /dev/null
+++ b/dep/StormLib/src/zlib/inffast.c
@@ -0,0 +1,318 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+ Based on testing to date,
+ Pre-increment preferred for:
+ - PowerPC G3 (Adler)
+ - MIPS R5000 (Randers-Pehrson)
+ Post-increment preferred for:
+ - none
+ No measurable difference:
+ - Pentium III (Anderson)
+ - M68060 (Nikl)
+ */
+#ifdef POSTINC
+# define OFF 0
+# define PUP(a) *(a)++
+#else
+# define OFF 1
+# define PUP(a) *++(a)
+#endif
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *in; /* local strm->next_in */
+ unsigned char FAR *last; /* while in < last, enough input available */
+ unsigned char FAR *out; /* local strm->next_out */
+ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
+ unsigned char FAR *end; /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+ unsigned dmax; /* maximum distance from zlib header */
+#endif
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
+ unsigned long hold; /* local strm->hold */
+ unsigned bits; /* local strm->bits */
+ code const FAR *lcode; /* local strm->lencode */
+ code const FAR *dcode; /* local strm->distcode */
+ unsigned lmask; /* mask for first level of length codes */
+ unsigned dmask; /* mask for first level of distance codes */
+ code this; /* retrieved table entry */
+ unsigned op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ unsigned len; /* match length, unused bytes */
+ unsigned dist; /* match distance */
+ unsigned char FAR *from; /* where to copy match from */
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ in = strm->next_in - OFF;
+ last = in + (strm->avail_in - 5);
+ out = strm->next_out - OFF;
+ beg = out - (start - strm->avail_out);
+ end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+ dmax = state->dmax;
+#endif
+ wsize = state->wsize;
+ whave = state->whave;
+ write = state->write;
+ window = state->window;
+ hold = state->hold;
+ bits = state->bits;
+ lcode = state->lencode;
+ dcode = state->distcode;
+ lmask = (1U << state->lenbits) - 1;
+ dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+ do {
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = lcode[hold & lmask];
+ dolen:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op == 0) { /* literal */
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ PUP(out) = (unsigned char)(this.val);
+ }
+ else if (op & 16) { /* length base */
+ len = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ len += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ }
+ Tracevv((stderr, "inflate: length %u\n", len));
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = dcode[hold & dmask];
+ dodist:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op & 16) { /* distance base */
+ dist = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ }
+ dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+ if (dist > dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ hold >>= op;
+ bits -= op;
+ Tracevv((stderr, "inflate: distance %u\n", dist));
+ op = (unsigned)(out - beg); /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ from = window - OFF;
+ if (write == 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ else if (write < op) { /* wrap around window */
+ from += wsize + write - op;
+ op -= write;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = window - OFF;
+ if (write < len) { /* some from start of window */
+ op = write;
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += write - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ while (len > 2) {
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ }
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ else {
+ from = out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level distance code */
+ this = dcode[this.val + (hold & ((1U << op) - 1))];
+ goto dodist;
+ }
+ else {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level length code */
+ this = lcode[this.val + (hold & ((1U << op) - 1))];
+ goto dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ else {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ } while (in < last && out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ in -= len;
+ bits -= len << 3;
+ hold &= (1U << bits) - 1;
+
+ /* update state and return */
+ strm->next_in = in + OFF;
+ strm->next_out = out + OFF;
+ strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+ strm->avail_out = (unsigned)(out < end ?
+ 257 + (end - out) : 257 - (out - end));
+ state->hold = hold;
+ state->bits = bits;
+ return;
+}
+
+/*
+ inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+ - Using bit fields for code structure
+ - Different op definition to avoid & for extra bits (do & for table bits)
+ - Three separate decoding do-loops for direct, window, and write == 0
+ - Special case for distance > 1 copies to do overlapped load and store copy
+ - Explicit branch predictions (based on measured branch probabilities)
+ - Deferring match copy and interspersed it with decoding subsequent codes
+ - Swapping literal/length else
+ - Swapping window/direct else
+ - Larger unrolled copy loops (three is about right)
+ - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/dep/StormLib/src/zlib/inffast.h b/dep/StormLib/src/zlib/inffast.h
new file mode 100644
index 00000000000..1e88d2d97b5
--- /dev/null
+++ b/dep/StormLib/src/zlib/inffast.h
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+void inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/dep/StormLib/src/zlib/inffixed.h b/dep/StormLib/src/zlib/inffixed.h
new file mode 100644
index 00000000000..75ed4b5978d
--- /dev/null
+++ b/dep/StormLib/src/zlib/inffixed.h
@@ -0,0 +1,94 @@
+ /* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by makefixed().
+ */
+
+ /* WARNING: this file should *not* be used by applications. It
+ is part of the implementation of the compression library and
+ is subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+ {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+ {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+ {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+ {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+ {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+ {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+ {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+ {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+ {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+ {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+ {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+ {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+ {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+ {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+ {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+ {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+ {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+ {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+ {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+ {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+ {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+ {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+ {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+ {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+ {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+ {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+ {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+ {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+ {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+ {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+ {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+ {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+ {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+ {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+ {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+ {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+ {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+ {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+ {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+ {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+ {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+ {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+ {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+ {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+ {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+ {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+ {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+ {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+ {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+ {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+ {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+ {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+ {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+ {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+ {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+ {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+ {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+ {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+ {0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+ {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+ {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+ {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+ {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+ {22,5,193},{64,5,0}
+ };
diff --git a/dep/StormLib/src/zlib/inflate.c b/dep/StormLib/src/zlib/inflate.c
new file mode 100644
index 00000000000..792fdee8e9c
--- /dev/null
+++ b/dep/StormLib/src/zlib/inflate.c
@@ -0,0 +1,1368 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0 24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ * creation of window when not needed, minimize use of window when it is
+ * needed, make inffast.c even faster, implement gzip decoding, and to
+ * improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1 25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2 4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ * to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3 22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ * buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4 1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common write == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ * source file infback.c to provide a call-back interface to inflate for
+ * programs like gzip and unzip -- uses window as output buffer to avoid
+ * window copying
+ *
+ * 1.2.beta5 1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ * input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6 4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ * make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7 27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0 9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ * for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ * and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+# ifndef BUILDFIXED
+# define BUILDFIXED
+# endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+ void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+ unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ strm->total_in = strm->total_out = state->total = 0;
+ strm->msg = Z_NULL;
+ strm->adler = 1; /* to support ill-conceived Java test suite */
+ state->mode = HEAD;
+ state->last = 0;
+ state->havedict = 0;
+ state->dmax = 32768U;
+ state->head = Z_NULL;
+ state->wsize = 0;
+ state->whave = 0;
+ state->write = 0;
+ state->hold = 0;
+ state->bits = 0;
+ state->lencode = state->distcode = state->next = state->codes;
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+ value &= (1L << bits) - 1;
+ state->hold += value << state->bits;
+ state->bits += bits;
+ return Z_OK;
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)
+ ZALLOC(strm, 1, sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ if (windowBits < 0) {
+ state->wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ state->wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+ if (windowBits < 48) windowBits &= 15;
+#endif
+ }
+ if (windowBits < 8 || windowBits > 15) {
+ ZFREE(strm, state);
+ strm->state = Z_NULL;
+ return Z_STREAM_ERROR;
+ }
+ state->wbits = (unsigned)windowBits;
+ state->window = Z_NULL;
+ return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+ Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also
+ defines BUILDFIXED, so the tables are built on the fly. makefixed() writes
+ those tables to stdout, which would be piped to inffixed.h. A small program
+ can simply call makefixed to do this:
+
+ void makefixed(void);
+
+ int main(void)
+ {
+ makefixed();
+ return 0;
+ }
+
+ Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+ a.out > inffixed.h
+ */
+void makefixed()
+{
+ unsigned low, size;
+ struct inflate_state state;
+
+ fixedtables(&state);
+ puts(" /* inffixed.h -- table for decoding fixed codes");
+ puts(" * Generated automatically by makefixed().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 7) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+ state.lencode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+ state.distcode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. If window does not exist yet, create it. This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+ struct inflate_state FAR *state;
+ unsigned copy, dist;
+
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* if it hasn't been done already, allocate space for the window */
+ if (state->window == Z_NULL) {
+ state->window = (unsigned char FAR *)
+ ZALLOC(strm, 1U << state->wbits,
+ sizeof(unsigned char));
+ if (state->window == Z_NULL) return 1;
+ }
+
+ /* if window not in use yet, initialize */
+ if (state->wsize == 0) {
+ state->wsize = 1U << state->wbits;
+ state->write = 0;
+ state->whave = 0;
+ }
+
+ /* copy state->wsize or less output bytes into the circular window */
+ copy = out - strm->avail_out;
+ if (copy >= state->wsize) {
+ zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+ state->write = 0;
+ state->whave = state->wsize;
+ }
+ else {
+ dist = state->wsize - state->write;
+ if (dist > copy) dist = copy;
+ zmemcpy(state->window + state->write, strm->next_out - copy, dist);
+ copy -= dist;
+ if (copy) {
+ zmemcpy(state->window, strm->next_out - copy, copy);
+ state->write = copy;
+ state->whave = state->wsize;
+ }
+ else {
+ state->write += dist;
+ if (state->write == state->wsize) state->write = 0;
+ if (state->whave < state->wsize) state->whave += dist;
+ }
+ }
+ return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+# define UPDATE(check, buf, len) \
+ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+# define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+# define CRC2(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ check = crc32(check, hbuf, 2); \
+ } while (0)
+
+# define CRC4(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ hbuf[2] = (unsigned char)((word) >> 16); \
+ hbuf[3] = (unsigned char)((word) >> 24); \
+ check = crc32(check, hbuf, 4); \
+ } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+ if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ if (have == 0) goto inf_leave; \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+ ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+ inflate() uses a state machine to process as much input data and generate as
+ much output data as possible before returning. The state machine is
+ structured roughly as follows:
+
+ for (;;) switch (state) {
+ ...
+ case STATEn:
+ if (not enough input data or output space to make progress)
+ return;
+ ... make progress ...
+ state = STATEm;
+ break;
+ ...
+ }
+
+ so when inflate() is called again, the same case is attempted again, and
+ if the appropriate resources are provided, the machine proceeds to the
+ next state. The NEEDBITS() macro is usually the way the state evaluates
+ whether it can proceed or should return. NEEDBITS() does the return if
+ the requested bits are not available. The typical use of the BITS macros
+ is:
+
+ NEEDBITS(n);
+ ... do something with BITS(n) ...
+ DROPBITS(n);
+
+ where NEEDBITS(n) either returns from inflate() if there isn't enough
+ input left to load n bits into the accumulator, or it continues. BITS(n)
+ gives the low n bits in the accumulator. When done, DROPBITS(n) drops
+ the low n bits off the accumulator. INITBITS() clears the accumulator
+ and sets the number of available bits to zero. BYTEBITS() discards just
+ enough bits to put the accumulator on a byte boundary. After BYTEBITS()
+ and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+ NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+ if there is no input available. The decoding of variable length codes uses
+ PULLBYTE() directly in order to pull just enough bytes to decode the next
+ code, and no more.
+
+ Some states loop until they get enough input, making sure that enough
+ state information is maintained to continue the loop where it left off
+ if NEEDBITS() returns in the loop. For example, want, need, and keep
+ would all have to actually be part of the saved state in case NEEDBITS()
+ returns:
+
+ case STATEw:
+ while (want < need) {
+ NEEDBITS(n);
+ keep[want++] = BITS(n);
+ DROPBITS(n);
+ }
+ state = STATEx;
+ case STATEx:
+
+ As shown above, if the next state is also the next case, then the break
+ is omitted.
+
+ A state may also return if there is not enough output space available to
+ complete that state. Those states are copying stored data, writing a
+ literal byte, and copying a matching string.
+
+ When returning, a "goto inf_leave" is used to update the total counters,
+ update the check value, and determine whether any progress has been made
+ during that inflate() call in order to return the proper return code.
+ Progress is defined as a change in either strm->avail_in or strm->avail_out.
+ When there is a window, goto inf_leave will update the window with the last
+ output written. If a goto inf_leave occurs in the middle of decompression
+ and there is no window currently, goto inf_leave will create one and copy
+ output to the window for the next call of inflate().
+
+ In this implementation, the flush parameter of inflate() only affects the
+ return code (per zlib.h). inflate() always writes as much as possible to
+ strm->next_out, given the space available and the provided input--the effect
+ documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
+ the allocation of and copying into a sliding window until necessary, which
+ provides the effect documented in zlib.h for Z_FINISH when the entire input
+ stream available. So the only thing the flush parameter actually does is:
+ when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
+ will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned in, out; /* save starting available input and output */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+#ifdef GUNZIP
+ unsigned char hbuf[4]; /* buffer for gzip header crc calculation */
+#endif
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0))
+ return Z_STREAM_ERROR;
+
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */
+ LOAD();
+ in = have;
+ out = left;
+ ret = Z_OK;
+ for (;;)
+ switch (state->mode) {
+ case HEAD:
+ if (state->wrap == 0) {
+ state->mode = TYPEDO;
+ break;
+ }
+ NEEDBITS(16);
+#ifdef GUNZIP
+ if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
+ state->check = crc32(0L, Z_NULL, 0);
+ CRC2(state->check, hold);
+ INITBITS();
+ state->mode = FLAGS;
+ break;
+ }
+ state->flags = 0; /* expect zlib header */
+ if (state->head != Z_NULL)
+ state->head->done = -1;
+ if (!(state->wrap & 1) || /* check if zlib header allowed */
+#else
+ if (
+#endif
+ ((BITS(8) << 8) + (hold >> 8)) % 31) {
+ strm->msg = (char *)"incorrect header check";
+ state->mode = BAD;
+ break;
+ }
+ if (BITS(4) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ DROPBITS(4);
+ len = BITS(4) + 8;
+ if (len > state->wbits) {
+ strm->msg = (char *)"invalid window size";
+ state->mode = BAD;
+ break;
+ }
+ state->dmax = 1U << len;
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = hold & 0x200 ? DICTID : TYPE;
+ INITBITS();
+ break;
+#ifdef GUNZIP
+ case FLAGS:
+ NEEDBITS(16);
+ state->flags = (int)(hold);
+ if ((state->flags & 0xff) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ if (state->flags & 0xe000) {
+ strm->msg = (char *)"unknown header flags set";
+ state->mode = BAD;
+ break;
+ }
+ if (state->head != Z_NULL)
+ state->head->text = (int)((hold >> 8) & 1);
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = TIME;
+ case TIME:
+ NEEDBITS(32);
+ if (state->head != Z_NULL)
+ state->head->time = hold;
+ if (state->flags & 0x0200) CRC4(state->check, hold);
+ INITBITS();
+ state->mode = OS;
+ case OS:
+ NEEDBITS(16);
+ if (state->head != Z_NULL) {
+ state->head->xflags = (int)(hold & 0xff);
+ state->head->os = (int)(hold >> 8);
+ }
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = EXLEN;
+ case EXLEN:
+ if (state->flags & 0x0400) {
+ NEEDBITS(16);
+ state->length = (unsigned)(hold);
+ if (state->head != Z_NULL)
+ state->head->extra_len = (unsigned)hold;
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ }
+ else if (state->head != Z_NULL)
+ state->head->extra = Z_NULL;
+ state->mode = EXTRA;
+ case EXTRA:
+ if (state->flags & 0x0400) {
+ copy = state->length;
+ if (copy > have) copy = have;
+ if (copy) {
+ if (state->head != Z_NULL &&
+ state->head->extra != Z_NULL) {
+ len = state->head->extra_len - state->length;
+ zmemcpy(state->head->extra + len, next,
+ len + copy > state->head->extra_max ?
+ state->head->extra_max - len : copy);
+ }
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ state->length -= copy;
+ }
+ if (state->length) goto inf_leave;
+ }
+ state->length = 0;
+ state->mode = NAME;
+ case NAME:
+ if (state->flags & 0x0800) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->name != Z_NULL &&
+ state->length < state->head->name_max)
+ state->head->name[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->name = Z_NULL;
+ state->length = 0;
+ state->mode = COMMENT;
+ case COMMENT:
+ if (state->flags & 0x1000) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->comment != Z_NULL &&
+ state->length < state->head->comm_max)
+ state->head->comment[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->comment = Z_NULL;
+ state->mode = HCRC;
+ case HCRC:
+ if (state->flags & 0x0200) {
+ NEEDBITS(16);
+ if (hold != (state->check & 0xffff)) {
+ strm->msg = (char *)"header crc mismatch";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ }
+ if (state->head != Z_NULL) {
+ state->head->hcrc = (int)((state->flags >> 9) & 1);
+ state->head->done = 1;
+ }
+ strm->adler = state->check = crc32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ break;
+#endif
+ case DICTID:
+ NEEDBITS(32);
+ strm->adler = state->check = REVERSE(hold);
+ INITBITS();
+ state->mode = DICT;
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ case TYPE:
+ if (flush == Z_BLOCK) goto inf_leave;
+ case TYPEDO:
+ if (state->last) {
+ BYTEBITS();
+ state->mode = CHECK;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+ case STORED:
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+ state->mode = COPY;
+ case COPY:
+ copy = state->length;
+ if (copy) {
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ if (copy == 0) goto inf_leave;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ break;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ state->have = 0;
+ state->mode = LENLENS;
+ case LENLENS:
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+ state->have = 0;
+ state->mode = CODELENS;
+ case CODELENS:
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = state->lens[state->have - 1];
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ inflate_fast(strm, out);
+ LOAD();
+ break;
+ }
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+ if ((int)(this.op) == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ state->mode = LIT;
+ break;
+ }
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = LENEXT;
+ case LENEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+ state->mode = DIST;
+ case DIST:
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = DISTEXT;
+ case DISTEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+#ifdef INFLATE_STRICT
+ if (state->offset > state->dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ if (state->offset > state->whave + out - left) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+ state->mode = MATCH;
+ case MATCH:
+ if (left == 0) goto inf_leave;
+ copy = out - left;
+ if (state->offset > copy) { /* copy from window */
+ copy = state->offset - copy;
+ if (copy > state->write) {
+ copy -= state->write;
+ from = state->window + (state->wsize - copy);
+ }
+ else
+ from = state->window + (state->write - copy);
+ if (copy > state->length) copy = state->length;
+ }
+ else { /* copy from output */
+ from = put - state->offset;
+ copy = state->length;
+ }
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+ case LIT:
+ if (left == 0) goto inf_leave;
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ case CHECK:
+ if (state->wrap) {
+ NEEDBITS(32);
+ out -= left;
+ strm->total_out += out;
+ state->total += out;
+ if (out)
+ strm->adler = state->check =
+ UPDATE(state->check, put - out, out);
+ out = left;
+ if ((
+#ifdef GUNZIP
+ state->flags ? hold :
+#endif
+ REVERSE(hold)) != state->check) {
+ strm->msg = (char *)"incorrect data check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: check matches trailer\n"));
+ }
+#ifdef GUNZIP
+ state->mode = LENGTH;
+ case LENGTH:
+ if (state->wrap && state->flags) {
+ NEEDBITS(32);
+ if (hold != (state->total & 0xffffffffUL)) {
+ strm->msg = (char *)"incorrect length check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+#endif
+ state->mode = DONE;
+ case DONE:
+ ret = Z_STREAM_END;
+ goto inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call updatewindow() to create and/or update the window state.
+ Note: a memory error from inflate() is non-recoverable.
+ */
+ inf_leave:
+ RESTORE();
+ if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+ if (updatewindow(strm, out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ in -= strm->avail_in;
+ out -= strm->avail_out;
+ strm->total_in += in;
+ strm->total_out += out;
+ state->total += out;
+ if (state->wrap && out)
+ strm->adler = state->check =
+ UPDATE(state->check, strm->next_out - out, out);
+ strm->data_type = state->bits + (state->last ? 64 : 0) +
+ (state->mode == TYPE ? 128 : 0);
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+ return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->window != Z_NULL) ZFREE(strm, state->window);
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ struct inflate_state FAR *state;
+ unsigned long id;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->wrap != 0 && state->mode != DICT)
+ return Z_STREAM_ERROR;
+
+ /* check for correct dictionary id */
+ if (state->mode == DICT) {
+ id = adler32(0L, Z_NULL, 0);
+ id = adler32(id, dictionary, dictLength);
+ if (id != state->check)
+ return Z_DATA_ERROR;
+ }
+
+ /* copy dictionary to window */
+ if (updatewindow(strm, strm->avail_out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ if (dictLength > state->wsize) {
+ zmemcpy(state->window, dictionary + dictLength - state->wsize,
+ state->wsize);
+ state->whave = state->wsize;
+ }
+ else {
+ zmemcpy(state->window + state->wsize - dictLength, dictionary,
+ dictLength);
+ state->whave = dictLength;
+ }
+ state->havedict = 1;
+ Tracev((stderr, "inflate: dictionary set\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+ /* save header structure */
+ state->head = head;
+ head->done = 0;
+ return Z_OK;
+}
+
+/*
+ Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found
+ or when out of input. When called, *have is the number of pattern bytes
+ found in order so far, in 0..3. On return *have is updated to the new
+ state. If on return *have equals four, then the pattern was found and the
+ return value is how many bytes were read including the last byte of the
+ pattern. If *have is less than four, then the pattern has not been found
+ yet and the return value is len. In the latter case, syncsearch() can be
+ called again with more data and the *have state. *have is initialized to
+ zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+ unsigned got;
+ unsigned next;
+
+ got = *have;
+ next = 0;
+ while (next < len && got < 4) {
+ if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+ got++;
+ else if (buf[next])
+ got = 0;
+ else
+ got = 4 - got;
+ next++;
+ }
+ *have = got;
+ return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+ unsigned len; /* number of bytes to look at or looked at */
+ unsigned long in, out; /* temporary to save total_in and total_out */
+ unsigned char buf[4]; /* to restore bit buffer to byte string */
+ struct inflate_state FAR *state;
+
+ /* check parameters */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+ /* if first time, start search in bit buffer */
+ if (state->mode != SYNC) {
+ state->mode = SYNC;
+ state->hold <<= state->bits & 7;
+ state->bits -= state->bits & 7;
+ len = 0;
+ while (state->bits >= 8) {
+ buf[len++] = (unsigned char)(state->hold);
+ state->hold >>= 8;
+ state->bits -= 8;
+ }
+ state->have = 0;
+ syncsearch(&(state->have), buf, len);
+ }
+
+ /* search available input */
+ len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+ strm->avail_in -= len;
+ strm->next_in += len;
+ strm->total_in += len;
+
+ /* return no joy or set up to restart inflate() on a new block */
+ if (state->have != 4) return Z_DATA_ERROR;
+ in = strm->total_in; out = strm->total_out;
+ inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->mode = TYPE;
+ return Z_OK;
+}
+
+/*
+ Returns true if inflate is currently at the end of a block generated by
+ Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses
+ Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+ block. When decompressing, PPP checks that at the end of input packet,
+ inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+ struct inflate_state FAR *state;
+ struct inflate_state FAR *copy;
+ unsigned char FAR *window;
+ unsigned wsize;
+
+ /* check input */
+ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+ source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)source->state;
+
+ /* allocate space */
+ copy = (struct inflate_state FAR *)
+ ZALLOC(source, 1, sizeof(struct inflate_state));
+ if (copy == Z_NULL) return Z_MEM_ERROR;
+ window = Z_NULL;
+ if (state->window != Z_NULL) {
+ window = (unsigned char FAR *)
+ ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+ if (window == Z_NULL) {
+ ZFREE(source, copy);
+ return Z_MEM_ERROR;
+ }
+ }
+
+ /* copy state */
+ zmemcpy(dest, source, sizeof(z_stream));
+ zmemcpy(copy, state, sizeof(struct inflate_state));
+ if (state->lencode >= state->codes &&
+ state->lencode <= state->codes + ENOUGH - 1) {
+ copy->lencode = copy->codes + (state->lencode - state->codes);
+ copy->distcode = copy->codes + (state->distcode - state->codes);
+ }
+ copy->next = copy->codes + (state->next - state->codes);
+ if (window != Z_NULL) {
+ wsize = 1U << state->wbits;
+ zmemcpy(window, state->window, wsize);
+ }
+ copy->window = window;
+ dest->state = (struct internal_state FAR *)copy;
+ return Z_OK;
+}
diff --git a/dep/StormLib/src/zlib/inflate.h b/dep/StormLib/src/zlib/inflate.h
new file mode 100644
index 00000000000..07bd3e78a7c
--- /dev/null
+++ b/dep/StormLib/src/zlib/inflate.h
@@ -0,0 +1,115 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip decoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ HEAD, /* i: waiting for magic header */
+ FLAGS, /* i: waiting for method and flags (gzip) */
+ TIME, /* i: waiting for modification time (gzip) */
+ OS, /* i: waiting for extra flags and operating system (gzip) */
+ EXLEN, /* i: waiting for extra length (gzip) */
+ EXTRA, /* i: waiting for extra bytes (gzip) */
+ NAME, /* i: waiting for end of file name (gzip) */
+ COMMENT, /* i: waiting for end of comment (gzip) */
+ HCRC, /* i: waiting for header crc (gzip) */
+ DICTID, /* i: waiting for dictionary check value */
+ DICT, /* waiting for inflateSetDictionary() call */
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ TYPEDO, /* i: same, but skip check to exit inflate on new block */
+ STORED, /* i: waiting for stored size (length and complement) */
+ COPY, /* i/o: waiting for input or output to copy stored block */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LENLENS, /* i: waiting for code length code lengths */
+ CODELENS, /* i: waiting for length/lit and distance code lengths */
+ LEN, /* i: waiting for length/lit code */
+ LENEXT, /* i: waiting for length extra bits */
+ DIST, /* i: waiting for distance code */
+ DISTEXT, /* i: waiting for distance extra bits */
+ MATCH, /* o: waiting for output space to copy string */
+ LIT, /* o: waiting for output space to write literal */
+ CHECK, /* i: waiting for 32-bit check value */
+ LENGTH, /* i: waiting for 32-bit length (gzip) */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD, /* got a data error -- remain here until reset */
+ MEM, /* got an inflate() memory error -- remain here until reset */
+ SYNC /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+ Process header:
+ HEAD -> (gzip) or (zlib)
+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+ NAME -> COMMENT -> HCRC -> TYPE
+ (zlib) -> DICTID or TYPE
+ DICTID -> DICT -> TYPE
+ Read deflate blocks:
+ TYPE -> STORED or TABLE or LEN or CHECK
+ STORED -> COPY -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN
+ Read deflate codes:
+ LEN -> LENEXT or LIT or TYPE
+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+ LIT -> LEN
+ Process trailer:
+ CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls. Approximately 7K bytes. */
+struct inflate_state {
+ inflate_mode mode; /* current inflate mode */
+ int last; /* true if processing last block */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int havedict; /* true if dictionary provided */
+ int flags; /* gzip header method and flags (0 if zlib) */
+ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
+ unsigned long check; /* protected copy of check value */
+ unsigned long total; /* protected copy of output count */
+ gz_headerp head; /* where to save gzip header information */
+ /* sliding window */
+ unsigned wbits; /* log base 2 of requested window size */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* bit accumulator */
+ unsigned long hold; /* input bit accumulator */
+ unsigned bits; /* number of bits in "in" */
+ /* for string and stored block copying */
+ unsigned length; /* literal or length of data to copy */
+ unsigned offset; /* distance back to copy string from */
+ /* for table and code decoding */
+ unsigned extra; /* extra bits needed */
+ /* fixed and dynamic code tables */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+};
diff --git a/dep/StormLib/src/zlib/inftrees.c b/dep/StormLib/src/zlib/inftrees.c
new file mode 100644
index 00000000000..8a9c13ff03d
--- /dev/null
+++ b/dep/StormLib/src/zlib/inftrees.c
@@ -0,0 +1,329 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+ " inflate 1.2.3 Copyright 1995-2005 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code this; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196};
+ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0};
+ static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) { /* no symbols to code at all */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)1;
+ this.val = (unsigned short)0;
+ *(*table)++ = this; /* make a table to force an error */
+ *(*table)++ = this;
+ *bits = 1;
+ return 0; /* no symbols, but wait for decoding to report error */
+ }
+ for (min = 1; min <= MAXBITS; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked when a LENS table is being made
+ against the space in *table, ENOUGH, minus the maximum space needed by
+ the worst case distance code, MAXD. This should never happen, but the
+ sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+ This assumes that when type == LENS, bits == 9.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ this.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ this.op = (unsigned char)0;
+ this.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ this.op = (unsigned char)(extra[work[sym]]);
+ this.val = base[work[sym]];
+ }
+ else {
+ this.op = (unsigned char)(32 + 64); /* end of block */
+ this.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ min = fill; /* save offset to next table */
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = this;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += min; /* here min is 1 << curr */
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /*
+ Fill in rest of table for incomplete codes. This loop is similar to the
+ loop above in incrementing huff for table indices. It is assumed that
+ len is equal to curr + drop, so there is no loop needed to increment
+ through high index bits. When the current sub-table is filled, the loop
+ drops back to the root table to fill in any remaining entries there.
+ */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)(len - drop);
+ this.val = (unsigned short)0;
+ while (huff != 0) {
+ /* when done with sub-table, drop back to root table */
+ if (drop != 0 && (huff & mask) != low) {
+ drop = 0;
+ len = root;
+ next = *table;
+ this.bits = (unsigned char)len;
+ }
+
+ /* put invalid code marker in table */
+ next[huff >> drop] = this;
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
diff --git a/dep/StormLib/src/zlib/inftrees.h b/dep/StormLib/src/zlib/inftrees.h
new file mode 100644
index 00000000000..b1104c87e76
--- /dev/null
+++ b/dep/StormLib/src/zlib/inftrees.h
@@ -0,0 +1,55 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 0001eeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of dynamic tree. The maximum found in a long but non-
+ exhaustive search was 1444 code structures (852 for length/literals
+ and 592 for distances, the latter actually the result of an
+ exhaustive search). The true maximum is not known, but the value
+ below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+extern int inflate_table OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
diff --git a/dep/StormLib/src/zlib/trees.c b/dep/StormLib/src/zlib/trees.c
new file mode 100644
index 00000000000..395e4e16814
--- /dev/null
+++ b/dep/StormLib/src/zlib/trees.c
@@ -0,0 +1,1219 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2005 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+ ct_data *dtree));
+local void set_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (value << s->bi_valid);
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (val << s->bi_valid);\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if ((unsigned) tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+ s->depth[n] : s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the last real code (before
+ * the EOB of the previous block) was thus at least one plus the length
+ * of the EOB plus what we have just sent of the empty static block.
+ */
+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L;
+#endif
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is binary or text */
+ if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN)
+ set_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute the block lengths in bytes. */
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+eof, 3);
+ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+eof, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (eof) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ ct_data *ltree; /* literal tree */
+ ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+ "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to BINARY or TEXT, using a crude approximation:
+ * set it to Z_TEXT if all symbols are either printable characters (33 to 255)
+ * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise.
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local void set_data_type(s)
+ deflate_state *s;
+{
+ int n;
+
+ for (n = 0; n < 9; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ break;
+ if (n == 9)
+ for (n = 14; n < 32; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ break;
+ s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
diff --git a/dep/StormLib/src/zlib/trees.h b/dep/StormLib/src/zlib/trees.h
new file mode 100644
index 00000000000..72facf900f7
--- /dev/null
+++ b/dep/StormLib/src/zlib/trees.h
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
diff --git a/dep/StormLib/src/zlib/zconf.h b/dep/StormLib/src/zlib/zconf.h
new file mode 100644
index 00000000000..03a9431c8be
--- /dev/null
+++ b/dep/StormLib/src/zlib/zconf.h
@@ -0,0 +1,332 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflateParams z_deflateParams
+# define deflateBound z_deflateBound
+# define deflatePrime z_deflatePrime
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateCopy z_inflateCopy
+# define inflateReset z_inflateReset
+# define inflateBack z_inflateBack
+# define inflateBackEnd z_inflateBackEnd
+# define compress z_compress
+# define compress2 z_compress2
+# define compressBound z_compressBound
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+# define zError z_zError
+
+# define alloc_func z_alloc_func
+# define free_func z_free_func
+# define in_func z_in_func
+# define out_func z_out_func
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+# define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+# ifndef SYS16BIT
+# define SYS16BIT
+# endif
+# endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+# ifndef STDC
+# define STDC
+# endif
+# if __STDC_VERSION__ >= 199901L
+# ifndef STDC99
+# define STDC99
+# endif
+# endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+# define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const /* note: need a more gentle solution here */
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+# if defined(M_I86SM) || defined(M_I86MM)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+# if (defined(__SMALL__) || defined(__MEDIUM__))
+ /* Turbo C small or medium model */
+# define SMALL_MEDIUM
+# ifdef __BORLANDC__
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+ /* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+# ifdef ZLIB_DLL
+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+# ifdef ZLIB_INTERNAL
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+# endif
+# endif /* ZLIB_DLL */
+ /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+ * define ZLIB_WINAPI.
+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+ */
+# ifdef ZLIB_WINAPI
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+ /* No need for _export, use ZLIB.DEF instead. */
+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR CDECL
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# ifdef ZLIB_DLL
+# ifdef ZLIB_INTERNAL
+# define ZEXPORT __declspec(dllexport)
+# define ZEXPORTVA __declspec(dllexport)
+# else
+# define ZEXPORT __declspec(dllimport)
+# define ZEXPORTVA __declspec(dllimport)
+# endif
+# endif
+#endif
+
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void const *voidpc;
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte const *voidpc;
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */
+# include <sys/types.h> /* for off_t */
+# include <unistd.h> /* for SEEK_* and off_t */
+# ifdef VMS
+# include <unixio.h> /* for off_t */
+# endif
+# define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+#if defined(__OS400__)
+# define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+# define NO_vsnprintf
+# ifdef FAR
+# undef FAR
+# endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+# pragma map(deflateInit_,"DEIN")
+# pragma map(deflateInit2_,"DEIN2")
+# pragma map(deflateEnd,"DEEND")
+# pragma map(deflateBound,"DEBND")
+# pragma map(inflateInit_,"ININ")
+# pragma map(inflateInit2_,"ININ2")
+# pragma map(inflateEnd,"INEND")
+# pragma map(inflateSync,"INSY")
+# pragma map(inflateSetDictionary,"INSEDI")
+# pragma map(compressBound,"CMBND")
+# pragma map(inflate_table,"INTABL")
+# pragma map(inflate_fast,"INFA")
+# pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/dep/StormLib/src/zlib/zlib.h b/dep/StormLib/src/zlib/zlib.h
new file mode 100644
index 00000000000..022817927ce
--- /dev/null
+++ b/dep/StormLib/src/zlib/zlib.h
@@ -0,0 +1,1357 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.3, July 18th, 2005
+
+ Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.3"
+#define ZLIB_VERNUM 0x1230
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms will be added later and will have the same
+ stream interface.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The compressed data format used by default by the in-memory functions is
+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+ around a deflate stream, which is itself documented in RFC 1951.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio using the functions that start
+ with "gz". The gzip format is different from the zlib format. gzip is a
+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+ This library can optionally read and write gzip streams in memory as well.
+
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never
+ crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: binary or text */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ gzip header information passed to and from zlib routines. See RFC 1952
+ for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+ int text; /* true if compressed data believed to be text */
+ uLong time; /* modification time */
+ int xflags; /* extra flags (not used when writing a gzip file) */
+ int os; /* operating system */
+ Bytef *extra; /* pointer to extra field or Z_NULL if none */
+ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */
+ uInt extra_max; /* space at extra (only when reading header) */
+ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */
+ uInt name_max; /* space at name (only when reading header) */
+ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */
+ uInt comm_max; /* space at comment (only when reading header) */
+ int hcrc; /* true if there was or will be a header crc */
+ int done; /* true when done reading gzip header (not used
+ when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+#define Z_BLOCK 5
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_RLE 3
+#define Z_FIXED 4
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_TEXT 1
+#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce some
+ output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+ decide how much data to accumualte before producing output, in order to
+ maximize compression.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In particular
+ avail_in is zero after the call if enough output space has been provided
+ before the call.) Flushing may degrade compression for some compression
+ algorithms and so it should be used only when necessary.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+ avail_out is greater than six to avoid repeated flush markers due to
+ avail_out == 0 on return.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ the value returned by deflateBound (see below). If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update strm->data_type if it can make a good guess about
+ the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+ fatal, and deflate() can be called again with more input and more output
+ space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+ value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller. msg is set to null if there is no error
+ message. inflateInit does not perform any decompression apart from reading
+ the zlib header if present: this will be done by inflate(). (So next_in and
+ avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+ Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+ if and when it gets to the next deflate block boundary. When decoding the
+ zlib or gzip format, this will cause inflate() to return immediately after
+ the header and before the first block. When doing a raw inflate, inflate()
+ will go ahead and process the first block, and will return when it gets to
+ the end of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64
+ if inflate() is currently decoding the last block in the deflate stream,
+ plus 128 if inflate() returned immediately after decoding an end-of-block
+ code or decoding the complete header up to just before the first byte of the
+ deflate stream. The end-of-block will not be indicated until all of the
+ uncompressed data from that block has been written to strm->next_out. The
+ number of unused bits may in general be greater than seven, except when
+ bit 7 of data_type is set, in which case the number of unused bits will be
+ less than eight.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster approach
+ may be used for the single inflate() call.
+
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the only effect of the flush parameter in this implementation
+ is on the return value of inflate(), as noted below, or when it returns early
+ because Z_BLOCK is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm->adler to the adler32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the adler32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically. Any information
+ contained in the gzip header is not retained, so applications that need that
+ information should instead use raw inflate, see inflateInit2() below, or
+ inflateBack() and perform their own processing of the gzip header and
+ trailer.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may then
+ call inflateSync() to look for a good compression block if a partial recovery
+ of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+ determines the window size. deflate() will then generate raw deflate data
+ with no zlib header or trailer, and will not compute an adler32 check value.
+
+ windowBits can also be greater than 15 for optional gzip encoding. Add
+ 16 to windowBits to write a simple gzip header and trailer around the
+ compressed data instead of a zlib wrapper. The gzip header will have no
+ file name, no extra data, no comment, no modification time (set to zero),
+ no header crc, and the operating system will be set to 255 (unknown). If a
+ gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match), or Z_RLE to limit match distances to one (run-length
+ encoding). Filtered data consists mostly of small values with a somewhat
+ random distribution. In this case, the compression algorithm is tuned to
+ compress them better. The effect of Z_FILTERED is to force more Huffman
+ coding and less string matching; it is somewhat intermediate between
+ Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+ Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+ parameter only affects the compression ratio but not the correctness of the
+ compressed output even if it is not set appropriately. Z_FIXED prevents the
+ use of dynamic Huffman codes, allowing for a simpler decoder for special
+ applications.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+ method). msg is set to null if there is no error message. deflateInit2 does
+ not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any
+ call of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size in
+ deflate or deflate2. Thus the strings most likely to be useful should be
+ put at the end of the dictionary, not at the front. In addition, the
+ current implementation of deflate will use at most the window size minus
+ 262 bytes of the provided dictionary.
+
+ Upon return of this function, strm->adler is set to the adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.) If a raw deflate was requested, then the
+ adler32 value is not computed and strm->adler is not set.
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different
+ strategy. If the compression level is changed, the input available so far
+ is compressed with the old level (and may be flushed); the new level will
+ take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+ int good_length,
+ int max_lazy,
+ int nice_length,
+ int max_chain));
+/*
+ Fine tune deflate's internal compression parameters. This should only be
+ used by someone who understands the algorithm used by zlib's deflate for
+ searching for the best matching string, and even then only by the most
+ fanatic optimizer trying to squeeze out the last compressed bit for their
+ specific input data. Read the deflate.c source code for the meaning of the
+ max_lazy, good_length, nice_length, and max_chain parameters.
+
+ deflateTune() can be called after deflateInit() or deflateInit2(), and
+ returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+ uLong sourceLen));
+/*
+ deflateBound() returns an upper bound on the compressed size after
+ deflation of sourceLen bytes. It must be called after deflateInit()
+ or deflateInit2(). This would be used to allocate an output buffer
+ for deflation in a single pass, and so would be called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ deflatePrime() inserts bits in the deflate output stream. The intent
+ is that this function is used to start off the deflate output with the
+ bits leftover from a previous deflate stream when appending to it. As such,
+ this function can only be used for raw deflate, and must be used before the
+ first deflate() call after a deflateInit2() or deflateReset(). bits must be
+ less than or equal to 16, and that many of the least significant bits of
+ value will be inserted in the output.
+
+ deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ deflateSetHeader() provides gzip header information for when a gzip
+ stream is requested by deflateInit2(). deflateSetHeader() may be called
+ after deflateInit2() or deflateReset() and before the first call of
+ deflate(). The text, time, os, extra field, name, and comment information
+ in the provided gz_header structure are written to the gzip header (xflag is
+ ignored -- the extra flags are set according to the compression level). The
+ caller must assure that, if not Z_NULL, name and comment are terminated with
+ a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+ available there. If hcrc is true, a gzip header crc is included. Note that
+ the current versions of the command-line version of gzip (up through version
+ 1.3.x) do not support header crc's, and will report that it is a "multi-part
+ gzip file" and give up.
+
+ If deflateSetHeader is not used, the default gzip header has text false,
+ the time set to zero, and os set to 255, with no extra, name, or comment
+ fields. The gzip header is returned to the default state by deflateReset().
+
+ deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is
+ a crc32 instead of an adler32.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+ is set to null if there is no error message. inflateInit2 does not perform
+ any decompression apart from reading the zlib header if present: this will
+ be done by inflate(). (So next_in and avail_in may be modified, but next_out
+ and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate,
+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by that call of inflate.
+ The compressor and decompressor must use exactly the same dictionary (see
+ deflateSetDictionary). For raw inflate, this function can be called
+ immediately after inflateInit2() or inflateReset() and before any call of
+ inflate() to set the dictionary. The application must insure that the
+ dictionary that was used for compression is provided.
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when randomly accessing a large stream. The
+ first pass through the stream can periodically record the inflate state,
+ allowing restarting inflate at those points when randomly accessing the
+ stream.
+
+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ This function inserts bits in the inflate input stream. The intent is
+ that this function is used to start inflating at a bit position in the
+ middle of a byte. The provided bits will be used before any bytes are used
+ from next_in. This function should only be used with raw inflate, and
+ should be used before the first inflate() call after inflateInit2() or
+ inflateReset(). bits must be less than or equal to 16, and that many of the
+ least significant bits of value will be inserted in the input.
+
+ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ inflateGetHeader() requests that gzip header information be stored in the
+ provided gz_header structure. inflateGetHeader() may be called after
+ inflateInit2() or inflateReset(), and before the first call of inflate().
+ As inflate() processes the gzip stream, head->done is zero until the header
+ is completed, at which time head->done is set to one. If a zlib stream is
+ being decoded, then head->done is set to -1 to indicate that there will be
+ no gzip header information forthcoming. Note that Z_BLOCK can be used to
+ force inflate() to return immediately after header processing is complete
+ and before any actual data is decompressed.
+
+ The text, time, xflags, and os fields are filled in with the gzip header
+ contents. hcrc is set to true if there is a header CRC. (The header CRC
+ was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+ contains the maximum number of bytes to write to extra. Once done is true,
+ extra_len contains the actual extra field length, and extra contains the
+ extra field, or that field truncated if extra_max is less than extra_len.
+ If name is not Z_NULL, then up to name_max characters are written there,
+ terminated with a zero unless the length is greater than name_max. If
+ comment is not Z_NULL, then up to comm_max characters are written there,
+ terminated with a zero unless the length is greater than comm_max. When
+ any of extra, name, or comment are not Z_NULL and the respective field is
+ not present in the header, then that field is set to Z_NULL to signal its
+ absence. This allows the use of deflateSetHeader() with the returned
+ structure to duplicate the header. However if those fields are set to
+ allocated memory, then the application will need to save those pointers
+ elsewhere so that they can be eventually freed.
+
+ If inflateGetHeader is not used, then the header information is simply
+ discarded. The header is always checked for validity, including the header
+ CRC if present. inflateReset() will reset the process to discard the header
+ information. The application would need to call inflateGetHeader() again to
+ retrieve the header from the next gzip stream.
+
+ inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window));
+
+ Initialize the internal stream state for decompression using inflateBack()
+ calls. The fields zalloc, zfree and opaque in strm must be initialized
+ before the call. If zalloc and zfree are Z_NULL, then the default library-
+ derived memory allocation routines are used. windowBits is the base two
+ logarithm of the window size, in the range 8..15. window is a caller
+ supplied buffer of that size. Except for special applications where it is
+ assured that deflate was used with small window sizes, windowBits must be 15
+ and a 32K byte window must be supplied to be able to decompress general
+ deflate streams.
+
+ See inflateBack() for the usage of these routines.
+
+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+ the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+ be allocated, or Z_VERSION_ERROR if the version of the library does not
+ match the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+/*
+ inflateBack() does a raw inflate with a single call using a call-back
+ interface for input and output. This is more efficient than inflate() for
+ file i/o applications in that it avoids copying between the output and the
+ sliding window by simply making the window itself the output buffer. This
+ function trusts the application to not change the output buffer passed by
+ the output function, at least until inflateBack() returns.
+
+ inflateBackInit() must be called first to allocate the internal state
+ and to initialize the state with the user-provided window buffer.
+ inflateBack() may then be used multiple times to inflate a complete, raw
+ deflate stream with each call. inflateBackEnd() is then called to free
+ the allocated state.
+
+ A raw deflate stream is one with no zlib or gzip header or trailer.
+ This routine would normally be used in a utility that reads zip or gzip
+ files and writes out uncompressed files. The utility would decode the
+ header and process the trailer on its own, hence this routine expects
+ only the raw deflate stream to decompress. This is different from the
+ normal behavior of inflate(), which expects either a zlib or gzip header and
+ trailer around the deflate stream.
+
+ inflateBack() uses two subroutines supplied by the caller that are then
+ called by inflateBack() for input and output. inflateBack() calls those
+ routines until it reads a complete deflate stream and writes out all of the
+ uncompressed data, or until it encounters an error. The function's
+ parameters and return types are defined above in the in_func and out_func
+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the
+ number of bytes of provided input, and a pointer to that input in buf. If
+ there is no input available, in() must return zero--buf is ignored in that
+ case--and inflateBack() will return a buffer error. inflateBack() will call
+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
+ should return zero on success, or non-zero on failure. If out() returns
+ non-zero, inflateBack() will return with an error. Neither in() nor out()
+ are permitted to change the contents of the window provided to
+ inflateBackInit(), which is also the buffer that out() uses to write from.
+ The length written by out() will be at most the window size. Any non-zero
+ amount of input may be provided by in().
+
+ For convenience, inflateBack() can be provided input on the first call by
+ setting strm->next_in and strm->avail_in. If that input is exhausted, then
+ in() will be called. Therefore strm->next_in must be initialized before
+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called
+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in
+ must also be initialized, and then if strm->avail_in is not zero, input will
+ initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+ The in_desc and out_desc parameters of inflateBack() is passed as the
+ first parameter of in() and out() respectively when they are called. These
+ descriptors can be optionally used to pass any information that the caller-
+ supplied in() and out() functions need to do their job.
+
+ On return, inflateBack() will set strm->next_in and strm->avail_in to
+ pass back any unused input that was provided by the last in() call. The
+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+ if in() or out() returned an error, Z_DATA_ERROR if there was a format
+ error in the deflate stream (in which case strm->msg is set to indicate the
+ nature of the error), or Z_STREAM_ERROR if the stream was not properly
+ initialized. In the case of Z_BUF_ERROR, an input or output error can be
+ distinguished using strm->next_in which will be Z_NULL only if in() returned
+ an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+ out() returning non-zero. (in() will always be called before out(), so
+ strm->next_in is assured to be defined if out() returns non-zero.) Note
+ that inflateBack() cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+ All memory allocated by inflateBackInit() is freed.
+
+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+ state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+ 1.0: size of uInt
+ 3.2: size of uLong
+ 5.4: size of voidpf (pointer)
+ 7.6: size of z_off_t
+
+ Compiler, assembler, and debug options:
+ 8: DEBUG
+ 9: ASMV or ASMINF -- use ASM code
+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+ 11: 0 (reserved)
+
+ One-time table building (smaller code, but not thread-safe if true):
+ 12: BUILDFIXED -- build static block decoding tables when needed
+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+ 14,15: 0 (reserved)
+
+ Library content (indicates missing functionality):
+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+ deflate code when not needed)
+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+ and decode gzip streams (to avoid linking crc code)
+ 18-19: 0 (reserved)
+
+ Operation variations (changes in library functionality):
+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+ 21: FASTEST -- deflate algorithm with only one, lowest compression level
+ 22,23: 0 (reserved)
+
+ The sprintf variant used by gzprintf (zero is best):
+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+ Remainder:
+ 27-31: 0 (reserved)
+ */
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level and memory usage,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least the value returned
+ by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+ compressBound() returns an upper bound on the compressed size after
+ compress() or compress2() on sourceLen bytes. It would be used before
+ a compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+ Huffman only compression as in "wb1h", or 'R' for run-length encoding
+ as in "wb1R". (See the description of deflateInit2 for more information
+ about the strategy parameter.)
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR). */
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ voidpc buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error). The number of
+ uncompressed bytes written is limited to 4095. The caller should assure that
+ this limit is not exceeded. If it is exceeded, then gzprintf() will return
+ return an error (0) with nothing written. In this case, there may also be a
+ buffer overflow with unpredictable consequences, which is possible only if
+ zlib was compiled with the insecure functions sprintf() or vsprintf()
+ because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or
+ a newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. The string is then terminated with a null
+ character.
+ gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+ Push one character back onto the stream to be read again later.
+ Only one character of push-back is allowed. gzungetc() returns the
+ character pushed, or -1 on failure. gzungetc() will fail if a
+ character has been pushed but not read yet, or if c is -1. The pushed
+ character will be discarded if the stream is repositioned with gzseek()
+ or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+/*
+ Sets the starting position for the next gzread or gzwrite on the
+ given compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+/*
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+ Returns 1 if file is being read directly without decompression, otherwise
+ zero.
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+ Clears the error and end-of-file flags for file. This is analogous to the
+ clearerr() function in stdio. This is useful for continuing to read a gzip
+ file that is being written concurrently.
+*/
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+ z_off_t len2));
+/*
+ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
+ and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+ each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running CRC-32 with the bytes buf[0..len-1] and return the
+ updated CRC-32. If buf is NULL, this function returns the required initial
+ value for the for the crc. Pre- and post-conditioning (one's complement) is
+ performed within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+/*
+ Combine two CRC-32 check values into one. For two sequences of bytes,
+ seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+ calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
+ check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+ len2.
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char * ZEXPORT zError OF((int));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/dep/StormLib/src/zlib/zutil.c b/dep/StormLib/src/zlib/zutil.c
new file mode 100644
index 00000000000..d55f5948a37
--- /dev/null
+++ b/dep/StormLib/src/zlib/zutil.c
@@ -0,0 +1,318 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+ uLong flags;
+
+ flags = 0;
+ switch (sizeof(uInt)) {
+ case 2: break;
+ case 4: flags += 1; break;
+ case 8: flags += 2; break;
+ default: flags += 3;
+ }
+ switch (sizeof(uLong)) {
+ case 2: break;
+ case 4: flags += 1 << 2; break;
+ case 8: flags += 2 << 2; break;
+ default: flags += 3 << 2;
+ }
+ switch (sizeof(voidpf)) {
+ case 2: break;
+ case 4: flags += 1 << 4; break;
+ case 8: flags += 2 << 4; break;
+ default: flags += 3 << 4;
+ }
+ switch (sizeof(z_off_t)) {
+ case 2: break;
+ case 4: flags += 1 << 6; break;
+ case 8: flags += 2 << 6; break;
+ default: flags += 3 << 6;
+ }
+#ifdef DEBUG
+ flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+ flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+ flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+ flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+ flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+ flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+ flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+ flags += 1L << 20;
+#endif
+#ifdef FASTEST
+ flags += 1L << 21;
+#endif
+#ifdef STDC
+# ifdef NO_vsnprintf
+ flags += 1L << 25;
+# ifdef HAS_vsprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_vsnprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#else
+ flags += 1L << 24;
+# ifdef NO_snprintf
+ flags += 1L << 25;
+# ifdef HAS_sprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_snprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#endif
+ return flags;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int z_verbose = verbose;
+
+void z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used.
+ */
+ int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+ (voidpf)calloc(items, size);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/dep/StormLib/src/zlib/zutil.h b/dep/StormLib/src/zlib/zutil.h
new file mode 100644
index 00000000000..b7d5eff81b6
--- /dev/null
+++ b/dep/StormLib/src/zlib/zutil.h
@@ -0,0 +1,269 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#ifdef STDC
+# ifndef _WIN32_WCE
+# include <stddef.h>
+# endif
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+# ifdef _WIN32_WCE
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used. We rename it to
+ * avoid conflict with other libraries that use the same workaround.
+ */
+# define errno z_errno
+# endif
+ extern int errno;
+#else
+# ifndef _WIN32_WCE
+# include <errno.h>
+# endif
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+# define OS_CODE 0x00
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+# ifdef M_I86
+ #include <malloc.h>
+# endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#ifdef WIN32
+# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
+# define OS_CODE 0x0b
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+# if defined(_WIN32_WCE)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# ifndef _PTRDIFF_T_DEFINED
+ typedef int ptrdiff_t;
+# define _PTRDIFF_T_DEFINED
+# endif
+# else
+# define fdopen(fd,type) _fdopen(fd,type)
+# endif
+#endif
+
+ /* common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#if defined(__CYGWIN__)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#ifndef HAVE_VSNPRINTF
+# ifdef MSDOS
+ /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+ but for now we just assume it doesn't. */
+# define NO_vsnprintf
+# endif
+# ifdef __TURBOC__
+# define NO_vsnprintf
+# endif
+# ifdef WIN32
+ /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+# if !defined(vsnprintf) && !defined(NO_vsnprintf)
+# define vsnprintf _vsnprintf
+# endif
+# endif
+# ifdef __SASC
+# define NO_vsnprintf
+# endif
+#endif
+#ifdef VMS
+# define NO_vsnprintf
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int z_verbose;
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* ZUTIL_H */
diff --git a/dep/StormLib/storm_dll/storm_dll.cpp b/dep/StormLib/storm_dll/storm_dll.cpp
new file mode 100644
index 00000000000..2941f2a37f5
--- /dev/null
+++ b/dep/StormLib/storm_dll/storm_dll.cpp
@@ -0,0 +1,117 @@
+/*****************************************************************************/
+/* Storm.cpp Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* This is just a dummy module for building import library for Storm.dll */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 11.04.03 1.00 Lad The first version of Storm.cpp */
+/*****************************************************************************/
+
+#include <windows.h>
+
+#define BUILDING_STORM_CPP
+#define STORM_ALTERNATE_NAMES
+#include "storm_dll.h"
+
+BOOL WINAPI SFILE(OpenArchive)(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, HANDLE *hMPQ)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI SFILE(CloseArchive)(HANDLE hMPQ)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI SFILE(GetArchiveName)(HANDLE hMPQ, LPCSTR lpBuffer, DWORD dwBufferLength)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI SFILE(OpenFile)(LPCSTR lpFileName, HANDLE *hFile)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI SFILE(OpenFileEx)(HANDLE hMPQ, LPCSTR lpFileName, DWORD dwSearchScope, HANDLE *hFile)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI SFILE(CloseFile)(HANDLE hFile)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+DWORD WINAPI SFILE(GetFileSize)(HANDLE hFile, LPDWORD lpFileSizeHigh)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI SFILE(GetFileArchive)(HANDLE hFile, HANDLE *hMPQ)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI SFILE(GetFileName)(HANDLE hFile, LPCSTR lpBuffer, DWORD dwBufferLength)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+DWORD WINAPI SFILE(SetFilePointer)(HANDLE hFile, long lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI SFILE(ReadFile)(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+LCID WINAPI SFILE(SetLocale)(LCID nNewLocale)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI SFILE(GetBasePath)(LPCSTR lpBuffer, DWORD dwBufferLength)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI SFILE(SetBasePath)(LPCSTR lpNewBasePath)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI SFILE(Destroy)()
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI SCOMP(Compress)(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int uCmp, int uCmpType, int nCmpLevel)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI SCOMP(Decompress)(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
diff --git a/dep/StormLib/storm_dll/storm_dll.def b/dep/StormLib/storm_dll/storm_dll.def
new file mode 100644
index 00000000000..8de88f5db3d
--- /dev/null
+++ b/dep/StormLib/storm_dll/storm_dll.def
@@ -0,0 +1,25 @@
+; Storm definition file with alternate Storm.dll names
+LIBRARY "Storm"
+
+EXPORTS
+ StormCloseArchive @252 ; 0x0FC
+ StormCloseFile @253 ; 0x0FD
+ StormDestroy @262 ; 0x106
+ StormGetFileArchive @264 ; 0x108
+ StormGetFileSize @265 ; 0x109
+ StormOpenArchive @266 ; 0x10A
+ StormOpenFile @267 ; 0x10B
+ StormOpenFileEx @268 ; 0x10C
+ StormReadFile @269 ; 0x10D
+ StormSetBasePath @270 ; 0x10E
+ StormSetFilePointer @271 ; 0x10F
+ StormSetLocale @272 ; 0x110
+ StormGetBasePath @273 ; 0x111
+ StormGetArchiveName @275 ; 0x113
+ StormGetFileName @276 ; 0x114
+
+; StormSetLastError @465 ; 0x
+
+ StormCompress @551 ; 0x227
+ StormDecompress @552 ; 0x228
+ \ No newline at end of file
diff --git a/dep/StormLib/storm_dll/storm_dll.h b/dep/StormLib/storm_dll/storm_dll.h
new file mode 100644
index 00000000000..6d67820a22f
--- /dev/null
+++ b/dep/StormLib/storm_dll/storm_dll.h
@@ -0,0 +1,67 @@
+/*****************************************************************************/
+/* Storm.h Copyright Justin Olbrantz(Quantam) 2000 */
+/*---------------------------------------------------------------------------*/
+/* Storm Interface Library v1.0 for Windows */
+/* */
+/* Author : Justin Olbrantz(Quantam) */
+/* E-mail : omega@dragonfire.net */
+/* WWW : www.campaigncreations.com/starcraft/mpq2k/inside_mopaq/ */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* xx.xx.00 1.00 Qua The first version of Storm.h */
+/* 11.04.03 1.00 Lad Added some functions */
+/*****************************************************************************/
+
+// We need the Windows data types for the Storm prototypes
+#include <windows.h>
+
+#ifndef __STORM_H__
+#define __STORM_H__
+
+// Somethimes is necessary to change the function names so they
+// will not conflict with other MPQ tools.
+#ifdef STORM_ALTERNATE_NAMES
+ #define SFILE(Name) Storm##Name
+ #define SCOMP(Name) Storm##Name
+#else
+ #define SFILE(Name) SFile##Name
+ #define SCOMP(Name) SComp##Name
+#endif
+
+
+// Just in case anyone is still using C out there
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Storm file function prototypes
+BOOL WINAPI SFILE(OpenArchive)(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, HANDLE *hMPQ);
+BOOL WINAPI SFILE(CloseArchive)(HANDLE hMPQ);
+BOOL WINAPI SFILE(GetArchiveName)(HANDLE hMPQ, LPCSTR lpBuffer, DWORD dwBufferLength);
+BOOL WINAPI SFILE(OpenFile)(LPCSTR lpFileName, HANDLE *hFile);
+BOOL WINAPI SFILE(OpenFileEx)(HANDLE hMPQ, LPCSTR lpFileName, DWORD dwSearchScope, HANDLE *hFile);
+BOOL WINAPI SFILE(CloseFile)(HANDLE hFile);
+DWORD WINAPI SFILE(GetFileSize)(HANDLE hFile, LPDWORD lpFileSizeHigh);
+BOOL WINAPI SFILE(GetFileArchive)(HANDLE hFile, HANDLE *hMPQ);
+BOOL WINAPI SFILE(GetFileName)(HANDLE hFile, LPCSTR lpBuffer, DWORD dwBufferLength);
+DWORD WINAPI SFILE(SetFilePointer)(HANDLE hFile, long lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod);
+BOOL WINAPI SFILE(ReadFile)(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped);
+LCID WINAPI SFILE(SetLocale)(LCID nNewLocale);
+BOOL WINAPI SFILE(GetBasePath)(LPCSTR lpBuffer, DWORD dwBufferLength);
+BOOL WINAPI SFILE(SetBasePath)(LPCSTR lpNewBasePath);
+
+// Storm (de)compression functions
+BOOL WINAPI SCOMP(Compress) (char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int uCmp, int uCmpType, int nCmpLevel);
+BOOL WINAPI SCOMP(Decompress)(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength);
+
+
+#if defined(_MSC_VER) && !defined(BUILDING_STORM_CPP)
+#pragma comment(lib, "Storm.lib") // Force linking Storm.lib and thus Storm.dll
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __STORM_H__
diff --git a/dep/StormLib/stormlib_dll/DllMain.c b/dep/StormLib/stormlib_dll/DllMain.c
new file mode 100644
index 00000000000..cbfa84a08a8
--- /dev/null
+++ b/dep/StormLib/stormlib_dll/DllMain.c
@@ -0,0 +1,24 @@
+/*****************************************************************************/
+/* DllMain.c Copyright (c) Ladislav Zezula 2006 */
+/*---------------------------------------------------------------------------*/
+/* Description: DllMain for the StormLib.dll library */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 23.11.06 1.00 Lad The first version of DllMain.c */
+/*****************************************************************************/
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+//-----------------------------------------------------------------------------
+// DllMain
+
+DWORD WINAPI DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved)
+{
+ UNREFERENCED_PARAMETER(hInst);
+ UNREFERENCED_PARAMETER(dwReason);
+ UNREFERENCED_PARAMETER(lpReserved);
+
+ return TRUE;
+}
diff --git a/dep/StormLib/stormlib_dll/StormLib.def b/dep/StormLib/stormlib_dll/StormLib.def
new file mode 100644
index 00000000000..0ba91884313
--- /dev/null
+++ b/dep/StormLib/stormlib_dll/StormLib.def
@@ -0,0 +1,76 @@
+;
+; Export file for Windows
+; Copyright (c) 2007-2010 Ladislav Zezula
+; ladik@zezula.net
+;
+
+LIBRARY StormLib.dll
+
+EXPORTS
+
+ SFileSetLocale
+ SFileGetLocale
+
+ SFileOpenArchive
+ SFileCreateArchive
+ SFileGetArchiveBitmap
+ SFileFlushArchive
+ SFileCloseArchive
+
+ SFileAddListFile
+
+ SFileSetCompactCallback
+ SFileCompactArchive
+
+ SFileGetMaxFileCount
+ SFileSetMaxFileCount
+
+ SFileGetAttributes
+ SFileSetAttributes
+ SFileUpdateFileAttributes
+
+ SFileOpenPatchArchive
+ SFileIsPatchedArchive
+
+ SFileOpenFileEx
+ SFileGetFileSize
+ SFileSetFilePointer
+ SFileReadFile
+ SFileCloseFile
+
+ SFileHasFile
+ SFileGetFileName
+ SFileGetFileInfo
+
+ SFileExtractFile
+
+ SFileVerifyFile
+ SFileVerifyRawData
+ SFileVerifyArchive
+
+ SFileFindFirstFile
+ SFileFindNextFile
+ SFileFindClose
+
+ SListFileFindFirstFile
+ SListFileFindNextFile
+ SListFileFindClose
+
+ SFileEnumLocales
+
+ SFileCreateFile
+ SFileWriteFile
+ SFileFinishFile
+ SFileAddFileEx
+ SFileAddFile
+ SFileAddWave
+ SFileRemoveFile
+ SFileRenameFile
+ SFileSetFileLocale
+ SFileSetDataCompression
+ SFileSetAddFileCallback
+
+ SCompImplode
+ SCompExplode
+ SCompCompress
+ SCompDecompress
diff --git a/dep/StormLib/stormlib_dll/StormLib.exp b/dep/StormLib/stormlib_dll/StormLib.exp
new file mode 100644
index 00000000000..aa18edb7aab
--- /dev/null
+++ b/dep/StormLib/stormlib_dll/StormLib.exp
@@ -0,0 +1,75 @@
+#
+# Export file for Mac OS X
+# Copyright (c) 2009 Sam Wilkins
+# swilkins1337@gmail.com
+#
+
+_SFileSetLocale
+_SFileGetLocale
+
+_SFileOpenArchive
+_SFileCreateArchive
+_SFileGetArchiveBitmap
+_SFileFlushArchive
+_SFileCloseArchive
+
+_SFileAddListFile
+
+_SFileSetCompactCallback
+_SFileCompactArchive
+
+_SFileGetMaxFileCount
+_SFileSetMaxFileCount
+
+_SFileGetAttributes
+_SFileSetAttributes
+_SFileUpdateFileAttributes
+
+_SFileOpenPatchArchive
+_SFileIsPatchedArchive
+
+_SFileOpenFileEx
+_SFileGetFileSize
+_SFileSetFilePointer
+_SFileReadFile
+_SFileCloseFile
+
+_SFileHasFile
+_SFileGetFileName
+_SFileGetFileInfo
+
+_SFileExtractFile
+
+_SFileVerifyFile
+_SFileVerifyRawData
+_SFileVerifyArchive
+
+_SFileFindFirstFile
+_SFileFindNextFile
+_SFileFindClose
+
+_SListFileFindFirstFile
+_SListFileFindNextFile
+_SListFileFindClose
+
+_SFileEnumLocales
+
+_SFileCreateFile
+_SFileWriteFile
+_SFileFinishFile
+_SFileAddFileEx
+_SFileAddFile
+_SFileAddWave
+_SFileRemoveFile
+_SFileRenameFile
+_SFileSetFileLocale
+_SFileSetDataCompression
+_SFileSetAddFileCallback
+
+_SCompImplode
+_SCompExplode
+_SCompCompress
+_SCompDecompress
+
+_SetLastError
+_GetLastError
diff --git a/dep/StormLib/test/Test.cpp b/dep/StormLib/test/Test.cpp
new file mode 100644
index 00000000000..e31c15fee29
--- /dev/null
+++ b/dep/StormLib/test/Test.cpp
@@ -0,0 +1,1892 @@
+/*****************************************************************************/
+/* StormLibTest.cpp Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Test module for StormLib */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 25.03.03 1.00 Lad The first version of StormLibTest.cpp */
+/*****************************************************************************/
+
+#define _CRT_SECURE_NO_DEPRECATE
+#define __INCLUDE_CRYPTOGRAPHY__
+#define __STORMLIB_SELF__ // Don't use StormLib.lib
+#include <stdio.h>
+
+#ifdef _MSC_VER
+#include <crtdbg.h>
+#endif
+
+#include "../src/StormLib.h"
+#include "../src/StormCommon.h"
+
+#ifdef _MSC_VER
+#pragma warning(disable: 4505) // 'XXX' : unreferenced local function has been removed
+#endif
+
+//------------------------------------------------------------------------------
+// Defines
+
+#ifdef PLATFORM_WINDOWS
+#define WORK_PATH_ROOT "E:\\Multimedia\\MPQs\\"
+#endif
+
+#ifdef PLATFORM_LINUX
+#define WORK_PATH_ROOT "/home/user/MPQs/"
+#endif
+
+#ifdef PLATFORM_MAC
+#define WORK_PATH_ROOT "/Users/sam/StormLib/test"
+#endif
+
+#ifndef LANG_CZECH
+#define LANG_CZECH 0x0405
+#endif
+
+#define MPQ_SECTOR_SIZE 0x1000
+
+#define MAKE_PATH(path) _T(WORK_PATH_ROOT) _T(path)
+
+// Unicode MPQ names
+/* Czech */ static const wchar_t szUnicodeName1[] = {0x010C, 0x0065, 0x0073, 0x006B, 0x00FD, _T('.'), _T('m'), _T('p'), _T('q'), 0};
+/* Russian */ static const wchar_t szUnicodeName2[] = {0x0420, 0x0443, 0x0441, 0x0441, 0x043A, 0x0438, 0x0439, _T('.'), _T('m'), _T('p'), _T('q'), 0};
+/* Greece */ static const wchar_t szUnicodeName3[] = {0x03B5, 0x03BB, 0x03BB, 0x03B7, 0x03BD, 0x03B9, 0x03BA, 0x03AC, _T('.'), _T('m'), _T('p'), _T('q'), 0};
+/* Chinese */ static const wchar_t szUnicodeName4[] = {0x65E5, 0x672C, 0x8A9E, _T('.'), _T('m'), _T('p'), _T('q'), 0};
+/* Japanese */ static const wchar_t szUnicodeName5[] = {0x7B80, 0x4F53, 0x4E2D, 0x6587, _T('.'), _T('m'), _T('p'), _T('q'), 0};
+/* Arabic */ static const wchar_t szUnicodeName6[] = {0x0627, 0x0644, 0x0639, 0x0639, 0x0631, 0x0628, 0x064A, 0x0629, _T('.'), _T('m'), _T('p'), _T('q'), 0};
+
+//-----------------------------------------------------------------------------
+// Constants
+
+static const TCHAR * szWorkDir = MAKE_PATH("Work");
+
+static unsigned int AddFlags[] =
+{
+// Compression Encryption Fixed key Single Unit Sector CRC
+ 0 | 0 | 0 | 0 | 0,
+ 0 | MPQ_FILE_ENCRYPTED | 0 | 0 | 0,
+ 0 | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | 0 | 0,
+ 0 | 0 | 0 | MPQ_FILE_SINGLE_UNIT | 0,
+ 0 | MPQ_FILE_ENCRYPTED | 0 | MPQ_FILE_SINGLE_UNIT | 0,
+ 0 | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | MPQ_FILE_SINGLE_UNIT | 0,
+ MPQ_FILE_IMPLODE | 0 | 0 | 0 | 0,
+ MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | 0 | 0 | 0,
+ MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | 0 | 0,
+ MPQ_FILE_IMPLODE | 0 | 0 | MPQ_FILE_SINGLE_UNIT | 0,
+ MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | 0 | MPQ_FILE_SINGLE_UNIT | 0,
+ MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | MPQ_FILE_SINGLE_UNIT | 0,
+ MPQ_FILE_IMPLODE | 0 | 0 | 0 | MPQ_FILE_SECTOR_CRC,
+ MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | 0 | 0 | MPQ_FILE_SECTOR_CRC,
+ MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | 0 | MPQ_FILE_SECTOR_CRC,
+ MPQ_FILE_COMPRESS | 0 | 0 | 0 | 0,
+ MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | 0 | 0 | 0,
+ MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | 0 | 0,
+ MPQ_FILE_COMPRESS | 0 | 0 | MPQ_FILE_SINGLE_UNIT | 0,
+ MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | 0 | MPQ_FILE_SINGLE_UNIT | 0,
+ MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | MPQ_FILE_SINGLE_UNIT | 0,
+ MPQ_FILE_COMPRESS | 0 | 0 | 0 | MPQ_FILE_SECTOR_CRC,
+ MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | 0 | 0 | MPQ_FILE_SECTOR_CRC,
+ MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | 0 | MPQ_FILE_SECTOR_CRC,
+ 0xFFFFFFFF
+};
+
+//-----------------------------------------------------------------------------
+// Local testing functions
+
+static void clreol()
+{
+#ifdef PLATFORM_WINDOWS
+ CONSOLE_SCREEN_BUFFER_INFO ScreenInfo;
+ HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+ LPTSTR szConsoleLine;
+ int nConsoleChars;
+ int i = 0;
+
+ GetConsoleScreenBufferInfo(hConsole, &ScreenInfo);
+ nConsoleChars = (ScreenInfo.srWindow.Right - ScreenInfo.srWindow.Left);
+ if(nConsoleChars > 0)
+ {
+ szConsoleLine = new TCHAR[nConsoleChars + 3];
+ if(szConsoleLine != NULL)
+ {
+ szConsoleLine[i++] = '\r';
+ for(; i < nConsoleChars; i++)
+ szConsoleLine[i] = ' ';
+ szConsoleLine[i++] = '\r';
+ szConsoleLine[i] = 0;
+
+ _tprintf(szConsoleLine);
+ delete [] szConsoleLine;
+ }
+ }
+#endif // PLATFORM_WINDOWS
+}
+
+static void PrintfTA(const TCHAR * szFormat, const TCHAR * szStrT, const char * szStrA, int lcLocale = 0)
+{
+ TCHAR * szTemp;
+ TCHAR szBuffer[MAX_PATH];
+
+ // Convert ANSI string to TCHAR
+ for(szTemp = szBuffer; *szStrA != 0; szTemp++, szStrA++)
+ szTemp[0] = szStrA[0];
+ szTemp[0] = 0;
+
+ _tprintf(szFormat, szStrT, szBuffer, lcLocale);
+}
+
+static void MergeLocalPath(TCHAR * szBuffer, const TCHAR * szPart1, const char * szPart2)
+{
+ // Copy directory name
+ while(*szPart1 != 0)
+ *szBuffer++ = *szPart1++;
+
+ // Add separator
+ *szBuffer++ = _T('/');
+
+ // Copy file name
+ while(*szPart2 != 0)
+ *szBuffer++ = *szPart2++;
+
+ // Terminate the string
+ *szBuffer = 0;
+}
+
+int GetFirstDiffer(void * ptr1, void * ptr2, int nSize)
+{
+ char * buff1 = (char *)ptr1;
+ char * buff2 = (char *)ptr2;
+ int nDiffer;
+
+ for(nDiffer = 0; nDiffer < nSize; nDiffer++)
+ {
+ if(*buff1++ != *buff2++)
+ return nDiffer;
+ }
+ return -1;
+}
+
+static void WINAPI CompactCB(void * /* lpParam */, DWORD dwWork, ULONGLONG BytesDone, ULONGLONG TotalBytes)
+{
+ clreol();
+
+ _tprintf(_T("%u of %u "), (DWORD)BytesDone, (DWORD)TotalBytes);
+ switch(dwWork)
+ {
+ case CCB_CHECKING_FILES:
+ _tprintf(_T("Checking files in archive ...\r"));
+ break;
+
+ case CCB_CHECKING_HASH_TABLE:
+ _tprintf(_T("Checking hash table ...\r"));
+ break;
+
+ case CCB_COPYING_NON_MPQ_DATA:
+ _tprintf(_T("Copying non-MPQ data ...\r"));
+ break;
+
+ case CCB_COMPACTING_FILES:
+ _tprintf(_T("Compacting archive ...\r"));
+ break;
+
+ case CCB_CLOSING_ARCHIVE:
+ _tprintf(_T("Closing archive ...\r"));
+ break;
+ }
+}
+
+static void GenerateRandomDataBlock(LPBYTE pbBuffer, DWORD cbBuffer)
+{
+ LPBYTE pbBufferEnd = pbBuffer + cbBuffer;
+ LPBYTE pbPtr = pbBuffer;
+ DWORD cbBytesToPut = 0;
+ BYTE ByteToPut = 0;
+ bool bRandomData = false;
+
+ while(pbPtr < pbBufferEnd)
+ {
+ // If there are no bytes to put, we will generate new byte and length
+ if(cbBytesToPut == 0)
+ {
+ bRandomData = false;
+ switch(rand() % 10)
+ {
+ case 0: // A short sequence of zeros
+ cbBytesToPut = rand() % 0x08;
+ ByteToPut = 0;
+ break;
+
+ case 1: // A long sequence of zeros
+ cbBytesToPut = rand() % 0x80;
+ ByteToPut = 0;
+ break;
+
+ case 2: // A short sequence of non-zeros
+ cbBytesToPut = rand() % 0x08;
+ ByteToPut = (BYTE)(rand() % 0x100);
+ break;
+
+ case 3: // A long sequence of non-zeros
+ cbBytesToPut = rand() % 0x80;
+ ByteToPut = (BYTE)(rand() % 0x100);
+ break;
+
+ case 4: // A short random data
+ cbBytesToPut = rand() % 0x08;
+ bRandomData = true;
+ break;
+
+ case 5: // A long random data
+ cbBytesToPut = rand() % 0x80;
+ bRandomData = true;
+ break;
+
+ default: // A single random byte
+ cbBytesToPut = 1;
+ ByteToPut = (BYTE)(rand() % 0x100);
+ break;
+ }
+ }
+
+ // Generate random byte, if needed
+ if(bRandomData)
+ ByteToPut = (BYTE)(rand() % 0x100);
+
+ // Put next byte to the output buffer
+ *pbPtr++ = ByteToPut;
+ cbBytesToPut--;
+ }
+}
+
+static bool CompareArchivedFiles(const char * szFileName, HANDLE hFile1, HANDLE hFile2, DWORD dwBlockSize)
+{
+ LPBYTE pbBuffer1 = NULL;
+ LPBYTE pbBuffer2 = NULL;
+ DWORD dwRead1; // Number of bytes read (Storm.dll)
+ DWORD dwRead2; // Number of bytes read (StormLib)
+ bool bResult1 = false; // Result from Storm.dll
+ bool bResult2 = false; // Result from StormLib
+ bool bResult = true;
+ int nDiff;
+
+ szFileName = szFileName;
+
+ // Allocate buffers
+ pbBuffer1 = new BYTE[dwBlockSize];
+ pbBuffer2 = new BYTE[dwBlockSize];
+
+ for(;;)
+ {
+ // Read the file's content by both methods and compare the result
+ memset(pbBuffer1, 0, dwBlockSize);
+ memset(pbBuffer2, 0, dwBlockSize);
+ bResult1 = SFileReadFile(hFile1, pbBuffer1, dwBlockSize, &dwRead1, NULL);
+ bResult2 = SFileReadFile(hFile2, pbBuffer2, dwBlockSize, &dwRead2, NULL);
+ if(bResult1 != bResult2)
+ {
+ _tprintf(_T("Different results from SFileReadFile, Mpq1 %u, Mpq2 %u\n"), bResult1, bResult2);
+ bResult = false;
+ break;
+ }
+
+ // Test the number of bytes read
+ if(dwRead1 != dwRead2)
+ {
+ _tprintf(_T("Different bytes read from SFileReadFile, Mpq1 %u, Mpq2 %u\n"), dwRead1, dwRead2);
+ bResult = false;
+ break;
+ }
+
+ // No more bytes ==> OK
+ if(dwRead1 == 0)
+ break;
+
+ // Test the content
+ if((nDiff = GetFirstDiffer(pbBuffer1, pbBuffer2, dwRead1)) != -1)
+ {
+ bResult = false;
+ break;
+ }
+ }
+
+ delete [] pbBuffer2;
+ delete [] pbBuffer1;
+ return bResult;
+}
+
+// Random read version
+static bool CompareArchivedFilesRR(const char * /* szFileName */, HANDLE hFile1, HANDLE hFile2, DWORD dwBlockSize)
+{
+ const char * szPositions[3] = {"FILE_BEGIN ", "FILE_CURRENT", "FILE_END "};
+ LPBYTE pbBuffer1 = NULL;
+ LPBYTE pbBuffer2 = NULL;
+ DWORD dwFileSize1; // File size (Storm.dll)
+ DWORD dwFileSize2; // File size (StormLib)
+ DWORD dwRead1; // Number of bytes read (Storm.dll)
+ DWORD dwRead2; // Number of bytes read (StormLib)
+ bool bResult1 = false; // Result from Storm.dll
+ bool bResult2 = false; // Result from StormLib
+ int nError = ERROR_SUCCESS;
+
+ // Test the file size
+ dwFileSize1 = SFileGetFileSize(hFile1, NULL);
+ dwFileSize2 = SFileGetFileSize(hFile2, NULL);
+ if(dwFileSize1 != dwFileSize2)
+ {
+ _tprintf(_T("Different size from SFileGetFileSize (file1: %u, file2: %u)\n"), dwFileSize1, dwFileSize2);
+ return false;
+ }
+
+ if(dwFileSize1 != 0)
+ {
+ for(int i = 0; i < 10000; i++)
+ {
+ DWORD dwRandom = rand() * rand();
+ DWORD dwMoveMethod = dwRandom % 3;
+ DWORD dwPosition = dwRandom % dwFileSize1;
+ DWORD dwToRead = dwRandom % dwBlockSize;
+
+ // Also test negative seek
+ if(rand() & 1)
+ {
+ int nPosition = (int)dwPosition;
+ dwPosition = (DWORD)(-nPosition);
+ }
+
+ // Allocate buffers
+ pbBuffer1 = new BYTE[dwToRead];
+ pbBuffer2 = new BYTE[dwToRead];
+
+ // Set the file pointer
+ _tprintf(_T("RndRead (%u): pos %8i from %s, size %u ...\r"), i, dwPosition, szPositions[dwMoveMethod], dwToRead);
+ dwRead1 = SFileSetFilePointer(hFile1, dwPosition, NULL, dwMoveMethod);
+ dwRead2 = SFileSetFilePointer(hFile2, dwPosition, NULL, dwMoveMethod);
+ if(dwRead1 != dwRead2)
+ {
+ _tprintf(_T("Difference returned by SFileSetFilePointer (file1: %u, file2: %u)\n"), dwRead1, dwRead2);
+ nError = ERROR_CAN_NOT_COMPLETE;
+ break;
+ }
+
+ // Read the file's content by both methods and compare the result
+ bResult1 = SFileReadFile(hFile1, pbBuffer1, dwToRead, &dwRead1, NULL);
+ bResult2 = SFileReadFile(hFile2, pbBuffer2, dwToRead, &dwRead2, NULL);
+ if(bResult1 != bResult2)
+ {
+ _tprintf(_T("Different results from SFileReadFile (file1: %u, file2: %u)\n\n"), bResult1, bResult2);
+ nError = ERROR_CAN_NOT_COMPLETE;
+ break;
+ }
+
+ // Test the number of bytes read
+ if(dwRead1 != dwRead2)
+ {
+ _tprintf(_T("Different bytes read from SFileReadFile (file1: %u, file2: %u)\n\n"), dwRead1, dwRead2);
+ nError = ERROR_CAN_NOT_COMPLETE;
+ break;
+ }
+
+ // Test the content
+ if(dwRead1 != 0 && memcmp(pbBuffer1, pbBuffer2, dwRead1))
+ {
+ _tprintf(_T("Different data content from SFileReadFile\n"));
+ nError = ERROR_CAN_NOT_COMPLETE;
+ break;
+ }
+
+ delete [] pbBuffer2;
+ delete [] pbBuffer1;
+ }
+ }
+ clreol();
+ return (nError == ERROR_SUCCESS) ? true : false;
+}
+
+//-----------------------------------------------------------------------------
+// Opening local file
+
+static int TestOpenLocalFile(const char * szFileName)
+{
+ HANDLE hFile;
+ char szRetrievedName[MAX_PATH];
+
+ if(SFileOpenFileEx(NULL, szFileName, SFILE_OPEN_LOCAL_FILE, &hFile))
+ {
+ SFileGetFileName(hFile, szRetrievedName);
+ SFileCloseFile(hFile);
+ }
+
+ return ERROR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// Partial file reading
+
+static int TestPartFileRead(const TCHAR * szFileName)
+{
+ ULONGLONG ByteOffset;
+ ULONGLONG FileSize = 0;
+ TFileStream * pStream;
+ BYTE BigBuffer[0x7000];
+ BYTE Buffer[0x100];
+ int nError = ERROR_SUCCESS;
+
+ // Open the partial file
+ pStream = FileStream_OpenFile(szFileName, false);
+ if(pStream == NULL)
+ nError = GetLastError();
+
+ // Get the size of the stream
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!FileStream_GetSize(pStream, FileSize))
+ nError = GetLastError();
+ }
+
+ // Read the last 0x7000 bytes
+ if(nError == ERROR_SUCCESS)
+ {
+ ByteOffset = FileSize - sizeof(BigBuffer);
+ if(!FileStream_Read(pStream, &ByteOffset, BigBuffer, sizeof(BigBuffer)))
+ nError = GetLastError();
+ }
+
+ // Read the last 0x100 bytes
+ if(nError == ERROR_SUCCESS)
+ {
+ ByteOffset = FileSize - sizeof(Buffer);
+ if(!FileStream_Read(pStream, &ByteOffset, Buffer, sizeof(Buffer)))
+ nError = GetLastError();
+ }
+
+ // Read 0x100 bytes from position (FileSize - 0xFF)
+ if(nError == ERROR_SUCCESS)
+ {
+ ByteOffset = FileSize - sizeof(Buffer) + 1;
+ if(!FileStream_Read(pStream, &ByteOffset, Buffer, sizeof(Buffer)))
+ nError = GetLastError();
+ }
+
+ FileStream_Close(pStream);
+ return nError;
+}
+
+//-----------------------------------------------------------------------------
+// Compare PKLIB decompression
+
+BYTE pbCompressed1[] = {0x00, 0x04, 0x00, 0x00, 0x04, 0xF0, 0x1F, 0x7B, 0x01, 0xFF};
+BYTE pbCompressed2[] = {0x00, 0x04, 0x00, 0x00, 0x04, 0xF0, 0x1F, 0x00, 0x00, 0x04, 0xFC, 0x03};
+
+static int ComparePklibCompressions()
+{
+ char Decompressed[0x1000];
+ char Compressed[0x1000];
+ int cbDecompressed = 0x208;
+ int cbCompressed = sizeof(Compressed);
+
+ memset(Decompressed, 0, cbDecompressed);
+ SCompImplode(Compressed, &cbCompressed, Decompressed, cbDecompressed);
+
+ cbDecompressed = sizeof(Decompressed);
+ SCompExplode(Decompressed, &cbDecompressed, Compressed, cbCompressed);
+
+
+ return ERROR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// Compare LZMA decompression
+
+#ifdef PLATFORM_WINDOWS
+typedef void * (*ALLOC_MEMORY)(size_t);
+typedef void (*FREE_MEMORY)(void *);
+typedef int (GIVE_DATA)(void *);
+
+extern "C" int starcraft_decompress_lzma(char * pbInBuffer, int cbInBuffer, char * pbOutBuffer, int cbOutBuffer, int * pcbOutBuffer, ALLOC_MEMORY pfnAllocMemory, FREE_MEMORY pfnFreeMemory);
+extern "C" int starcraft_compress_lzma(char * pbInBuffer, int cbInBuffer, int dummy1, char * pbOutBuffer, int cbOutBuffer, int dummy2, int * pcbOutBuffer, ALLOC_MEMORY pfnAllocMemory, FREE_MEMORY pfnFreeMemory, GIVE_DATA pfnGiveData);
+void Compress_LZMA(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer, int *, int);
+int Decompress_LZMA(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer);
+
+extern "C" void * operator_new(size_t sz)
+{
+ return malloc(sz);
+}
+
+void * Memory_Allocate(size_t byte_size)
+{
+ return malloc(byte_size);
+}
+
+void Memory_Free(void * address)
+{
+ if(address != NULL)
+ free(address);
+}
+
+int GiveData(void *)
+{
+ return 0;
+}
+
+static int StarcraftCompress_LZMA(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer)
+{
+ return starcraft_compress_lzma(pbInBuffer,
+ cbInBuffer,
+ 0,
+ pbOutBuffer,
+ *pcbOutBuffer,
+ 0,
+ pcbOutBuffer,
+ Memory_Allocate,
+ Memory_Free,
+ GiveData);
+}
+
+static int StarcraftDecompress_LZMA(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer)
+{
+ return starcraft_decompress_lzma(pbInBuffer,
+ cbInBuffer,
+ pbOutBuffer,
+ *pcbOutBuffer,
+ pcbOutBuffer,
+ Memory_Allocate,
+ Memory_Free);
+}
+
+static int CompareLzmaCompressions(int nSectorSize)
+{
+ LPBYTE pbCompressed1 = NULL; // Compressed by our code
+ LPBYTE pbCompressed2 = NULL; // Compressed by Blizzard's code
+ LPBYTE pbDecompressed1 = NULL; // Decompressed by our code
+ LPBYTE pbDecompressed2 = NULL; // Decompressed by Blizzard's code
+ LPBYTE pbOriginalData = NULL;
+ int nError = ERROR_SUCCESS;
+
+ // Allocate buffers
+ // Must allocate twice blocks due to probable bug in Storm.dll.
+ // Storm.dll corrupts stack when uncompresses data with PKWARE DCL
+ // and no compression occurs.
+ pbDecompressed1 = new BYTE [nSectorSize];
+ pbDecompressed2 = new BYTE [nSectorSize];
+ pbCompressed1 = new BYTE [nSectorSize];
+ pbCompressed2 = new BYTE [nSectorSize];
+ pbOriginalData = new BYTE[nSectorSize];
+ if(!pbDecompressed1 || !pbDecompressed2 || !pbCompressed1 || !pbCompressed2 || !pbOriginalData)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+
+ if(nError == ERROR_SUCCESS)
+ {
+ for(int i = 0; i < 100000; i++)
+ {
+ int nDcmpLength1;
+ int nDcmpLength2;
+ int nCmpLength1;
+ int nCmpLength2;
+ int nDiff;
+
+ clreol();
+ _tprintf(_T("Testing compression of sector %u\r"), i + 1);
+
+ // Generate random data sector
+ GenerateRandomDataBlock(pbOriginalData, nSectorSize);
+
+ // Compress the sector by both methods
+ nCmpLength1 = nCmpLength2 = nSectorSize;
+// Compress_LZMA((char *)pbCompressed1, &nCmpLength1, (char *)pbOriginalData, nSectorSize, 0, 0);
+ StarcraftCompress_LZMA((char *)pbCompressed1, &nCmpLength2, (char *)pbOriginalData, nSectorSize);
+
+__TryToDecompress:
+
+ // Only test decompression when the compression actually succeeded
+ if(nCmpLength1 < nSectorSize)
+ {
+ // Decompress both data
+ nDcmpLength2 = nDcmpLength1 = nSectorSize;
+// Decompress_LZMA((char *)pbDecompressed1, &nDcmpLength1, (char *)pbCompressed1, nCmpLength1);
+ StarcraftDecompress_LZMA((char *)pbDecompressed2, &nDcmpLength2, (char *)pbCompressed1, nCmpLength1);
+
+ // Compare the length of the output data
+ if(nDcmpLength1 != nDcmpLength2)
+ {
+ _tprintf(_T("Difference in compressed blocks lengths (%u vs %u)\n"), nDcmpLength1, nDcmpLength2);
+ goto __TryToDecompress;
+ }
+
+ // Compare the output
+ if((nDiff = GetFirstDiffer(pbDecompressed1, pbDecompressed2, nDcmpLength1)) != -1)
+ {
+ _tprintf(_T("Difference in decompressed blocks (offset 0x%08X)\n"), nDiff);
+ goto __TryToDecompress;
+ }
+
+ // Check for data overflow
+ if(pbDecompressed1[nSectorSize] != 0xFD || pbDecompressed1[nSectorSize] != 0xFD)
+ {
+ _tprintf(_T("Damage after decompressed sector !!!\n"));
+ goto __TryToDecompress;
+ }
+
+ // Compare the decompressed data against original data
+ if((nDiff = GetFirstDiffer(pbDecompressed1, pbOriginalData, nDcmpLength1)) != -1)
+ {
+ _tprintf(_T("Difference between original data and decompressed data (offset 0x%08X)\n"), nDiff);
+ goto __TryToDecompress;
+ }
+ }
+ }
+ }
+
+ // Cleanup
+ if(pbOriginalData != NULL)
+ delete [] pbOriginalData;
+ if(pbCompressed2 != NULL)
+ delete [] pbCompressed2;
+ if(pbCompressed1 != NULL)
+ delete [] pbCompressed1;
+ if(pbDecompressed2 != NULL)
+ delete [] pbDecompressed2;
+ if(pbDecompressed1 != NULL)
+ delete [] pbDecompressed1;
+ clreol();
+ return nError;
+}
+#endif // PLATFORM_WINDOWS
+
+//-----------------------------------------------------------------------------
+// Compression method test
+
+static int TestSectorCompress(int nSectorSize)
+{
+ LPBYTE pbDecompressed = NULL;
+ LPBYTE pbCompressed = NULL;
+ LPBYTE pbOriginal = NULL;
+ int nError = ERROR_SUCCESS;
+
+ // Allocate buffers
+ pbDecompressed = new BYTE[nSectorSize];
+ pbCompressed = new BYTE[nSectorSize];
+ pbOriginal = new BYTE[nSectorSize];
+ if(!pbDecompressed || !pbCompressed || !pbOriginal)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+
+ if(nError == ERROR_SUCCESS)
+ {
+ for(int i = 0; i < 100000; i++)
+ {
+ int nOriginalLength = nSectorSize % (rand() + 1);
+ int nCompressedLength;
+ int nDecompressedLength;
+ int nCmp = MPQ_COMPRESSION_SPARSE | MPQ_COMPRESSION_ZLIB | MPQ_COMPRESSION_BZIP2 | MPQ_COMPRESSION_PKWARE;
+ int nDiff;
+
+ clreol();
+ _tprintf(_T("Testing compression of sector %u\r"), i + 1);
+
+ // Generate random data sector
+ GenerateRandomDataBlock(pbOriginal, nOriginalLength);
+ if(nOriginalLength == 0x123)
+ nOriginalLength = 0;
+
+__TryAgain:
+
+ // Compress the sector
+ nCompressedLength = nOriginalLength;
+ SCompCompress((char *)pbCompressed, &nCompressedLength, (char *)pbOriginal, nOriginalLength, nCmp, 0, -1);
+// SCompImplode((char *)pbCompressed, &nCompressedLength, (char *)pbOriginal, nOriginalLength);
+
+ // When the method was unable to compress data,
+ // the compressed data must be identical to original data
+ if(nCompressedLength == nOriginalLength)
+ {
+ if((nDiff = GetFirstDiffer(pbCompressed, pbOriginal, nOriginalLength)) != -1)
+ {
+ _tprintf(_T("Compression error: Fail when unable to compress the data (Offset 0x%08X).\n"), nDiff);
+ goto __TryAgain;
+ }
+ }
+
+ // Uncompress the sector
+ nDecompressedLength = nOriginalLength;
+ SCompDecompress((char *)pbDecompressed, &nDecompressedLength, (char *)pbCompressed, nCompressedLength);
+// SCompExplode((char *)pbDecompressed, &nDecompressedLength, (char *)pbCompressed, nCompressedLength);
+
+ // Check the decompressed length against original length
+ if(nDecompressedLength != nOriginalLength)
+ {
+ _tprintf(_T("Length of uncompressed data does not agree with original data length !!!\n"));
+ goto __TryAgain;
+ }
+
+ // Check decompressed block against original block
+ if((nDiff = GetFirstDiffer(pbDecompressed, pbOriginal, nOriginalLength)) != -1)
+ {
+ _tprintf(_T("Decompressed sector does not agree with the original data !!! (Offset 0x%08X)\n"), nDiff);
+ goto __TryAgain;
+ }
+ }
+ }
+
+ // Cleanup
+ delete [] pbOriginal;
+ delete [] pbCompressed;
+ delete [] pbDecompressed;
+ clreol();
+ return nError;
+}
+
+static int TestArchiveOpenAndClose(const TCHAR * szMpqName)
+{
+ const char * szFileName1 = "DBFilesClient\\Item.dbc";
+// const char * szFileName2 = "items\\map\\mapz_deleted.cel";
+ TMPQArchive * ha = NULL;
+ HANDLE hFile1 = NULL;
+// HANDLE hFile2 = NULL;
+ HANDLE hMpq = NULL;
+ int nError = ERROR_SUCCESS;
+
+ if(nError == ERROR_SUCCESS)
+ {
+ _tprintf(_T("Opening archive %s ...\n"), szMpqName);
+ if(!SFileOpenArchive(szMpqName, 0, STREAM_PROVIDER_ENCRYPTED | BASE_PROVIDER_FILE, &hMpq))
+ nError = GetLastError();
+ ha = (TMPQArchive *)hMpq;
+ }
+/*
+ // Test for TBitArray
+ if(nError == ERROR_SUCCESS && ha->pHetTable != NULL)
+ {
+ TBitArray * pBitArray = ha->pHetTable->pBetIndexes;
+
+ for(ULONG i = 0; i < 0x10000; i++)
+ {
+ BYTE LoadedBits[0x20];
+ BYTE SaveBits[0x40];
+ unsigned int nBitPosition = (i >> 0x08);
+ unsigned int nBitCount = (i & 0xFF);
+
+ memset(LoadedBits, 0, sizeof(LoadedBits));
+ memcpy(SaveBits, pBitArray->Elements, sizeof(SaveBits));
+
+ // Load the index to the BET table
+ pBitArray->GetBits(nBitPosition, nBitCount, LoadedBits, sizeof(LoadedBits));
+
+ // Load the index to the BET table
+ pBitArray->SetBits(nBitPosition, nBitCount, LoadedBits, sizeof(LoadedBits));
+
+ // Verify the bits
+ if(memcmp(SaveBits, pBitArray->Elements, sizeof(SaveBits)))
+ assert(false);
+ }
+ }
+*/
+ // Verify the raw data in the archive
+ if(nError == ERROR_SUCCESS)
+ {
+ // Verify the archive
+ SFileVerifyRawData(hMpq, SFILE_VERIFY_FILE, szFileName1);
+
+ // Try to open a file
+ if(!SFileOpenFileEx(hMpq, szFileName1, SFILE_OPEN_FROM_MPQ, &hFile1))
+ {
+ nError = GetLastError();
+ printf("%s - file not found in the MPQ\n", szFileName1);
+ }
+ }
+
+ // Dummy read from the file
+ if(nError == ERROR_SUCCESS)
+ {
+ DWORD dwBytesRead = 0;
+ BYTE Buffer[0x1000];
+
+ SFileSetFileLocale(hFile1, 0x405);
+ SFileReadFile(hFile1, Buffer, sizeof(Buffer), &dwBytesRead);
+ }
+/*
+ // Verify the MPQ listfile
+ if(nError == ERROR_SUCCESS)
+ {
+ SFileVerifyFile(hMpq, szFileName1, 0xFFFFFFFF);
+ if(!CompareArchivedFilesRR(szFileName1, hFile1, hFile2, 0x100000))
+ nError = ERROR_CAN_NOT_COMPLETE;
+ }
+*/
+ if(hFile1 != NULL)
+ SFileCloseFile(hFile1);
+ if(hMpq != NULL)
+ SFileCloseArchive(hMpq);
+ return nError;
+}
+
+static int TestFindFiles(const TCHAR * szMpqName)
+{
+ TMPQFile * hf;
+ HANDLE hFile;
+ HANDLE hMpq = NULL;
+ BYTE Buffer[100];
+ int nError = ERROR_SUCCESS;
+ int nFiles = 0;
+ int nFound = 0;
+
+ // Open the archive
+ if(nError == ERROR_SUCCESS)
+ {
+ _tprintf(_T("Opening \"%s\" for finding files ...\n"), szMpqName);
+ if(!SFileOpenArchive(szMpqName, 0, 0, &hMpq))
+ nError = GetLastError();
+ }
+
+ // Compact the archive
+ if(nError == ERROR_SUCCESS)
+ {
+ SFILE_FIND_DATA sf;
+ HANDLE hFind;
+ DWORD dwExtraDataSize;
+ bool bFound = true;
+
+ hFind = SFileFindFirstFile(hMpq, "*", &sf, "c:\\Tools32\\ListFiles\\ListFile.txt");
+ while(hFind != NULL && bFound != false)
+ {
+ if(SFileOpenFileEx(hMpq, sf.cFileName, 0, &hFile))
+ {
+ hf = (TMPQFile *)hFile;
+ SFileReadFile(hFile, Buffer, sizeof(Buffer));
+ nFiles++;
+
+ if(sf.dwFileFlags & MPQ_FILE_SECTOR_CRC)
+ {
+ dwExtraDataSize = hf->SectorOffsets[hf->dwSectorCount + 1] - hf->SectorOffsets[hf->dwSectorCount];
+ if(dwExtraDataSize != 0)
+ nFound++;
+ }
+
+ SFileCloseFile(hFile);
+ }
+
+ bFound = SFileFindNextFile(hFind, &sf);
+ }
+ }
+
+ if(hMpq != NULL)
+ SFileCloseArchive(hMpq);
+ if(nError == ERROR_SUCCESS)
+ _tprintf(_T("Search complete\n"));
+ return nError;
+}
+
+static int TestMpqCompacting(const TCHAR * szMpqName)
+{
+ HANDLE hMpq = NULL;
+ int nError = ERROR_SUCCESS;
+
+ // Open the archive
+ if(nError == ERROR_SUCCESS)
+ {
+ _tprintf(_T("Opening \"%s\" for compacting ...\n"), szMpqName);
+ if(!SFileOpenArchive(szMpqName, 0, 0, &hMpq))
+ nError = GetLastError();
+ }
+
+ if(nError == ERROR_SUCCESS)
+ {
+ const char * szFileName = "Shaders\\Effects\\shadowmap.wfx";
+
+ printf("Deleting file %s ...\r", szFileName);
+ if(!SFileRemoveFile(hMpq, szFileName))
+ nError = GetLastError();
+ }
+/*
+ // Compact the archive
+ if(nError == ERROR_SUCCESS)
+ {
+ _tprintf(_T("Compacting archive ...\r"));
+ SFileSetCompactCallback(hMpq, CompactCB, NULL);
+ if(!SFileCompactArchive(hMpq, "c:\\Tools32\\ListFiles\\ListFile.txt"))
+ nError = GetLastError();
+ }
+*/
+ if(hMpq != NULL)
+ SFileCloseArchive(hMpq);
+ if(nError == ERROR_SUCCESS)
+ _tprintf(_T("Compacting complete (No errors)\n"));
+ return nError;
+}
+
+static int TestCreateArchive(const TCHAR * szMpqName)
+{
+ TFileStream * pStream;
+ const TCHAR * szFileName1 = MAKE_PATH("FileTest.exe");
+ const TCHAR * szFileName2 = MAKE_PATH("ZeroSize.txt");
+ HANDLE hMpq = NULL; // Handle of created archive
+ DWORD dwVerifyResult;
+ DWORD dwFileCount = 0;
+ LCID LocaleIDs[] = {0x000, 0x405, 0x406, 0x407, 0xFFFF};
+ char szMpqFileName[MAX_PATH];
+ int nError = ERROR_SUCCESS;
+ int i;
+
+ // Create the new file
+ _tprintf(_T("Creating %s ...\n"), szMpqName);
+ pStream = FileStream_CreateFile(szMpqName, STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE);
+ if(pStream == NULL)
+ nError = GetLastError();
+
+ // Write some data
+ if(nError == ERROR_SUCCESS)
+ {
+ ULONGLONG FileSize = 0x100000;
+
+ FileStream_SetSize(pStream, FileSize);
+ FileStream_Close(pStream);
+ }
+
+ // Well, now create the MPQ archive
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!SFileCreateArchive(szMpqName,
+ MPQ_CREATE_ARCHIVE_V4 | MPQ_CREATE_ATTRIBUTES,
+ 17,
+ &hMpq))
+ {
+ nError = GetLastError();
+ }
+ }
+
+ // Add the same file multiple times
+ if(nError == ERROR_SUCCESS)
+ {
+ // Add FileTest.exe
+ for(i = 0; AddFlags[i] != 0xFFFFFFFF; i++)
+ {
+ sprintf(szMpqFileName, "FileTest_%02u.exe", i);
+ PrintfTA(_T("Adding %s as %s ...\n"), szFileName1, szMpqFileName);
+ if(SFileAddFileEx(hMpq, szFileName1, szMpqFileName, AddFlags[i], MPQ_COMPRESSION_ZLIB))
+ {
+ dwVerifyResult = SFileVerifyFile(hMpq, szMpqFileName, MPQ_ATTRIBUTE_CRC32 | MPQ_ATTRIBUTE_MD5);
+ if(dwVerifyResult & (VERIFY_OPEN_ERROR | VERIFY_READ_ERROR | VERIFY_FILE_SECTOR_CRC_ERROR | VERIFY_FILE_CHECKSUM_ERROR | VERIFY_FILE_MD5_ERROR))
+ printf("CRC error on \"%s\"\n", szMpqFileName);
+ dwFileCount++;
+ }
+ else
+ {
+ printf("Failed to add the file \"%s\".\n", szMpqFileName);
+ }
+ }
+
+
+ // Delete a file in the middle of the file table
+ SFileRemoveFile(hMpq, "FileTest_10.exe");
+ SFileAddFileEx(hMpq, szFileName1, "FileTest_xx.exe", MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED, MPQ_COMPRESSION_ZLIB);
+
+ // Try to decrement max file count
+ dwFileCount = SFileGetMaxFileCount(hMpq);
+ SFileSetMaxFileCount(hMpq, dwFileCount - 1);
+
+ // Add ZeroSize.txt (1)
+ sprintf(szMpqFileName, "ZeroSize_1.txt");
+ for(i = 0; LocaleIDs[i] != 0xFFFF; i++)
+ {
+ PrintfTA(_T("Adding %s as %s (locale %04x) ...\n"), szFileName2, szMpqFileName, LocaleIDs[i]);
+ SFileSetLocale(LocaleIDs[i]);
+ if(!SFileAddFileEx(hMpq, szFileName2, szMpqFileName, MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED, MPQ_COMPRESSION_ZLIB))
+ printf("Cannot add the file\n");
+ }
+
+ // Add ZeroSize.txt (1)
+ sprintf(szMpqFileName, "ZeroSize_2.txt");
+ for(int i = 0; LocaleIDs[i] != 0xFFFF; i++)
+ {
+ PrintfTA(_T("Adding %s as %s (locale %04x) ...\n"), szFileName2, szMpqFileName, LocaleIDs[i]);
+ SFileSetLocale(LocaleIDs[i]);
+ if(!SFileAddFileEx(hMpq, szFileName2, szMpqFileName, MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED, MPQ_COMPRESSION_ZLIB))
+ printf("Cannot add the file\n");
+ }
+ }
+
+ // Test rename function
+ if(nError == ERROR_SUCCESS)
+ {
+ _tprintf(_T("Testing rename files ...\n"));
+ SFileSetLocale(LANG_NEUTRAL);
+ if(!SFileRenameFile(hMpq, "FileTest_08.exe", "FileTest_08a.exe"))
+ {
+ nError = GetLastError();
+ _tprintf(_T("Failed to rename the file\n"));
+ }
+
+ if(!SFileRenameFile(hMpq, "FileTest_08a.exe", "FileTest_08.exe"))
+ {
+ nError = GetLastError();
+ _tprintf(_T("Failed to rename the file\n"));
+ }
+
+ if(!SFileRenameFile(hMpq, "FileTest_10.exe", "FileTest_10a.exe"))
+ {
+ nError = GetLastError();
+ _tprintf(_T("Failed to rename the file\n"));
+ }
+
+ if(!SFileRenameFile(hMpq, "FileTest_10a.exe", "FileTest_10.exe"))
+ {
+ nError = GetLastError();
+ _tprintf(_T("Failed to rename the file\n"));
+ }
+
+ if(nError == ERROR_SUCCESS)
+ _tprintf(_T("Rename test succeeded.\n\n"));
+ else
+ _tprintf(_T("Rename test failed.\n\n"));
+ }
+
+ // Compact the archive
+// if(nError == ERROR_SUCCESS)
+// SFileCompactArchive(hMpq);
+
+ // Test changing hash table size
+ if(nError == ERROR_SUCCESS)
+ SFileSetMaxFileCount(hMpq, 0x95);
+
+ if(hMpq != NULL)
+ SFileCloseArchive(hMpq);
+
+ // Try to reopen the archive
+ if(SFileOpenArchive(szMpqName, 0, 0, &hMpq))
+ SFileCloseArchive(hMpq);
+
+ _tprintf(_T("\n"));
+ return nError;
+}
+
+static int TestCreateArchive_PaliRoharBug(const TCHAR * szMpqName)
+{
+ const TCHAR * szFileName = MAKE_PATH("FileTest.exe");
+ HANDLE hMpq = NULL; // Handle of created archive
+ DWORD dwMaxFileCount = 0;
+ DWORD dwMpqFlags = MPQ_FILE_ENCRYPTED | MPQ_FILE_COMPRESS;
+ char szMpqFileName[MAX_PATH];
+ int nError = ERROR_SUCCESS;
+ int i;
+
+ _tremove(szMpqName);
+ if(SFileCreateArchive(szMpqName,
+ MPQ_CREATE_ARCHIVE_V4 | MPQ_CREATE_ATTRIBUTES,
+ 1,
+ &hMpq))
+ {
+ // Add the file there
+ SFileAddFileEx(hMpq, szFileName, "FileTest_base.exe", dwMpqFlags, MPQ_COMPRESSION_ZLIB);
+ SFileFlushArchive(hMpq);
+ SFileCloseArchive(hMpq);
+
+ // Add the same file 10 times
+ for(i = 0; i < 10; i++)
+ {
+ if(SFileOpenArchive(szMpqName, 0, 0, &hMpq))
+ {
+ dwMaxFileCount = SFileGetMaxFileCount(hMpq) + 1;
+ _tprintf(_T("Increasing max file count to %u ...\n"), dwMaxFileCount);
+ SFileSetMaxFileCount(hMpq, dwMaxFileCount);
+
+ sprintf(szMpqFileName, "FileTest_%02u.exe", dwMaxFileCount);
+ PrintfTA(_T("Adding %s as %s\n"), szFileName, szMpqFileName);
+ if(!SFileAddFileEx(hMpq, szFileName, szMpqFileName, dwMpqFlags, MPQ_COMPRESSION_ZLIB))
+ {
+ printf("Failed to add the file \"%s\".\n", szMpqFileName);
+ break;
+ }
+
+ SFileFlushArchive(hMpq);
+ SFileCompactArchive(hMpq);
+ SFileCloseArchive(hMpq);
+ }
+ }
+ }
+
+ _tprintf(_T("\n"));
+ return nError;
+}
+
+
+static int TestAddFilesToMpq(
+ const TCHAR * szMpqName,
+ ...
+ )
+{
+ const TCHAR * szFileName;
+ const TCHAR * szSrc;
+ char * szTrg;
+ HANDLE hMpq;
+ va_list argList;
+ char szMpqFileName[MAX_PATH];
+ int nError = ERROR_SUCCESS;
+
+ if(!SFileOpenArchive(szMpqName, 0, 0, &hMpq))
+ return GetLastError();
+
+ va_start(argList, szMpqName);
+ while((szFileName = va_arg(argList, const TCHAR *)) != NULL)
+ {
+ // Convert the plain name to ANSI
+ szSrc = GetPlainFileNameT(szFileName);
+ szTrg = szMpqFileName;
+ while(*szSrc != 0)
+ *szTrg++ = (char)*szSrc++;
+ *szTrg = 0;
+
+ // Add the file to MPQ
+ if(!SFileAddFileEx(hMpq, szFileName,
+ szMpqFileName,
+ MPQ_FILE_COMPRESS,
+ MPQ_COMPRESSION_ZLIB))
+ {
+ nError = GetLastError();
+ printf("Failed to add the file \"%s\"\n", szFileName);
+ }
+ }
+
+ SFileCloseArchive(hMpq);
+ return nError;
+}
+
+static int TestCreateArchiveFromMemory(const TCHAR * szMpqName)
+{
+#define FILE_SIZE 65535
+
+ HANDLE hFile;
+ HANDLE hMPQ;
+ char* data = new char [FILE_SIZE]; // random memory data
+ char szFileName[100];
+ int i;
+
+ // Create an mpq file for testing
+ if(SFileCreateArchive(szMpqName, MPQ_CREATE_ARCHIVE_V2|MPQ_CREATE_ATTRIBUTES, 0x100000, &hMPQ))
+ {
+ for(i = 0; i < 1000; i++)
+ {
+ sprintf(szFileName, "File%03u.bin", i);
+ printf("Adding file %s\r", szFileName);
+
+ if(SFileCreateFile(hMPQ, szFileName, 0, FILE_SIZE, 0, MPQ_FILE_COMPRESS, &hFile))
+ {
+ SFileWriteFile(hFile, data, FILE_SIZE, MPQ_COMPRESSION_ZLIB);
+ SFileFinishFile(hFile);
+ }
+ }
+ }
+ SFileCloseArchive(hMPQ);
+ delete [] data;
+ return ERROR_SUCCESS;
+}
+
+static int TestFileReadAndWrite(
+ const TCHAR * szMpqName,
+ const char * szFileName)
+{
+ LPBYTE pvFile = NULL;
+ HANDLE hFile = NULL;
+ HANDLE hMpq = NULL;
+ DWORD dwBytesRead;
+ DWORD dwFileSize = 0;
+ int nError = ERROR_SUCCESS;
+
+ if(!SFileOpenArchive(szMpqName, 0, 0, &hMpq))
+ {
+ nError = GetLastError();
+ _tprintf(_T("Failed to open the archive %s (%u).\n"), szMpqName, nError);
+ }
+
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!SFileOpenFileEx(hMpq, szFileName, 0, &hFile))
+ {
+ nError = GetLastError();
+ printf("Failed to open the file %s (%u).\n", szFileName, nError);
+ }
+ }
+
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!SFileGetFileInfo(hFile, SFILE_INFO_FILE_SIZE, &dwFileSize, sizeof(DWORD)))
+ {
+ nError = GetLastError();
+ _tprintf(_T("Failed to get the file size (%u).\n"), nError);
+ }
+ }
+
+ if(nError == ERROR_SUCCESS)
+ {
+ pvFile = new BYTE[dwFileSize];
+ if(pvFile == NULL)
+ {
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ printf("Failed to allocate buffer for the file (%u).\n", nError);
+ }
+ }
+
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!SFileReadFile(hFile, pvFile, dwFileSize, &dwBytesRead))
+ {
+ nError = GetLastError();
+ printf("Failed to read file (%u).\n", nError);
+ }
+ }
+
+ if(hFile != NULL)
+ {
+ SFileCloseFile(hFile);
+ hFile = NULL;
+ }
+
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!SFileCreateFile(hMpq, szFileName, 0, dwFileSize, 0, MPQ_FILE_REPLACEEXISTING, &hFile))
+ {
+ nError = GetLastError();
+ printf("Failed to create %s in the archive (%u).\n", szFileName, nError);
+ }
+ }
+
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!SFileWriteFile(hFile, pvFile, dwFileSize, 0))
+ {
+ nError = GetLastError();
+ printf("Failed to write the data to the MPQ (%u).\n", nError);
+ }
+ }
+
+ if(hFile != NULL)
+ {
+ if(!SFileFinishFile(hFile))
+ {
+ nError = GetLastError();
+ printf("Failed to finalize file creation (%u).\n", nError);
+ }
+ }
+
+ if(pvFile != NULL)
+ delete [] pvFile;
+ if(hMpq != NULL)
+ SFileCloseArchive(hMpq);
+ return nError;
+}
+
+static int TestSignatureVerify(const TCHAR * szMpqName)
+{
+ HANDLE hMpq;
+
+ if(SFileOpenArchive(szMpqName, 0, 0, &hMpq))
+ {
+ _tprintf(_T("Verifying digital signature in %s:\n"), szMpqName);
+ switch(SFileVerifyArchive(hMpq))
+ {
+ case ERROR_NO_SIGNATURE:
+ _tprintf(_T("No digital signature present.\n"));
+ break;
+
+ case ERROR_VERIFY_FAILED:
+ _tprintf(_T("Failed to verify signature.\n"));
+ break;
+
+ case ERROR_WEAK_SIGNATURE_OK:
+ _tprintf(_T("Weak signature is OK.\n"));
+ break;
+
+ case ERROR_WEAK_SIGNATURE_ERROR:
+ _tprintf(_T("Weak signature mismatch.\n"));
+ break;
+
+ case ERROR_STRONG_SIGNATURE_OK:
+ _tprintf(_T("Strong signature is OK.\n"));
+ break;
+
+ case ERROR_STRONG_SIGNATURE_ERROR:
+ _tprintf(_T("Strong signature mismatch.\n"));
+ break;
+ }
+
+ SFileCloseArchive(hMpq);
+ _tprintf(_T("\n"));
+ }
+
+ return 0;
+}
+
+
+static int TestCreateArchiveCopy(const TCHAR * szMpqName, const TCHAR * szMpqCopyName, const char * szListFile)
+{
+ TFileStream * pStream;
+ TCHAR szLocalFile[MAX_PATH];
+ HANDLE hMpq1 = NULL; // Handle of existing archive
+ HANDLE hMpq2 = NULL; // Handle of created archive
+ DWORD dwHashTableSize = 0;
+ int nError = ERROR_SUCCESS;
+
+ // If no listfile or an empty one, use NULL
+ if(szListFile == NULL || *szListFile == 0)
+ szListFile = NULL;
+
+ // Create the new file
+ pStream = FileStream_CreateFile(szMpqCopyName, STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE);
+ if(pStream == NULL)
+ nError = GetLastError();
+
+ // Write some data
+ if(nError == ERROR_SUCCESS)
+ {
+ ULONGLONG FileSize = 0x100000;
+
+ FileStream_SetSize(pStream, FileSize);
+ FileStream_Close(pStream);
+ }
+
+ // Open the existing MPQ archive
+ if(nError == ERROR_SUCCESS)
+ {
+ _tprintf(_T("Opening %s ...\n"), szMpqName);
+ if(!SFileOpenArchive(szMpqName, 0, 0, &hMpq1))
+ nError = GetLastError();
+ }
+
+ // Well, now create the MPQ archive
+ if(nError == ERROR_SUCCESS)
+ {
+ _tprintf(_T("Creating %s ...\n"), szMpqCopyName);
+ SFileGetFileInfo(hMpq1, SFILE_INFO_HASH_TABLE_SIZE, &dwHashTableSize, 4);
+ if(!SFileCreateArchive(szMpqCopyName, 0, dwHashTableSize, &hMpq2))
+ nError = GetLastError();
+ }
+
+ // Copy all files from one archive to another
+ if(nError == ERROR_SUCCESS)
+ {
+ SFILE_FIND_DATA sf;
+ HANDLE hFind = SFileFindFirstFile(hMpq1, "*", &sf, szListFile);
+ bool bResult = true;
+
+ _tprintf(_T("Copying files ...\n"));
+
+ if(hFind != NULL)
+ {
+ while(bResult)
+ {
+ if(strcmp(sf.cFileName, LISTFILE_NAME) && strcmp(sf.cFileName, ATTRIBUTES_NAME))
+ {
+ SFileSetLocale(sf.lcLocale);
+
+ // Create the local file name
+ MergeLocalPath(szLocalFile, szWorkDir, sf.szPlainName);
+ if(SFileExtractFile(hMpq1, sf.cFileName, szLocalFile))
+ {
+ printf("Extracting %s ... OK\n", sf.cFileName);
+ if(!SFileAddFile(hMpq2, szLocalFile, sf.cFileName, sf.dwFileFlags))
+ {
+ nError = GetLastError();
+ printf("Adding %s ... Failed\n\n", sf.cFileName);
+ _tremove(szLocalFile);
+ break;
+ }
+ else
+ {
+ printf("Adding %s ... OK\n", sf.cFileName);
+ }
+ }
+ else
+ {
+ printf("Extracting %s ... Failed\n", sf.cFileName);
+ }
+
+ // Delete the added file
+ _tremove(szLocalFile);
+ }
+
+ // Find the next file
+ bResult = SFileFindNextFile(hFind, &sf);
+ }
+
+ // Close the search handle
+ SFileFindClose(hFind);
+ printf("\n");
+ }
+ }
+
+ // Close both archives
+ if(hMpq2 != NULL)
+ SFileCloseArchive(hMpq2);
+ if(hMpq1 != NULL)
+ SFileCloseArchive(hMpq1);
+ return nError;
+}
+
+static int TestOpenPatchedArchive(const TCHAR * szMpqName, ...)
+{
+ TFileStream * pStream;
+ HANDLE hFile = NULL;
+ HANDLE hMpq = NULL;
+ va_list argList;
+ const char * szFileName = "World\\Minimaps\\Azeroth\\noLiquid_map20_44.blp";
+ TCHAR szLocFileName[MAX_PATH];
+ LPBYTE pbFullFile = NULL;
+ DWORD dwFileSize;
+ int nError = ERROR_SUCCESS;
+
+ // Open the primary MPQ
+ _tprintf(_T("Opening %s ...\n"), szMpqName);
+ if(!SFileOpenArchive(szMpqName, 0, MPQ_OPEN_READ_ONLY, &hMpq))
+ {
+ nError = GetLastError();
+ _tprintf(_T("Failed to open the archive %s ...\n"), szMpqName);
+ }
+
+ // Add all patches
+ if(nError == ERROR_SUCCESS)
+ {
+ va_start(argList, szMpqName);
+ while((szMpqName = va_arg(argList, const TCHAR *)) != NULL)
+ {
+ _tprintf(_T("Adding patch %s ...\n"), szMpqName);
+ if(!SFileOpenPatchArchive(hMpq, szMpqName, NULL, 0))
+ {
+ nError = GetLastError();
+ printf("Failed to add patch %s ...\n", szMpqName);
+ }
+ }
+ va_end(argList);
+ }
+
+ // Now search all files
+ if(nError == ERROR_SUCCESS)
+ {
+ SFILE_FIND_DATA sf;
+ HANDLE hFind;
+ bool bResult = true;
+
+ hFind = SFileFindFirstFile(hMpq, "World\\Minimaps\\Azeroth\\noLiquid_map20_44.*", &sf, NULL);
+ while(hFind && bResult)
+ {
+ printf("%s\n", sf.cFileName);
+ bResult = SFileFindNextFile(hFind, &sf);
+ }
+ }
+
+ // Now try to open patched version of a file
+ if(nError == ERROR_SUCCESS)
+ {
+ SFileExtractFile(hMpq, szFileName, _T("E:\\noLiquid_map20_44.blp"));
+ }
+
+ // Now try to open patched version of "Achievement.dbc"
+ if(nError == ERROR_SUCCESS)
+ {
+ printf("Opening patched file \"%s\" ...\n", szFileName);
+ SFileVerifyFile(hMpq, szFileName, SFILE_VERIFY_RAW_MD5);
+ if(!SFileOpenFileEx(hMpq, szFileName, SFILE_OPEN_PATCHED_FILE, &hFile))
+ {
+ nError = GetLastError();
+ printf("Failed to open patched file \"%s\"\n", szFileName);
+ }
+ }
+
+ // Verify of the patched version is correct
+ if(nError == ERROR_SUCCESS)
+ {
+ TCHAR * szPatchChain = NULL;
+ DWORD cbPatchChain = 0;
+
+ // Get the patch chain
+ SFileGetFileInfo(hFile, SFILE_INFO_PATCH_CHAIN, szPatchChain, cbPatchChain, &cbPatchChain);
+ szPatchChain = (TCHAR *)(new BYTE[cbPatchChain]);
+ SFileGetFileInfo(hFile, SFILE_INFO_PATCH_CHAIN, szPatchChain, cbPatchChain, &cbPatchChain);
+ delete [] szPatchChain;
+
+ // Get the size of the full patched file
+ dwFileSize = SFileGetFileSize(hFile, NULL);
+ if(dwFileSize != 0)
+ {
+ DWORD dwBytesRead = 0;
+ BYTE TempData[0x100];
+
+ SFileReadFile(hFile, TempData, sizeof(TempData), &dwBytesRead);
+ SFileSetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+
+ // Allocate space for the full file
+ pbFullFile = new BYTE[dwFileSize];
+ if(pbFullFile != NULL)
+ {
+ if(!SFileReadFile(hFile, pbFullFile, dwFileSize))
+ {
+ nError = GetLastError();
+ printf("Failed to read full patched file data \"%s\"\n", szFileName);
+ }
+
+ if(nError == ERROR_SUCCESS)
+ {
+ MergeLocalPath(szLocFileName, MAKE_PATH("Work//"), GetPlainFileNameA(szFileName));
+ pStream = FileStream_CreateFile(szLocFileName, STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE);
+ if(pStream != NULL)
+ {
+ FileStream_Write(pStream, NULL, pbFullFile, dwFileSize);
+ FileStream_Close(pStream);
+ }
+ }
+
+ delete [] pbFullFile;
+ }
+ }
+ }
+
+ // Close handles
+ if(hFile != NULL)
+ SFileCloseFile(hFile);
+ if(hMpq != NULL)
+ SFileCloseArchive(hMpq);
+ return nError;
+}
+
+static int TestCompareTwoArchives(
+ const TCHAR * szMpqName1,
+ const TCHAR * szMpqName2,
+ const char * szListFile,
+ DWORD dwBlockSize)
+{
+ TMPQArchive * ha1 = NULL;
+ TMPQArchive * ha2 = NULL;
+ HANDLE hMpq1 = NULL; // Handle of the first archive
+ HANDLE hMpq2 = NULL; // Handle of the second archive
+ HANDLE hFile1 = NULL;
+ HANDLE hFile2 = NULL;
+ int nError = ERROR_SUCCESS;
+
+ // If no listfile or an empty one, use NULL
+ if(szListFile == NULL || *szListFile == 0)
+ szListFile = NULL;
+
+ _tprintf(_T("=============== Comparing MPQ archives ===============\n"));
+
+ // Open the first MPQ archive
+ if(nError == ERROR_SUCCESS && szMpqName1 != NULL)
+ {
+ _tprintf(_T("Opening %s ...\n"), szMpqName1);
+ if(!SFileOpenArchive(szMpqName1, 0, 0, &hMpq1))
+ nError = GetLastError();
+ ha1 = (TMPQArchive *)hMpq1;
+ }
+
+ // Open the second MPQ archive
+ if(nError == ERROR_SUCCESS && szMpqName2 != NULL)
+ {
+ _tprintf(_T("Opening %s ...\n"), szMpqName2);
+ if(!SFileOpenArchive(szMpqName2, 0, 0, &hMpq2))
+ nError = GetLastError();
+ ha2 = (TMPQArchive *)hMpq2;
+ }
+
+ // Compare the header
+ if(nError == ERROR_SUCCESS && (ha1 != NULL && ha2 != NULL))
+ {
+ if(ha1->pHeader->dwHeaderSize != ha2->pHeader->dwHeaderSize)
+ printf(" - Header size is different\n");
+ if(ha1->pHeader->wFormatVersion != ha2->pHeader->wFormatVersion)
+ printf(" - Format version is different\n");
+ if(ha1->pHeader->wSectorSize != ha2->pHeader->wSectorSize)
+ printf(" - Sector size is different\n");
+ if(ha1->pHeader->HetTableSize64 != ha2->pHeader->HetTableSize64)
+ printf(" - HET table size is different\n");
+ if(ha1->pHeader->BetTableSize64 != ha2->pHeader->BetTableSize64)
+ printf(" - BET table size is different\n");
+ if(ha1->pHeader->dwHashTableSize != ha2->pHeader->dwHashTableSize)
+ printf(" - Hash table size is different\n");
+ if(ha1->pHeader->dwBlockTableSize != ha2->pHeader->dwBlockTableSize)
+ printf(" - Block table size is different\n");
+ }
+
+ // Find all files in the first archive and compare them
+ if(nError == ERROR_SUCCESS)
+ {
+ SFILE_FIND_DATA sf;
+ TMPQFile * hf1;
+ TMPQFile * hf2;
+ HANDLE hFind = SFileFindFirstFile(hMpq1, "*", &sf, szListFile);
+ bool bResult = true;
+
+ while(hFind != NULL && bResult == true)
+ {
+// printf("%s \r", sf.cFileName);
+ SFileSetLocale(sf.lcLocale);
+
+ // Open the first file
+ if(!SFileOpenFileEx(hMpq1, sf.cFileName, 0, &hFile1))
+ printf("Failed to open the file %s in the first archive\n", sf.cFileName);
+
+ if(!SFileOpenFileEx(hMpq2, sf.cFileName, 0, &hFile2))
+ printf("Failed to open the file %s in the second archive\n", sf.cFileName);
+
+ if(hFile1 != NULL && hFile2 != NULL)
+ {
+ // Get the TMPQFile pointers
+ hf1 = (TMPQFile *)hFile1;
+ hf2 = (TMPQFile *)hFile2;
+
+ // Compare the file sizes
+ if(hf1->pFileEntry->dwFileSize != hf2->pFileEntry->dwFileSize)
+ printf("Different file size: %s (%u x %u)\n", sf.cFileName, hf1->pFileEntry->dwFileSize, hf2->pFileEntry->dwFileSize);
+
+ if(hf1->pFileEntry->dwCmpSize != hf2->pFileEntry->dwCmpSize)
+ printf("Different cmpr size: %s (%u x %u)\n", sf.cFileName, hf1->pFileEntry->dwCmpSize, hf2->pFileEntry->dwCmpSize);
+
+ if(hf1->pFileEntry->dwFlags != hf2->pFileEntry->dwFlags)
+ printf("Different mpq flags: %s (%08X x %08X)\n", sf.cFileName, hf1->pFileEntry->dwFlags, hf2->pFileEntry->dwFlags);
+
+ if(!CompareArchivedFiles(sf.cFileName, hFile1, hFile2, dwBlockSize))
+ printf("Different file data: %s\n", sf.cFileName);
+
+// if(!CompareArchivedFilesRR(sf.cFileName, hFile1, hFile2, dwBlockSize))
+// printf("Different file data: %s\n", sf.cFileName);
+ }
+
+ // Close both files
+ if(hFile2 != NULL)
+ SFileCloseFile(hFile2);
+ if(hFile1 != NULL)
+ SFileCloseFile(hFile1);
+ hFile2 = hFile1 = NULL;
+
+ // Find the next file
+ bResult = SFileFindNextFile(hFind, &sf);
+ }
+
+ // Close the find handle
+ if(hFind != NULL)
+ SFileFindClose(hFind);
+ }
+
+ // Close both archives
+ clreol();
+ printf("================ MPQ compare complete ================\n");
+ if(hMpq2 != NULL)
+ SFileCloseArchive(hMpq2);
+ if(hMpq1 != NULL)
+ SFileCloseArchive(hMpq1);
+ return nError;
+}
+
+//-----------------------------------------------------------------------------
+// Searching all known MPQs
+
+#ifdef _WIN32
+static int TestSearchOneArchive(const TCHAR * szMpqName)
+{
+ SFILE_FIND_DATA sf;
+ HANDLE hFind;
+ HANDLE hMpq;
+ const TCHAR * szExtension;
+ bool bFound = true;
+
+ // Get the file extension
+ szExtension = _tcsrchr(szMpqName, _T('.'));
+ if(szExtension == NULL)
+ return ERROR_SUCCESS;
+
+ // Only search defined extensions
+ if(_tcsicmp(szExtension, _T(".mpq")) && _tcsnicmp(szExtension, _T(".SC2"), 4))
+ return ERROR_SUCCESS;
+
+ _tprintf(_T("Searching %s ...\n"), szMpqName);
+
+ // Try to open the MPQ
+ if(SFileOpenArchive(szMpqName, 0, MPQ_OPEN_READ_ONLY, &hMpq))
+ {
+ hFind = SFileFindFirstFile(hMpq, "*", &sf, NULL);
+ if(hFind != NULL)
+ {
+ while(bFound)
+ {
+ if(sf.dwFileFlags & MPQ_FILE_DELETE_MARKER)
+ _tprintf(_T("Delete marker: %s:%hs\n"), szMpqName, sf.cFileName);
+
+ bFound = SFileFindNextFile(hFind, &sf);
+ }
+ }
+
+ SFileCloseArchive(hMpq);
+ }
+
+ return ERROR_SUCCESS;
+}
+
+static int TestSearchAllArchives(const TCHAR * szSearchMask)
+{
+ WIN32_FIND_DATA wf;
+ LPTSTR szFilePart;
+ HANDLE hFind;
+ TCHAR szFullPath[MAX_PATH];
+ BOOL bFound = TRUE;
+
+ // Initiate search
+ _tcscpy(szFullPath, szSearchMask);
+ szFilePart = _tcschr(szFullPath, _T('*'));
+ assert(szFilePart != NULL);
+
+ // Begin search
+ hFind = FindFirstFile(szSearchMask, &wf);
+ if(hFind != INVALID_HANDLE_VALUE)
+ {
+ while(bFound)
+ {
+ // Eliminate "." and ".."
+ if(wf.cFileName[0] != _T('.'))
+ {
+ // Construct the full path
+ _tcscpy(szFilePart, wf.cFileName);
+
+ // If it a directory?
+ if(wf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ _tcscat(szFullPath, _T("\\*"));
+ TestSearchAllArchives(szFullPath);
+ }
+ else
+ {
+ TestSearchOneArchive(szFullPath);
+ }
+ }
+ bFound = FindNextFile(hFind, &wf);
+ }
+ FindClose(hFind);
+ }
+
+ return ERROR_SUCCESS;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Main
+//
+
+int main(void)
+{
+ int nError = ERROR_SUCCESS;
+
+#if defined(_MSC_VER) && defined(_DEBUG)
+ _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif // defined(_MSC_VER) && defined(_DEBUG)
+
+// FileStream_OpenEncrypted(_T("e:\\Multimedia\\MPQs\\2010 - Starcraft II\\Installer UI 2 deDE.MPQE"));
+
+ // Mix the random number generator
+// srand(GetTickCount());
+
+ // Test structure sizes
+// if(nError == ERROR_SUCCESS)
+// nError = TestStructureSizes();
+
+// if(nError == ERROR_SUCCESS)
+// nError = TestOpenLocalFile("C:\\autoexec.bat");
+
+ // Test reading partial file
+// if(nError == ERROR_SUCCESS)
+// nError = TestPartFileRead(MAKE_PATH("2009 - PartialMPQs/patch.MPQ.part"));
+
+// if(nError == ERROR_SUCCESS)
+// nError = ComparePklibCompressions();
+
+ // Test LZMA compression method against the code ripped from Starcraft II
+// if(nError == ERROR_SUCCESS)
+// nError = CompareLzmaCompressions(MPQ_SECTOR_SIZE);
+
+ // Test compression methods
+// if(nError == ERROR_SUCCESS)
+// nError = TestSectorCompress(MPQ_SECTOR_SIZE);
+
+ // Test the archive open and close
+// if(nError == ERROR_SUCCESS)
+// nError = TestArchiveOpenAndClose(_T("d:\\Install\\Blizzard\\Diablo III\\Diablo-III-8370-enGB-Installer\\Installer Tome 1.MPQE"));
+// nError = TestArchiveOpenAndClose(MAKE_PATH("2011 - WoW BETA/wow-update-13202.MPQ"));
+// nError = TestArchiveOpenAndClose(MAKE_PATH("2002 - Warcraft III/ProtectedMap_HashTable_FakeValid.w3x"));
+// nError = TestArchiveOpenAndClose(MAKE_PATH("2010 - Starcraft II/Installer Tome 1 enGB.MPQE"));
+// nError = TestArchiveOpenAndClose(MAKE_PATH("1997 - Diablo I/DIABDAT_orig.MPQ"));
+// nError = TestArchiveOpenAndClose(MAKE_PATH("2004 - World of Warcraft/SoundCache-enUS.MPQ"));
+// nError = TestArchiveOpenAndClose(MAKE_PATH("smpq.mpq "));
+
+// if(nError == ERROR_SUCCESS)
+// nError = TestFindFiles(MAKE_PATH("2002 - Warcraft III/HumanEd.mpq"));
+
+ // Create a big MPQ archive
+// if(nError == ERROR_SUCCESS)
+// nError = TestCreateArchive_PaliRoharBug(MAKE_PATH("Test.mpq"));
+// nError = TestCreateArchive(MAKE_PATH("Test.mpq"));
+// nError = TestCreateArchive((const TCHAR*)szUnicodeName1);
+// nError = TestCreateArchive((const TCHAR*)szUnicodeName2);
+// nError = TestCreateArchive((const TCHAR*)szUnicodeName3);
+// nError = TestCreateArchive((const TCHAR*)szUnicodeName4);
+// nError = TestCreateArchive((const TCHAR*)szUnicodeName5);
+// nError = TestCreateArchive((const TCHAR*)szUnicodeName6);
+
+// if(nError == ERROR_SUCCESS)
+// nError = TestAddFilesToMpq(MAKE_PATH("wow-update-13202.MPQ"),
+// "c:\\Tools32\\Arj32.exe",
+// "c:\\Tools32\\autoruns.chm",
+// "c:\\Tools32\\CPUEater.exe",
+// "c:\\Tools32\\dumpbin.exe",
+// "c:\\Tools32\\editbin.exe",
+// "c:\\Tools32\\fsg.ini",
+// "c:\\Tools32\\hiew8.ini",
+// "c:\\Tools32\\ida.bat",
+// "c:\\Tools32\\mp3.ini",
+// NULL);
+
+// if(nError == ERROR_SUCCESS)
+// nError = TestCreateArchiveFromMemory(MAKE_PATH("Test-leak.mpq"));
+
+// if(nError == ERROR_SUCCESS)
+// nError = TestFileReadAndWrite(MAKE_PATH("2002 - Warcraft III/(10)DustwallowKeys.w3m"), "war3map.j");
+
+ // Verify the archive signature
+// if(nError == ERROR_SUCCESS)
+// nError = TestSignatureVerify(MAKE_PATH("1998 - Starcraft/BW-1152.exe"));
+// nError = TestSignatureVerify(MAKE_PATH("2002 - Warcraft III/(10)DustwallowKeys.w3m"));
+// nError = TestSignatureVerify(MAKE_PATH("2002 - Warcraft III/War3TFT_121b_English.exe"));
+// nError = TestSignatureVerify(MAKE_PATH("2004 - World of Warcraft/WoW-2.3.3.7799-to-2.4.0.8089-enUS-patch.exe"));
+// nError = TestSignatureVerify(MAKE_PATH("2004 - World of Warcraft/standalone.MPQ"));
+
+ // Compact the archive
+// if(nError == ERROR_SUCCESS)
+// nError = TestMpqCompacting(MAKE_PATH("wow-update-base-14333.MPQ"));
+
+ // Create copy of the archive, appending some bytes before the MPQ header
+// if(nError == ERROR_SUCCESS)
+// nError = TestCreateArchiveCopy(MAKE_PATH("PartialMPQs/interface.MPQ.part"), MAKE_PATH("PartialMPQs/interface-copy.MPQ.part"), NULL);
+
+/*
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = TestOpenPatchedArchive(MAKE_PATH("2011 - WoW 4.x/locale-enGB.MPQ"),
+ MAKE_PATH("2011 - WoW 4.x/wow-update-13164.MPQ"),
+ MAKE_PATH("2011 - WoW 4.x/wow-update-13205.MPQ"),
+ MAKE_PATH("2011 - WoW 4.x/wow-update-13287.MPQ"),
+ MAKE_PATH("2011 - WoW 4.x/wow-update-13329.MPQ"),
+ MAKE_PATH("2011 - WoW 4.x/wow-update-13596.MPQ"),
+ MAKE_PATH("2011 - WoW 4.x/wow-update-13623.MPQ"),
+ MAKE_PATH("2011 - WoW 4.x/wow-update-enGB-13914.MPQ"),
+ MAKE_PATH("2011 - WoW 4.x/wow-update-enGB-14007.MPQ"),
+ MAKE_PATH("2011 - WoW 4.x/wow-update-enGB-14333.MPQ"),
+ MAKE_PATH("2011 - WoW 4.x/wow-update-enGB-14480.MPQ"),
+ NULL);
+ }
+*/
+
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = TestCompareTwoArchives(MAKE_PATH("Sound-copy.mpq"),
+ MAKE_PATH("Sound.mpq"),
+ NULL,
+ 0x1001);
+ }
+
+
+// if(nError == ERROR_SUCCESS)
+// nError = TestSearchAllArchives(MAKE_PATH("*"));
+
+ return nError;
+}
diff --git a/dep/StormLib/test/x86_ripped_code.asm b/dep/StormLib/test/x86_ripped_code.asm
new file mode 100644
index 00000000000..4b4be328a6c
--- /dev/null
+++ b/dep/StormLib/test/x86_ripped_code.asm
@@ -0,0 +1,1231 @@
+.686P
+.MODEL FLAT
+ASSUME FS: NOTHING
+.CODE
+
+extrn _memset:PROC
+extrn _memcpy:PROC
+extrn _memmove:PROC
+
+;------------------------------------------------------------------------------
+; Structures
+;
+
+;------------------------------------------------------------------------------
+; Functions
+;
+
+_aullrem proc near ; CODE XREF: sub_6CC140+3Ap
+ ; sub_6CC1E0+57p ...
+
+DividendLo = dword ptr 8
+DividendHi = dword ptr 0Ch
+DivisorLo = dword ptr 10h
+DivisorHi = dword ptr 14h
+
+ push ebx
+ mov eax, [esp+DivisorHi]
+ or eax, eax
+ jnz short loc_8F8FE1
+ mov ecx, [esp+DivisorLo]
+ mov eax, [esp+DividendHi]
+ xor edx, edx
+ div ecx
+ mov eax, [esp+DividendLo]
+ div ecx
+ mov eax, edx
+ xor edx, edx
+ jmp short loc_8F9031
+; ---------------------------------------------------------------------------
+
+loc_8F8FE1: ; CODE XREF: _aullrem+7j
+ mov ecx, eax
+ mov ebx, [esp+DivisorLo]
+ mov edx, [esp+DividendHi]
+ mov eax, [esp+DividendLo]
+
+loc_8F8FEF: ; CODE XREF: _aullrem+39j
+ shr ecx, 1
+ rcr ebx, 1
+ shr edx, 1
+ rcr eax, 1
+ or ecx, ecx
+ jnz short loc_8F8FEF
+ div ebx
+ mov ecx, eax
+ mul [esp+DivisorHi]
+ xchg eax, ecx
+ mul [esp+DivisorLo]
+ add edx, ecx
+ jb short loc_8F901A
+ cmp edx, [esp+DividendHi]
+ ja short loc_8F901A
+ jb short loc_8F9022
+ cmp eax, [esp+DividendLo]
+ jbe short loc_8F9022
+
+loc_8F901A: ; CODE XREF: _aullrem+4Aj
+ ; _aullrem+50j
+ sub eax, [esp+DivisorLo]
+ sbb edx, [esp+DivisorHi]
+
+loc_8F9022: ; CODE XREF: _aullrem+52j
+ ; _aullrem+58j
+ sub eax, [esp+DividendLo]
+ sbb edx, [esp+DividendHi]
+ neg edx
+ neg eax
+ sbb edx, 0
+
+loc_8F9031: ; CODE XREF: _aullrem+1Fj
+ pop ebx
+ retn 10h
+_aullrem endp
+
+_aullshr proc near ; CODE XREF: sub_40E2B6+1ECp
+ ; sub_40E2B6+240p ...
+ cmp cl, 40h
+ jnb short loc_414BDA
+ cmp cl, 20h
+ jnb short loc_414BD0
+ shrd eax, edx, cl
+ shr edx, cl
+ retn
+; ---------------------------------------------------------------------------
+
+loc_414BD0: ; CODE XREF: _aullshr+8j
+ mov eax, edx
+ xor edx, edx
+ and cl, 1Fh
+ shr eax, cl
+ retn
+; ---------------------------------------------------------------------------
+
+loc_414BDA: ; CODE XREF: _aullshr+3j
+ xor eax, eax
+ xor edx, edx
+ retn
+_aullshr endp
+
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+SFileDecryptMpqHeader proc near ; CODE XREF: sub_6D00E0+AEp
+ ; sub_6D00E0+D3p
+
+EncryptedDataAligned= dword ptr -88h
+var_48 = dword ptr -48h
+DecryptBuffer = dword ptr -44h
+var_40 = dword ptr -40h
+var_3C = dword ptr -3Ch
+var_38 = dword ptr -38h
+var_34 = dword ptr -34h
+var_30 = dword ptr -30h
+var_2C = dword ptr -2Ch
+var_28 = dword ptr -28h
+var_24 = dword ptr -24h
+var_20 = dword ptr -20h
+var_1C = dword ptr -1Ch
+var_18 = dword ptr -18h
+var_14 = dword ptr -14h
+var_10 = dword ptr -10h
+var_0C = dword ptr -0Ch
+var_8 = dword ptr -8
+var_4 = dword ptr -4
+arg_FFFFFFF8 = dword ptr 0
+arg_FFFFFFFC = dword ptr 4
+arg_0 = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ sub esp, 88h
+ mov eax, [ecx+8]
+ mov edx, [ecx+14h]
+ push ebx
+ mov ebx, [ecx+10h]
+ mov [ebp+var_0C], eax
+ mov eax, [ebp+arg_0]
+ push esi
+ push edi
+ mov edi, [ecx+0Ch]
+ mov [ebp+DecryptBuffer], ecx
+ mov [ebp+var_10], edx
+ test al, 3
+ jz short loc_6C9F03
+ mov ecx, [eax]
+ mov [ebp+EncryptedDataAligned], ecx
+ mov ecx, [eax+4]
+ mov [ebp+EncryptedDataAligned+4], ecx
+ mov ecx, [eax+8]
+ mov [ebp+EncryptedDataAligned+8], ecx
+ mov ecx, [eax+0Ch]
+ mov [ebp+EncryptedDataAligned+0Ch], ecx
+ mov ecx, [eax+10h]
+ mov [ebp+EncryptedDataAligned+10h], ecx
+ mov ecx, [eax+14h]
+ mov [ebp+EncryptedDataAligned+14h], ecx
+ mov ecx, [eax+18h]
+ mov [ebp+EncryptedDataAligned+18h], ecx
+ mov ecx, [eax+1Ch]
+ mov [ebp+EncryptedDataAligned+1Ch], ecx
+ mov ecx, [eax+20h]
+ mov [ebp+EncryptedDataAligned+20h], ecx
+ mov ecx, [eax+24h]
+ mov [ebp+EncryptedDataAligned+24h], ecx
+ mov ecx, [eax+28h]
+ mov [ebp+EncryptedDataAligned+28h], ecx
+ mov ecx, [eax+2Ch]
+ mov [ebp+EncryptedDataAligned+2Ch], ecx
+ mov ecx, [eax+30h]
+ mov [ebp+EncryptedDataAligned+30h], ecx
+ mov ecx, [eax+34h]
+ mov [ebp+EncryptedDataAligned+34h], ecx
+ mov ecx, [eax+38h]
+ mov eax, [eax+3Ch]
+ mov [ebp+EncryptedDataAligned+3Ch], eax
+ mov [ebp+EncryptedDataAligned+38h], ecx
+ lea eax, [ebp+EncryptedDataAligned]
+
+loc_6C9F03: ; CODE XREF: SFileDecryptMpqHeader+26j
+ mov ecx, [eax]
+ mov [ebp+var_30], ecx
+ mov esi, edi
+ not esi
+ and esi, edx
+ mov edx, ebx
+ and edx, edi
+ or esi, edx
+ add esi, ecx
+ mov ecx, [ebp+var_0C]
+ lea edx, [esi+ecx-28955B88h]
+ mov ecx, [eax+4]
+ rol edx, 7
+ add edx, edi
+ mov [ebp+var_2C], ecx
+ mov ecx, edx
+ not ecx
+ and ecx, ebx
+ mov esi, edi
+ and esi, edx
+ or ecx, esi
+ add ecx, [ebp+var_2C]
+ mov esi, [ebp+var_10]
+ lea esi, [ecx+esi-173848AAh]
+ mov ecx, [eax+8]
+ mov [ebp+var_40], ecx
+ rol esi, 0Ch
+ add esi, edx
+ mov ecx, esi
+ not ecx
+ and ecx, edi
+ mov edi, esi
+ and edi, edx
+ or ecx, edi
+ add ecx, [ebp+var_40]
+ lea edi, [ecx+ebx+242070DBh]
+ mov ecx, [eax+0Ch]
+ ror edi, 0Fh
+ add edi, esi
+ mov [ebp+var_1C], ecx
+ mov ebx, edi
+ not ebx
+ and ebx, edx
+ mov ecx, esi
+ and ecx, edi
+ or ebx, ecx
+ add ebx, [ebp+var_1C]
+ mov ecx, [ebp+DecryptBuffer]
+ mov ecx, [ecx+0Ch]
+ lea ecx, [ebx+ecx-3E423112h]
+ ror ecx, 0Ah
+ add ecx, edi
+ mov [ebp+var_4], edi
+ and edi, ecx
+ mov ebx, ecx
+ not ebx
+ and ebx, esi
+ or ebx, edi
+ mov edi, [eax+10h]
+ add ebx, edi
+ lea edx, [ebx+edx-0A83F051h]
+ rol edx, 7
+ add edx, ecx
+ mov [ebp+arg_0], edx
+ not edx
+ and edx, [ebp+var_4]
+ mov ebx, ecx
+ and ebx, [ebp+arg_0]
+ mov [ebp+var_10], edi
+ mov edi, [eax+14h]
+ or edx, ebx
+ add edx, edi
+ lea esi, [edx+esi+4787C62Ah]
+ mov edx, [eax+18h]
+ mov [ebp+var_34], edi
+ mov edi, [ebp+arg_0]
+ rol esi, 0Ch
+ add esi, edi
+ mov [ebp+var_20], edx
+ mov edx, esi
+ not edx
+ and edx, ecx
+ mov ebx, esi
+ and ebx, edi
+ or edx, ebx
+ add edx, [ebp+var_20]
+ mov ebx, [ebp+var_4]
+ lea edx, [edx+ebx-57CFB9EDh]
+ ror edx, 0Fh
+ add edx, esi
+ mov ebx, edx
+ not ebx
+ and ebx, edi
+ mov edi, esi
+ and edi, edx
+ or ebx, edi
+ mov edi, [eax+1Ch]
+ add ebx, edi
+ lea ecx, [ebx+ecx-2B96AFFh]
+ ror ecx, 0Ah
+ add ecx, edx
+ mov [ebp+var_3C], edi
+ mov edi, [eax+20h]
+ mov [ebp+var_14], edi
+ mov edi, ecx
+ not edi
+ and edi, esi
+ mov ebx, edx
+ and ebx, ecx
+ or edi, ebx
+ add edi, [ebp+var_14]
+ mov ebx, [ebp+arg_0]
+ lea edi, [edi+ebx+698098D8h]
+ mov [ebp+var_8], ecx
+ rol edi, 7
+ add edi, ecx
+ and ecx, edi
+ mov ebx, edi
+ not ebx
+ and ebx, edx
+ or ebx, ecx
+ mov ecx, [eax+24h]
+ add ebx, ecx
+ mov [ebp+var_0C], ecx
+ mov ecx, [eax+28h]
+ lea esi, [ebx+esi-74BB0851h]
+ mov [ebp+var_24], ecx
+ rol esi, 0Ch
+ add esi, edi
+ mov ecx, esi
+ not ecx
+ and ecx, [ebp+var_8]
+ mov ebx, esi
+ and ebx, edi
+ or ecx, ebx
+ add ecx, [ebp+var_24]
+ mov ebx, esi
+ lea edx, [ecx+edx-0A44Fh]
+ mov ecx, [eax+2Ch]
+ ror edx, 0Fh
+ add edx, esi
+ mov [ebp+var_18], ecx
+ and ebx, edx
+ mov ecx, edx
+ not ecx
+ and ecx, edi
+ or ecx, ebx
+ add ecx, [ebp+var_18]
+ mov ebx, [ebp+var_8]
+ lea ecx, [ecx+ebx-76A32842h]
+ ror ecx, 0Ah
+ add ecx, edx
+ mov ebx, ecx
+ not ebx
+ mov [ebp+var_4], edx
+ and edx, ecx
+ and ebx, esi
+ or ebx, edx
+ mov edx, [eax+30h]
+ add ebx, edx
+ mov [ebp+var_38], edx
+ lea edi, [ebx+edi+6B901122h]
+ mov edx, [eax+34h]
+ rol edi, 7
+ add edi, ecx
+ mov [ebp+arg_0], edi
+ not edi
+ and edi, [ebp+var_4]
+ mov ebx, ecx
+ and ebx, [ebp+arg_0]
+ mov [ebp+var_8], edx
+ or edi, ebx
+ add edi, edx
+ mov edx, [eax+38h]
+ mov eax, [eax+3Ch]
+ lea esi, [edi+esi-2678E6Dh]
+ rol esi, 0Ch
+ add esi, [ebp+arg_0]
+ mov [ebp+var_28], edx
+ mov edi, esi
+ not edi
+ mov edx, edi
+ and edx, ecx
+ mov ebx, esi
+ and ebx, [ebp+arg_0]
+ or edx, ebx
+ add edx, [ebp+var_28]
+ mov ebx, [ebp+var_4]
+ lea edx, [edx+ebx-5986BC72h]
+ mov [ebp+var_4], eax
+ ror edx, 0Fh
+ add edx, esi
+ mov ebx, edx
+ not ebx
+ mov [ebp+var_48], ebx
+ and ebx, [ebp+arg_0]
+ mov eax, esi
+ and eax, edx
+ or ebx, eax
+ add ebx, [ebp+var_4]
+ and edi, edx
+ lea ecx, [ebx+ecx+49B40821h]
+ ror ecx, 0Ah
+ add ecx, edx
+ mov eax, esi
+ and eax, ecx
+ or edi, eax
+ add edi, [ebp+var_2C]
+ mov eax, [ebp+arg_0]
+ lea edi, [edi+eax-9E1DA9Eh]
+ mov eax, [ebp+var_48]
+ and eax, ecx
+ rol edi, 5
+ add edi, ecx
+ mov ebx, edx
+ and ebx, edi
+ or eax, ebx
+ add eax, [ebp+var_20]
+ lea esi, [eax+esi-3FBF4CC0h]
+ rol esi, 9
+ add esi, edi
+ mov eax, ecx
+ not eax
+ and eax, edi
+ mov ebx, esi
+ and ebx, ecx
+ or eax, ebx
+ add eax, [ebp+var_18]
+ lea edx, [eax+edx+265E5A51h]
+ rol edx, 0Eh
+ add edx, esi
+ mov eax, edi
+ not eax
+ and eax, esi
+ mov ebx, edx
+ and ebx, edi
+ or eax, ebx
+ add eax, [ebp+var_30]
+ lea ecx, [eax+ecx-16493856h]
+ ror ecx, 0Ch
+ mov eax, esi
+ add ecx, edx
+ not eax
+ and eax, edx
+ mov ebx, esi
+ and ebx, ecx
+ or eax, ebx
+ add eax, [ebp+var_34]
+ lea edi, [eax+edi-29D0EFA3h]
+ rol edi, 5
+ add edi, ecx
+ mov [ebp+arg_0], edi
+ mov eax, edx
+ not eax
+ and eax, ecx
+ mov edi, edx
+ and edi, [ebp+arg_0]
+ or eax, edi
+ add eax, [ebp+var_24]
+ mov edi, ecx
+ lea esi, [eax+esi+2441453h]
+ mov eax, [ebp+arg_0]
+ not edi
+ and edi, eax
+ rol esi, 9
+ add esi, eax
+ not eax
+ and eax, esi
+ mov ebx, esi
+ and ebx, ecx
+ or edi, ebx
+ add edi, [ebp+var_4]
+ lea edx, [edi+edx-275E197Fh]
+ rol edx, 0Eh
+ add edx, esi
+ mov edi, edx
+ and edi, [ebp+arg_0]
+ or eax, edi
+ add eax, [ebp+var_10]
+ mov edi, esi
+ lea ecx, [eax+ecx-182C0438h]
+ ror ecx, 0Ch
+ add ecx, edx
+ and edi, ecx
+ mov eax, esi
+ not eax
+ and eax, edx
+ or eax, edi
+ add eax, [ebp+var_0C]
+ mov edi, [ebp+arg_0]
+ lea eax, [eax+edi+21E1CDE6h]
+ rol eax, 5
+ add eax, ecx
+ mov [ebp+arg_0], eax
+ mov eax, edx
+ not eax
+ and eax, ecx
+ mov edi, edx
+ and edi, [ebp+arg_0]
+ or eax, edi
+ add eax, [ebp+var_28]
+ mov edi, ecx
+ lea esi, [eax+esi-3CC8F82Ah]
+ mov eax, [ebp+arg_0]
+ rol esi, 9
+ add esi, eax
+ not edi
+ and edi, eax
+ mov ebx, esi
+ and ebx, ecx
+ or edi, ebx
+ add edi, [ebp+var_1C]
+ not eax
+ lea edx, [edi+edx-0B2AF279h]
+ rol edx, 0Eh
+ add edx, esi
+ and eax, esi
+ mov edi, edx
+ and edi, [ebp+arg_0]
+ or eax, edi
+ add eax, [ebp+var_14]
+ lea ecx, [eax+ecx+455A14EDh]
+ ror ecx, 0Ch
+ add ecx, edx
+ mov eax, esi
+ not eax
+ and eax, edx
+ mov edi, esi
+ and edi, ecx
+ or eax, edi
+ add eax, [ebp+var_8]
+ mov edi, [ebp+arg_0]
+ lea eax, [eax+edi-561C16FBh]
+ rol eax, 5
+ add eax, ecx
+ mov [ebp+arg_0], eax
+ mov eax, edx
+ not eax
+ and eax, ecx
+ mov edi, edx
+ and edi, [ebp+arg_0]
+ or eax, edi
+ add eax, [ebp+var_40]
+ mov edi, ecx
+ lea esi, [eax+esi-3105C08h]
+ mov eax, [ebp+arg_0]
+ not edi
+ and edi, eax
+ rol esi, 9
+ add esi, eax
+ mov ebx, esi
+ and ebx, ecx
+ or edi, ebx
+ add edi, [ebp+var_3C]
+ not eax
+ lea edx, [edi+edx+676F02D9h]
+ and eax, esi
+ rol edx, 0Eh
+ add edx, esi
+ mov edi, edx
+ and edi, [ebp+arg_0]
+ or eax, edi
+ add eax, [ebp+var_38]
+ mov edi, [ebp+arg_0]
+ lea ecx, [eax+ecx-72D5B376h]
+ ror ecx, 0Ch
+ add ecx, edx
+ mov eax, esi
+ xor eax, edx
+ xor eax, ecx
+ add eax, [ebp+var_34]
+ lea eax, [eax+edi-5C6BEh]
+ rol eax, 4
+ add eax, ecx
+ mov edi, edx
+ xor edi, ecx
+ xor edi, eax
+ add edi, [ebp+var_14]
+ lea esi, [edi+esi-788E097Fh]
+ rol esi, 0Bh
+ add esi, eax
+ mov edi, esi
+ xor edi, ecx
+ xor edi, eax
+ add edi, [ebp+var_18]
+ lea edx, [edi+edx+6D9D6122h]
+ rol edx, 10h
+ add edx, esi
+ mov edi, esi
+ xor edi, edx
+ mov ebx, edi
+ xor ebx, eax
+ add ebx, [ebp+var_28]
+ lea ecx, [ebx+ecx-21AC7F4h]
+ ror ecx, 9
+ add ecx, edx
+ xor edi, ecx
+ add edi, [ebp+var_2C]
+ lea eax, [edi+eax-5B4115BCh]
+ rol eax, 4
+ mov edi, edx
+ add eax, ecx
+ xor edi, ecx
+ xor edi, eax
+ add edi, [ebp+var_10]
+ lea esi, [edi+esi+4BDECFA9h]
+ rol esi, 0Bh
+ add esi, eax
+ mov edi, esi
+ xor edi, ecx
+ xor edi, eax
+ add edi, [ebp+var_3C]
+ lea edx, [edi+edx-944B4A0h]
+ rol edx, 10h
+ add edx, esi
+ mov edi, esi
+ xor edi, edx
+ mov ebx, edi
+ xor ebx, eax
+ add ebx, [ebp+var_24]
+ lea ecx, [ebx+ecx-41404390h]
+ ror ecx, 9
+ add ecx, edx
+ xor edi, ecx
+ add edi, [ebp+var_8]
+ lea eax, [edi+eax+289B7EC6h]
+ rol eax, 4
+ add eax, ecx
+ mov edi, edx
+ xor edi, ecx
+ xor edi, eax
+ add edi, [ebp+var_30]
+ lea esi, [edi+esi-155ED806h]
+ rol esi, 0Bh
+ add esi, eax
+ mov edi, esi
+ xor edi, ecx
+ xor edi, eax
+ add edi, [ebp+var_1C]
+ lea edi, [edi+edx-2B10CF7Bh]
+ rol edi, 10h
+ add edi, esi
+ mov edx, esi
+ xor edx, edi
+ mov ebx, edx
+ xor ebx, eax
+ add ebx, [ebp+var_20]
+ lea ecx, [ebx+ecx+4881D05h]
+ ror ecx, 9
+ add ecx, edi
+ xor edx, ecx
+ add edx, [ebp+var_0C]
+ lea eax, [edx+eax-262B2FC7h]
+ rol eax, 4
+ add eax, ecx
+ mov edx, edi
+ xor edx, ecx
+ xor edx, eax
+ add edx, [ebp+var_38]
+ lea edx, [edx+esi-1924661Bh]
+ rol edx, 0Bh
+ add edx, eax
+ mov esi, edx
+ xor esi, ecx
+ xor esi, eax
+ add esi, [ebp+var_4]
+ mov ebx, edx
+ lea esi, [esi+edi+1FA27CF8h]
+ mov edi, [ebp+var_40]
+ rol esi, 10h
+ add esi, edx
+ xor ebx, esi
+ xor ebx, eax
+ add ebx, edi
+ lea ecx, [ebx+ecx-3B53A99Bh]
+ ror ecx, 9
+ add ecx, esi
+ mov ebx, edx
+ not ebx
+ or ebx, ecx
+ xor ebx, esi
+ add ebx, [ebp+var_30]
+ lea eax, [ebx+eax-0BD6DDBCh]
+ rol eax, 6
+ add eax, ecx
+ mov ebx, esi
+ not ebx
+ or ebx, eax
+ xor ebx, ecx
+ add ebx, [ebp+var_3C]
+ lea edx, [ebx+edx+432AFF97h]
+ rol edx, 0Ah
+ add edx, eax
+ mov ebx, ecx
+ not ebx
+ or ebx, edx
+ xor ebx, eax
+ add ebx, [ebp+var_28]
+ lea esi, [ebx+esi-546BDC59h]
+ rol esi, 0Fh
+ add esi, edx
+ mov ebx, eax
+ not ebx
+ or ebx, esi
+ xor ebx, edx
+ add ebx, [ebp+var_34]
+ lea ecx, [ebx+ecx-36C5FC7h]
+ ror ecx, 0Bh
+ add ecx, esi
+ mov ebx, edx
+ not ebx
+ or ebx, ecx
+ xor ebx, esi
+ add ebx, [ebp+var_38]
+ lea eax, [ebx+eax+655B59C3h]
+ rol eax, 6
+ add eax, ecx
+ mov ebx, esi
+ not ebx
+ or ebx, eax
+ xor ebx, ecx
+ add ebx, [ebp+var_1C]
+ lea edx, [ebx+edx-70F3336Eh]
+ rol edx, 0Ah
+ add edx, eax
+ mov ebx, ecx
+ not ebx
+ or ebx, edx
+ xor ebx, eax
+ add ebx, [ebp+var_24]
+ lea esi, [ebx+esi-100B83h]
+ rol esi, 0Fh
+ add esi, edx
+ mov ebx, eax
+ not ebx
+ or ebx, esi
+ xor ebx, edx
+ add ebx, [ebp+var_2C]
+ lea ecx, [ebx+ecx-7A7BA22Fh]
+ ror ecx, 0Bh
+ add ecx, esi
+ mov ebx, edx
+ not ebx
+ or ebx, ecx
+ xor ebx, esi
+ add ebx, [ebp+var_14]
+ lea eax, [ebx+eax+6FA87E4Fh]
+ rol eax, 6
+ add eax, ecx
+ mov ebx, esi
+ not ebx
+ or ebx, eax
+ xor ebx, ecx
+ add ebx, [ebp+var_4]
+ lea edx, [ebx+edx-1D31920h]
+ rol edx, 0Ah
+ add edx, eax
+ mov ebx, ecx
+ not ebx
+ or ebx, edx
+ xor ebx, eax
+ add ebx, [ebp+var_20]
+ lea esi, [ebx+esi-5CFEBCECh]
+ rol esi, 0Fh
+ mov ebx, eax
+ add esi, edx
+ not ebx
+ or ebx, esi
+ xor ebx, edx
+ add ebx, [ebp+var_8]
+ lea ecx, [ebx+ecx+4E0811A1h]
+ ror ecx, 0Bh
+ add ecx, esi
+ mov ebx, edx
+ not ebx
+ or ebx, ecx
+ xor ebx, esi
+ add ebx, [ebp+var_10]
+ lea eax, [ebx+eax-8AC817Eh]
+ rol eax, 6
+ add eax, ecx
+ mov ebx, esi
+ not ebx
+ or ebx, eax
+ xor ebx, ecx
+ add ebx, [ebp+var_18]
+ lea edx, [ebx+edx-42C50DCBh]
+ rol edx, 0Ah
+ add edx, eax
+ mov ebx, ecx
+ not ebx
+ or ebx, edx
+ xor ebx, eax
+ add ebx, edi
+ lea esi, [ebx+esi+2AD7D2BBh]
+ mov edi, eax
+ not edi
+ rol esi, 0Fh
+ add esi, edx
+ or edi, esi
+ xor edi, edx
+ add edi, [ebp+var_0C]
+ lea edi, [edi+ecx-14792C6Fh]
+ mov ecx, [ebp+DecryptBuffer]
+ mov ebx, [ecx+8]
+ add ebx, eax
+ mov eax, [ecx+10h]
+ ror edi, 0Bh
+ add edi, [ecx+0Ch]
+ add eax, esi
+ add edi, esi
+ mov [ecx+10h], eax
+ mov eax, [ecx+14h]
+ mov [ecx+0Ch], edi
+ pop edi
+ add eax, edx
+ pop esi
+ mov [ecx+8], ebx
+ mov [ecx+14h], eax
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+SFileDecryptMpqHeader endp
+
+; ---------------------------------------------------------------------------
+
+; ---------------------------------------------------------------------------
+
+sub_6D00E0 proc near ; CODE XREF: sub_6D0210+59p
+ ; sub_6D0210+66p ...
+
+var_10 = dword ptr -10h
+pbMpqHeader = dword ptr -4
+pMpqHeader = dword ptr 8
+dwSize = dword ptr 0Ch
+
+ push ebp
+ mov ebp, esp
+ push ecx
+ mov eax, [ebp+pMpqHeader] ; EAX = MPQ Header
+ push ebx
+ mov ebx, [ebp+dwSize] ; EBX - size of MPQ Header
+ push esi
+ push edi
+ mov esi, ecx ; ESI - decryption buffer (6 DWORDs)
+ mov edi, [esi]
+ shr edi, 3
+ and edi, 3Fh
+ mov [ebp+pbMpqHeader], eax
+ lea ecx, ds:0[ebx*8] ; ECX = sizeof header * 8
+ test ebx, ebx
+ jbe loc_6D01F8
+ add [esi], ecx
+ mov edx, ebx ; EDX = size of header
+ shr edx, 1Dh
+ add [esi+4], edx
+ mov edx, [esi+4]
+ cmp [esi], ecx
+ jnb short loc_6D011E
+ inc edx
+ mov [esi+4], edx
+
+loc_6D011E: ; CODE XREF: sub_6D00E0+38j
+ test edi, edi
+ jz short loc_6D0196
+ lea eax, [edi+ebx]
+ cmp eax, 40h
+ jbe short loc_6D0136
+ mov eax, 40h
+ sub eax, edi
+ mov [ebp+dwSize], eax
+ jmp short loc_6D013B
+; ---------------------------------------------------------------------------
+
+loc_6D0136: ; CODE XREF: sub_6D00E0+48j
+ mov [ebp+dwSize], ebx
+ mov eax, ebx
+
+loc_6D013B: ; CODE XREF: sub_6D00E0+54j
+ mov edx, [ebp+pMpqHeader]
+ add edx, eax
+ lea ecx, [edi+esi+18h]
+ mov [ebp+pbMpqHeader], edx
+ cmp ecx, edx
+ jnb short loc_6D0163
+ lea edx, [ecx+eax]
+ mov ecx, [ebp+pMpqHeader]
+ cmp edx, ecx
+ jbe short loc_6D0166
+ push eax
+ push ecx
+ lea eax, [edi+esi+18h]
+ push eax
+ call _memmove
+ jmp short loc_6D0172
+; ---------------------------------------------------------------------------
+
+loc_6D0163: ; CODE XREF: sub_6D00E0+69j
+ mov ecx, [ebp+pMpqHeader]
+
+loc_6D0166: ; CODE XREF: sub_6D00E0+73j
+ push eax
+ push ecx
+ lea eax, [edi+esi+18h]
+ push eax
+ call _memcpy
+
+loc_6D0172: ; CODE XREF: sub_6D00E0+81j
+ mov eax, [ebp+dwSize]
+ lea ecx, [eax+edi]
+ add esp, 0Ch
+ cmp ecx, 40h
+ jl short loc_6D01F8
+ mov edx, [ebp+pbMpqHeader]
+ sub ebx, eax
+ lea eax, [esi+18h]
+ push eax
+ mov ecx, esi
+ mov [ebp+pbMpqHeader], edx
+ call SFileDecryptMpqHeader
+ mov eax, [ebp+pbMpqHeader]
+
+loc_6D0196: ; CODE XREF: sub_6D00E0+40j
+ cmp ebx, 40h
+ jl short loc_6D01C4
+ mov edi, ebx
+ shr edi, 6
+ mov ecx, edi
+ neg ecx
+ shl ecx, 6
+ add ebx, ecx
+ lea esp, [esp+0]
+
+loc_6D01B0: ; CODE XREF: sub_6D00E0+E2j
+ push eax
+ mov ecx, esi
+ call SFileDecryptMpqHeader
+ add [ebp+pbMpqHeader], 40h
+ sub edi, 1
+ mov eax, [ebp+pbMpqHeader]
+ jnz short loc_6D01B0
+
+loc_6D01C4: ; CODE XREF: sub_6D00E0+B9j
+ test ebx, ebx
+ jz short loc_6D01F8
+ add esi, 18h
+ lea edx, [ebx+eax]
+ cmp esi, edx
+ jnb short loc_6D01ED
+ lea ecx, [esi+ebx]
+ cmp ecx, eax
+ jbe short loc_6D01ED
+ push ebx
+ push eax
+ push esi
+ call _memmove
+ add esp, 0Ch
+ pop edi
+ pop esi
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_6D01ED: ; CODE XREF: sub_6D00E0+F0j
+ ; sub_6D00E0+F7j
+ push ebx
+ push eax
+ push esi
+ call _memcpy
+ add esp, 0Ch
+
+loc_6D01F8: ; CODE XREF: sub_6D00E0+23j
+ ; sub_6D00E0+9Ej ...
+ pop edi
+ pop esi
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 8
+sub_6D00E0 endp
+
+aA_1: ; DATA XREF: sub_6249D0+68o
+ ; sub_6D0210+4Fo ...
+ dw 80h, 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+
+sub_6D0210 proc near ; CODE XREF: SFileVerifyMpqHeaderMD5+42p
+ ; sub_6D2D60+A9p ...
+
+var_8 = byte ptr -8
+var_6 = byte ptr -6
+var_5 = byte ptr -5
+var_4 = byte ptr -4
+var_3 = byte ptr -3
+var_2 = byte ptr -2
+var_1 = byte ptr -1
+arg_0 = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ sub esp, 8
+ push esi
+ mov esi, ecx ; Source address
+ mov eax, [esi]
+ mov ecx, eax
+ shr ecx, 8
+ mov [ebp-7], cl
+ mov ecx, eax
+ shr ecx, 18h
+ mov [ebp+var_5], cl
+ mov ecx, [esi+4]
+ mov edx, eax
+ shr edx, 10h
+ mov [ebp+var_6], dl
+ mov edx, ecx
+ mov [ebp+var_4], cl
+ shr edx, 8
+ mov [ebp+var_3], dl
+ mov edx, ecx
+ shr ecx, 18h
+ mov [ebp+var_1], cl
+ mov [ebp+var_8], al
+ shr eax, 3
+ mov ecx, 0FFFFFFF7h
+ sub ecx, eax
+ and ecx, 3Fh
+ push edi
+ inc ecx
+ push ecx
+ shr edx, 10h
+ push offset aA_1 ; ""
+ mov ecx, esi
+ mov [ebp+var_2], dl
+ call sub_6D00E0
+ push 8
+ lea edx, [ebp+var_8]
+ push edx
+ mov ecx, esi
+ call sub_6D00E0
+ mov edi, [ebp+arg_0]
+ xor eax, eax
+
+loc_6D0280: ; CODE XREF: sub_6D0210+8Ej
+ mov ecx, eax
+ and ecx, 3
+ add ecx, ecx
+ mov edx, eax
+ sar edx, 2
+ mov edx, [esi+edx*4+8]
+ add ecx, ecx
+ add ecx, ecx
+ shr edx, cl
+ inc eax
+ cmp eax, 10h
+ mov [eax+edi-1], dl
+ jl short loc_6D0280
+ pop edi
+ pop esi
+ mov esp, ebp
+ pop ebp
+ retn 4
+sub_6D0210 endp
+
+
+sub_6CEBE0 proc near ; CODE XREF: sub_4A72D0+49p
+ ; SFileVerifyMpqHeaderMD5+51p ...
+
+var_4 = dword ptr -4
+arg_0 = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ mov edx, [ebp+arg_0]
+ mov eax, 10h
+ push esi
+ lea esp, [esp+0]
+
+loc_6CEBF0: ; CODE XREF: sub_6CEBE0+22j
+ mov esi, [ecx]
+ cmp esi, [edx]
+ jnz short loc_6CEC14
+ sub eax, 4
+ add edx, 4
+ add ecx, 4
+ cmp eax, 4
+ jnb short loc_6CEBF0
+ xor eax, eax
+ xor edx, edx
+ test eax, eax
+ setz dl
+ mov al, dl
+ pop esi
+ pop ebp
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_6CEC14: ; CODE XREF: sub_6CEBE0+14j
+ movzx eax, byte ptr [ecx]
+ movzx esi, byte ptr [edx]
+ sub eax, esi
+ jnz short loc_6CEC40
+ movzx eax, byte ptr [ecx+1]
+ movzx esi, byte ptr [edx+1]
+ sub eax, esi
+ jnz short loc_6CEC40
+ movzx eax, byte ptr [ecx+2]
+ movzx esi, byte ptr [edx+2]
+ sub eax, esi
+ jnz short loc_6CEC40
+ movzx eax, byte ptr [ecx+3]
+ movzx ecx, byte ptr [edx+3]
+ sub eax, ecx
+
+loc_6CEC40: ; CODE XREF: sub_6CEBE0+3Cj
+ ; sub_6CEBE0+48j ...
+ sar eax, 1Fh
+ or eax, 1
+ xor edx, edx
+ test eax, eax
+ setz dl
+ mov al, dl
+ pop esi
+ pop ebp
+ retn 4
+sub_6CEBE0 endp
+
+SFileVerifyMpqHeaderMD5 proc near ; CODE XREF: SFileVerifyMpqHeader+6Bp
+
+var_68 = dword ptr -68h
+var_64 = dword ptr -64h
+var_60 = dword ptr -60h
+var_5C = dword ptr -5Ch
+var_58 = dword ptr -58h
+var_54 = dword ptr -54h
+var_10 = dword ptr -10h
+
+ push ebp
+ mov ebp, esp
+ sub esp, 68h
+ push esi
+ mov esi, eax ; ESI = pointer to MPQ Header
+ xor eax, eax
+ push 0C0h
+ push esi
+ lea ecx, [ebp+var_68]
+ mov [ebp+var_64], eax
+ mov [ebp+var_68], eax
+ mov [ebp+var_60], 67452301h
+ mov [ebp+var_5C], 0EFCDAB89h
+ mov [ebp+var_58], 98BADCFEh
+ mov [ebp+var_54], 10325476h
+ call sub_6D00E0
+ lea eax, [ebp+var_10]
+ push eax
+ lea ecx, [ebp+var_68]
+ call sub_6D0210
+ add esi, 0C0h
+ push esi
+ lea ecx, [ebp+var_10]
+ call sub_6CEBE0
+ pop esi
+ mov esp, ebp
+ pop ebp
+ retn
+SFileVerifyMpqHeaderMD5 endp
+
+
+_wow_SFileVerifyMpqHeaderMD5 proc
+ push ebp
+ mov ebp, esp
+ mov eax, [ebp+8]
+ call SFileVerifyMpqHeaderMD5
+ mov esp, ebp
+ pop ebp
+ retn
+_wow_SFileVerifyMpqHeaderMD5 endp
+
+END
diff --git a/dep/StormLib/test/x86_starcraft_lzma.asm b/dep/StormLib/test/x86_starcraft_lzma.asm
new file mode 100644
index 00000000000..bb13200b432
--- /dev/null
+++ b/dep/StormLib/test/x86_starcraft_lzma.asm
@@ -0,0 +1,11066 @@
+;
+; LZMA compression code ripped from Starctaft II BEta
+; Used while StormLib's LZMA implementation was tested against Starcraft compression
+; Not used in StormLib.
+;
+
+.686P
+.MODEL FLAT
+ASSUME FS: NOTHING
+
+.DATA
+
+;---------------------------------------------------------------------------
+; Data
+
+byte_4CB248 db 0, 0Bh, 0Bh, 0Bh ; indirect table for switch statement
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 1, 2, 3, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 4, 5, 6, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 7, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 8, 9, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Bh, 0Bh, 0Bh, 0Bh
+ db 0Ah
+ align 10h
+
+dword_544960 dd 0BB40E64Eh ; DATA XREF: sub_401C72+B
+dword_553598 dd ? ; DATA XREF: sub_4CB8A0+9
+
+off_50CD3C dd offset sub_4A0605 ; DATA XREF: sub_4A05F7+1o
+ ; .data:off_52A004o ...
+dword_50CD40 dd 0E06D7363h ; DATA XREF: _CxxThrowException(x,x)+Eo
+ dd 1
+ dd 0
+ dd 0
+ dd 3
+ dd 19930520h
+ dd 0
+ dd 0
+
+; ---------------------------------------------------------------------------
+
+off_546E20 dd offset sub_4CDD70 ; DATA XREF: sub_4D0270:loc_4D0324o
+off_546E24 dd offset sub_4CDD90 ; DATA XREF: sub_4CF810+53r
+off_546E28 dd offset off_50CD3C ; DATA XREF: .rdata:off_51B888o
+ dd 0
+ db '.?AUISequentialInStream@@',0
+ db 0
+ db 0
+off_546E4C dd offset off_50CD3C ; DATA XREF: .rdata:off_51B8C0o
+ dd 0
+ db '.?AUISequentialOutStream@@',0
+ db 0
+off_546E70 dd offset off_50CD3C ; DATA XREF: .rdata:off_51B8F8o
+ dd 0
+ db '.?AUICompressCoder@@',0
+ db 0
+ db 0
+ db 0
+off_546E90 dd offset off_50CD3C ; DATA XREF: .rdata:off_51B944o
+ dd 0
+ db '.?AUICompressSetOutStream@@',0
+off_546EB4 dd offset off_50CD3C ; DATA XREF: .rdata:0051B96Co
+ dd 0
+ db '.?AUICompressSetCoderProperties@@',0
+ db 0
+ db 0
+off_546EE0 dd offset off_50CD3C ; DATA XREF: .rdata:0051B9B8o
+ dd 0
+ db '.?AUICompressWriteCoderProperties@@',0
+ dd offset off_50CD3C
+ dd 0
+ db '.?AUCSystemException@@',0
+ db 0
+ dd offset off_50CD3C
+ dd 0
+ db '.?AUCOutBufferException@@',0
+ db 0
+ db 0
+off_546F50 dd offset off_50CD3C ; DATA XREF: .rdata:0051BA04o
+ dd 0
+ db '.?AVCInStreamMemory@@',0
+ db 0
+ db 0
+off_546F70 dd offset off_50CD3C ; DATA XREF: .rdata:off_51BA4Co
+ dd 0
+ db '.?AVCMyUnknownImp@@',0
+off_546F8C dd offset off_50CD3C ; DATA XREF: .rdata:0051BAA8o
+ dd 0
+ db '.?AVCOutStreamMemory@@',0
+ db 0
+off_546FAC dd offset off_50CD3C ; DATA XREF: .rdata:0051BAFCo
+ dd 0
+ db '.?AVCEncoder@NLZMA@NCompress@@',0
+ db 0
+off_546FD4 dd offset off_50CD3C ; DATA XREF: .rdata:off_51BBECo
+ dd 0
+ db '.?AVCBaseState@NLZMA@NCompress@@',0
+ db 0
+ db 0
+ db 0
+
+; ---------------------------------------------------------------------------
+
+dword_51B960 dd 0 ; DATA XREF: .rdata:00517A64o
+ dd 0
+ dd 0
+ dd offset off_546EB4
+ dd 0 ; offset dword_51B974
+
+dword_51B9AC dd 0 ; DATA XREF: .rdata:00517A78o
+ dd 0
+ dd 0
+ dd offset off_546EE0
+ dd 0 ;offset dword_51B9C0
+
+dword_51B9F8 dd 0 ; DATA XREF: .rdata:00517A8Co
+ dd 0
+ dd 0
+ dd offset off_546F50
+ dd 0 ; offset dword_51BA0C
+
+dword_51BA9C dd 0 ; DATA XREF: .rdata:00517AA0o
+ dd 0
+ dd 0
+ dd offset off_546F8C
+ dd 0 ; offset dword_51BAB0
+
+dword_51BAF0 dd 0 ; DATA XREF: .rdata:00517AF8o
+ dd 0
+ dd 0
+ dd offset off_546FAC
+ dd 0 ; offset dword_51BB04
+
+dword_51BC58 dd 0 ; DATA XREF: .rdata:00517AE0o
+ dd 4
+ dd 0
+ dd offset off_546FAC
+ dd 0 ; offset dword_51BB04
+
+dword_51BC6C dd 0 ; DATA XREF: .rdata:00517ACCo
+ dd 8
+ dd 0
+ dd offset off_546FAC
+ dd 0 ; offset dword_51BB04
+
+dword_51BC80 dd 0 ; DATA XREF: .rdata:00517AB8o
+ dd 0Ch
+ dd 0
+ dd offset off_546FAC
+ dd 0 ; offset dword_51BB04
+
+; ---------------------------------------------------------------------------
+
+dword_512730 dd 0 ; DATA XREF: sub_48DB4D+B9o
+dword_512734 dd 0 ; DATA XREF: CCmdTarget::GetInterface(void const *)+2Dr
+dword_512738 dd 0C0h ; DATA XREF: CCmdTarget::GetInterface(void const *)+38r
+dword_51273C dd 46000000h ; DATA XREF: CCmdTarget::GetInterface(void const *)+43r
+
+dword_5535A0 dd ? ; DATA XREF: sub_4CF900:loc_4CF94Co
+dword_5535A4 dd ? ; DATA XREF: .text:004DAF37w
+dword_5535A8 dd ? ; DATA XREF: .text:004DAF3Cw
+dword_5535AC dd ? ; DATA XREF: .text:004DAF41w
+
+dword_5535B0 dd ? ; DATA XREF: sub_4CF900+5Eo
+dword_5535B4 dd ? ; DATA XREF: .text:004DAF17w
+dword_5535B8 dd ? ; DATA XREF: .text:004DAF1Cw
+dword_5535BC dd ? ; DATA XREF: .text:004DAF21w
+
+dword_5535C0 dd ? ; DATA XREF: sub_4CF900:loc_4CF98Fo
+dword_5535C4 dd ? ; DATA XREF: .text:004DAEF7w
+dword_5535C8 dd ? ; DATA XREF: .text:004DAEFCw
+dword_5535CC dd ? ; DATA XREF: .text:004DAF01w
+
+
+dword_526DD0 dd 0 ; DATA XREF: .text:loc_4CF6CBo
+ dd 0
+ dd 0
+ dd 0 ; offset dword_526DE0
+
+kLiteralNextStates db 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5
+kMatchNextStates db 7, 7, 7, 7, 7, 7, 7, 0Ah, 0Ah, 0Ah, 0Ah, 0Ah
+kRepNextStates db 8, 8, 8, 8, 8, 8, 8, 0Bh, 0Bh, 0Bh, 0Bh, 0Bh
+kShortRepNextStates db 9, 9, 9, 9, 9, 9, 9, 0Bh, 0Bh, 0Bh, 0Bh, 0Bh
+
+dword_550998 dd 200h dup(?)
+dword_551198 dd 800h dup(?)
+dword_553198 dd 100h dup(?)
+
+ICompressSetOutStream_vftable dd offset __purecall ; DATA XREF: NCompress_NLZMA_CEncoder_CEncoder+2o
+ dd offset __purecall
+ dd offset __purecall
+ dd offset __purecall
+ dd offset __purecall
+ dd offset dword_51B960
+ICompressSetCoderProperties_vftable dd offset __purecall ; DATA XREF: NCompress_NLZMA_CEncoder_CEncoder+9o
+ dd offset __purecall
+ dd offset __purecall
+ dd offset __purecall
+ dd offset dword_51B9AC
+ICompressWriteCoderProperties_vftable dd offset __purecall ; DATA XREF: NCompress_NLZMA_CEncoder_CEncoder+10o
+ dd offset __purecall
+ dd offset __purecall
+ dd offset __purecall
+ dd offset dword_51B9F8
+off_517A90 dd offset Interface1_QueryInterface
+ dd offset Interface1_AddRef
+ dd offset Interface1_Release
+ dd offset sub_4CCB20
+ dd offset dword_51BA9C
+off_517AA4 dd offset Interface1_QueryInterface ; DATA XREF: sub_4CF610+Eo
+ dd offset Interface1_AddRef
+ dd offset Interface2_Release
+ dd offset sub_4CCB90
+ dd offset sub_4CF590
+ dd offset dword_51BC80
+NCompress_NLZMA_CEncoder_vftable_ICompressWriteCoderProperties dd offset sub_4CFA50 ; DATA XREF: sub_4CF810+3Do
+ dd offset sub_4CFA10
+ dd offset sub_4CFA70
+ dd offset sub_4CDDB0
+ dd offset dword_51BC6C
+NCompress_NLZMA_CEncoder_vftable_ICompressSetCoderProperties dd offset ICompressSetCoderProperties_QueryInterface ; DATA XREF: sub_4CF810+36o
+ dd offset ICompressSetCoderProperties_AddRef
+ dd offset ICompressSetCoderProperties_Release
+ dd offset ICompressSetCoderProperties_SetCoderProperties
+ dd offset dword_51BC58
+NCompress_NLZMA_CEncoder_vftable_ICompressSetOutStream dd offset sub_4CFA20 ; DATA XREF: sub_4CF810+2Fo
+ dd offset sub_4CFA80
+ dd offset sub_4CFA40
+ dd offset sub_4CFA90
+ dd offset sub_4CDE70
+ dd offset dword_51BAF0
+NCompress_NLZMA_CEncoder_vftable dd offset sub_4CF900 ; DATA XREF: sub_4CF810+29o
+ dd offset sub_4CF9D0
+ dd offset sub_4CF9E0
+ dd offset CEncoder_Code
+ dd offset sub_4D0250
+
+.CODE
+
+extrn _operator_new:PROC
+extrn __allshr: PROC
+extrn _free: PROC
+extrn _memcmp: PROC
+extrn _memcpy: PROC
+extrn _memset: PROC
+extrn ___report_gsfailure: PROC
+extrn __purecall: PROC
+VirtualAlloc PROTO STDCALL :DWORD,:DWORD,:DWORD,:DWORD
+VirtualFree PROTO STDCALL :DWORD,:DWORD,:DWORD
+
+; ---------------------------------------------------------------------------
+
+; void __cdecl j__free(void *Memory)
+; 004843B8
+j__free proc near ; CODE XREF: sub_401048+16p
+ ; .text:004010CFp ...
+ jmp _free
+j__free endp
+
+
+; ---------------------------------------------------------------------------
+
+; int __cdecl unknown_libname_324(void *Buf1, void *Buf2)
+unknown_libname_324 proc near
+; sub_48B7BA
+
+Buf1 = dword ptr 4
+Buf2 = dword ptr 8
+
+ push 10h ; Size
+ push [esp+4+Buf2] ; Buf2
+ push [esp+8+Buf1] ; Buf1
+ call _memcmp
+ add esp, 0Ch
+ neg eax
+ sbb eax, eax
+ inc eax
+ retn
+unknown_libname_324 endp
+
+; ---------------------------------------------------------------------------
+
+sub_4A05F7 proc near ; CODE XREF: sub_4A0605+3p
+ push ecx
+ mov dword ptr [ecx], offset off_50CD3C
+ call sub_4A98B8
+ pop ecx
+ retn
+sub_4A05F7 endp
+
+; ---------------------------------------------------------------------------
+
+; int __thiscall sub_4A0605(void *Memory, char)
+sub_4A0605 proc near ; DATA XREF: .rdata:off_50CD3Co
+
+arg_0 = byte ptr 4
+
+ push esi
+ mov esi, ecx
+ call sub_4A05F7
+ test [esp+4+arg_0], 1
+ jz short loc_4A061B
+ push esi ; Memory
+ call j__free
+ pop ecx
+
+loc_4A061B: ; CODE XREF: sub_4A0605+Dj
+ mov eax, esi
+ pop esi
+ retn 4
+sub_4A0605 endp
+
+; ---------------------------------------------------------------------------
+
+sub_4A0686 proc near ; CODE XREF: sub_401C72+49p
+ ; sub_40222F+15Cp ...
+ cmp ecx, dword_544960
+ jnz short loc_4A0690
+ retn
+loc_4A0690: ; CODE XREF: sub_4A0686+6j
+ jmp ___report_gsfailure
+sub_4A0686 endp
+
+; ---------------------------------------------------------------------------
+
+sub_4A98B8 proc near ; CODE XREF: sub_4A05F7+7p
+
+ int 3
+ retn
+sub_4A98B8 endp
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CAEC0 proc near ; CODE XREF: CEncoder_GetOptimum+514p
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+
+ push esi
+ push edi
+ mov edi, [esp+8+arg_4]
+ lea eax, [edi-2]
+ cmp eax, 4
+ mov esi, ecx
+ jb short loc_4CAED5
+ mov eax, 3
+
+loc_4CAED5: ; CODE XREF: sub_4CAEC0+Ej
+ mov edx, [esp+8+arg_0]
+ cmp edx, 80h
+ jnb short loc_4CAEEF
+ shl eax, 7
+ add eax, edx
+ mov ecx, [esi+eax*4+33314h]
+ jmp short loc_4CAF25
+; ---------------------------------------------------------------------------
+
+loc_4CAEEF: ; CODE XREF: sub_4CAEC0+1Fj
+ mov ecx, 7FFFFh
+ sub ecx, edx
+ sar ecx, 1Fh
+ push ebx
+ and ecx, 0Ch
+ add ecx, 6
+ mov ebx, edx
+ shr ebx, cl
+ shl eax, 5
+ add eax, ecx
+ and edx, 0Fh
+ movzx ebx, byte ptr dword_551198[ebx]
+ lea eax, [ebx+eax*2]
+ mov ecx, [esi+eax*4+32F14h]
+ add ecx, [esi+edx*4+33B14h]
+ pop ebx
+
+loc_4CAF25: ; CODE XREF: sub_4CAEC0+2Dj
+ mov edx, [esp+8+arg_8]
+ imul edx, 110h
+ add edx, edi
+ mov eax, [esi+edx*4+295B8h]
+ pop edi
+ add eax, ecx
+ pop esi
+ retn 0Ch
+sub_4CAEC0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CAF40: ; CODE XREF: .text:004DAED5j
+ push ecx
+ push ebx
+ push ebp
+ push esi
+ mov ebp, 2
+ mov bl, 2
+ push edi
+ mov byte ptr dword_551198, 0
+ mov byte ptr dword_551198+1, 1
+ mov [esp+10h], bl
+ mov edi, ebp
+
+loc_4CAF60: ; CODE XREF: .text:004CAF96j
+ mov ecx, edi
+ shr ecx, 1
+ sub ecx, 1
+ mov esi, 1
+ shl esi, cl
+ test esi, esi
+ jbe short loc_4CAF89
+ mov ecx, [esp+10h]
+ push esi
+ lea eax, dword_551198[ebp]
+ push ecx
+ push eax
+ call _memset
+ add esp, 0Ch
+ add ebp, esi
+
+loc_4CAF89: ; CODE XREF: .text:004CAF70j
+ add bl, 1
+ add edi, 1
+ cmp bl, 1Ah
+ mov [esp+10h], bl
+ jb short loc_4CAF60
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ pop ecx
+ retn
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CAFA0 proc near ; CODE XREF: sub_4CAFC0+90p
+
+arg_0 = dword ptr 4
+
+ mov eax, [esp+arg_0]
+ lea ecx, [eax-61h]
+ cmp cx, 19h
+ ja short locret_4CAFB2
+ add eax, 0FFE0h
+
+locret_4CAFB2: ; CODE XREF: sub_4CAFA0+Bj
+ retn
+sub_4CAFA0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+sub_4CAFC0 proc near ; CODE XREF: ICompressSetCoderProperties_SetCoderProperties+A5p
+ movzx ecx, word ptr [eax]
+ lea edx, [ecx-61h]
+ cmp dx, 19h
+ ja short loc_4CAFD2
+ add ecx, 0FFE0h
+
+loc_4CAFD2: ; CODE XREF: sub_4CAFC0+Aj
+ add eax, 2
+ cmp cx, 48h
+ jnz short loc_4CB01B
+ movzx ecx, word ptr [eax]
+ lea edx, [ecx-61h]
+ cmp dx, 19h
+ ja short loc_4CAFED
+ add ecx, 0FFE0h
+
+loc_4CAFED: ; CODE XREF: sub_4CAFC0+25j
+ add eax, 2
+ cmp cx, 43h
+ jz short loc_4CAFF9
+
+loc_4CAFF6: ; CODE XREF: sub_4CAFC0+44j
+ ; sub_4CAFC0+4Bj ...
+ xor eax, eax
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CAFF9: ; CODE XREF: sub_4CAFC0+34j
+ movzx ecx, word ptr [eax]
+ sub ecx, 30h
+ lea edx, [ecx-4]
+ test edx, edx
+ ja short loc_4CAFF6
+ cmp word ptr [eax+2], 0
+ jnz short loc_4CAFF6
+ mov dword ptr [ebx], 0
+ mov [edi], ecx
+ mov eax, 1
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CB01B: ; CODE XREF: sub_4CAFC0+19j
+ cmp cx, 42h
+ jnz short loc_4CAFF6
+ movzx ecx, word ptr [eax]
+ lea edx, [ecx-61h]
+ cmp dx, 19h
+ ja short loc_4CB033
+ add ecx, 0FFE0h
+
+loc_4CB033: ; CODE XREF: sub_4CAFC0+6Bj
+ add eax, 2
+ cmp cx, 54h
+ jnz short loc_4CAFF6
+ push esi
+ movzx esi, word ptr [eax]
+ sub esi, 30h
+ lea ecx, [esi-2]
+ cmp ecx, 2
+ ja short loc_4CB06C
+ movzx eax, word ptr [eax+2]
+ push eax
+ call sub_4CAFA0
+ add esp, 4
+ test ax, ax
+ jnz short loc_4CB06C
+ mov dword ptr [ebx], 1
+ mov [edi], esi
+ mov eax, 1
+ pop esi
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CB06C: ; CODE XREF: sub_4CAFC0+89j
+ ; sub_4CAFC0+9Bj
+ xor eax, eax
+ pop esi
+ retn
+sub_4CAFC0 endp
+
+
+ICompressSetCoderProperties_SetCoderProperties proc near ; DATA XREF: .rdata:00517ADCo
+
+var_4 = dword ptr -4
+pThis = dword ptr 4
+propIDs = dword ptr 8
+properties = dword ptr 0Ch
+numProperties = dword ptr 10h
+
+ push ecx
+ push ebx
+ push ebp
+ xor edx, edx
+ cmp [esp+0Ch+numProperties], edx
+ push esi
+ push edi
+ mov [esp+14h+var_4], edx
+ jbe loc_4CB20D
+ mov esi, [esp+14h+properties]
+ mov ebp, [esp+14h+pThis]
+ lea ecx, [ecx+0]
+
+loc_4CB090: ; CODE XREF: sub_4CB070+197j
+ mov eax, [esp+14h+propIDs]
+ mov eax, [eax+edx*4]
+ add eax, 0FFFFFC00h
+ cmp eax, 90h ; switch 145 cases
+ ja loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ movzx ecx, ds:byte_4CB248[eax]
+ jmp ds:off_4CB218[ecx*4] ; switch jump
+
+loc_4CB0B5: ; DATA XREF: .text:off_4CB218o
+ cmp word ptr [esi], 13h ; jumptable 004CB0AE case 80
+ jnz short loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ mov eax, [esi+8]
+ lea ecx, [eax-5]
+ cmp ecx, 10Ch
+ ja short loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ mov [ebp+32EF0h], eax
+ jmp loc_4CB1F9
+; ---------------------------------------------------------------------------
+
+loc_4CB0D4: ; CODE XREF: sub_4CB070+3Ej
+ ; DATA XREF: .text:off_4CB218o
+ cmp word ptr [esi], 13h ; jumptable 004CB0AE case 82
+ jnz short loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ mov eax, [esi+8]
+ mov [ebp+33B88h], eax
+ jmp loc_4CB1F9
+; ---------------------------------------------------------------------------
+
+loc_4CB0E8: ; CODE XREF: sub_4CB070+3Ej
+ ; DATA XREF: .text:off_4CB218o
+ cmp word ptr [esi], 13h ; jumptable 004CB0AE case 112
+ jnz short loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ cmp dword ptr [esi+8], 0
+ setz cl
+ mov [ebp+32EECh], cl
+ jmp loc_4CB1F9
+; ---------------------------------------------------------------------------
+
+loc_4CB100: ; CODE XREF: sub_4CB070+3Ej
+ ; DATA XREF: .text:off_4CB218o
+ cmp word ptr [esi], 8 ; jumptable 004CB0AE case 81
+ jnz short loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ mov eax, [esi+8]
+ lea edi, [ebp+0C4h]
+ lea ebx, [ebp+0CCh]
+ call sub_4CAFC0
+ test eax, eax
+ jz short loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ mov edx, [esp+14h+var_4]
+ jmp loc_4CB1F9
+; ---------------------------------------------------------------------------
+
+loc_4CB127: ; CODE XREF: sub_4CB070+3Ej
+ ; DATA XREF: .text:off_4CB218o
+ cmp word ptr [esi], 0Bh ; jumptable 004CB0AE case 128
+ jz loc_4CB1F9
+
+loc_4CB131: ; CODE XREF: sub_4CB070+31j
+ ; sub_4CB070+3Ej ...
+ pop edi ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ pop esi
+ pop ebp
+ mov eax, 80070057h
+ pop ebx
+ pop ecx
+ retn 10h
+; ---------------------------------------------------------------------------
+
+loc_4CB13E: ; CODE XREF: sub_4CB070+3Ej
+ ; DATA XREF: .text:off_4CB218o
+ cmp word ptr [esi], 13h ; jumptable 004CB0AE case 129
+ jnz short loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ jmp loc_4CB1F9
+; ---------------------------------------------------------------------------
+
+loc_4CB149: ; CODE XREF: sub_4CB070+3Ej
+ ; DATA XREF: .text:off_4CB218o
+ cmp word ptr [esi], 13h ; jumptable 004CB0AE case 0
+ jnz short loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ mov eax, [esi+8]
+ lea ecx, [eax-1]
+ cmp ecx, 3FFFFFFFh
+ ja short loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ mov [ebp+33B64h], eax
+ xor ecx, ecx
+
+loc_4CB165: ; CODE XREF: sub_4CB070+106j
+ mov edi, 1
+ shl edi, cl
+ cmp eax, edi
+ jbe short loc_4CB178
+ add ecx, 1
+ cmp ecx, 1Eh
+ jb short loc_4CB165
+
+loc_4CB178: ; CODE XREF: sub_4CB070+FEj
+ lea eax, [ecx+ecx]
+ mov [ebp+33B50h], eax
+ jmp short loc_4CB1F9
+; ---------------------------------------------------------------------------
+
+loc_4CB183: ; CODE XREF: sub_4CB070+3Ej
+ ; DATA XREF: .text:off_4CB218o
+ cmp word ptr [esi], 13h ; jumptable 004CB0AE case 64
+ jnz short loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ mov ecx, [esi+8]
+ cmp ecx, 4
+ ja short loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ mov eax, 1
+ shl eax, cl
+ mov [ebp+33B54h], ecx
+ sub eax, 1
+ mov [ebp+33B58h], eax
+ jmp short loc_4CB1F9
+; ---------------------------------------------------------------------------
+
+loc_4CB1A9: ; CODE XREF: sub_4CB070+3Ej
+ ; DATA XREF: .text:off_4CB218o
+ cmp word ptr [esi], 13h ; jumptable 004CB0AE case 66
+ jnz short loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ mov eax, [esi+8]
+ cmp eax, 4
+ ja loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ mov [ebp+33B5Ch], eax
+ jmp short loc_4CB1F9
+; ---------------------------------------------------------------------------
+
+loc_4CB1C3: ; CODE XREF: sub_4CB070+3Ej
+ ; DATA XREF: .text:off_4CB218o
+ cmp word ptr [esi], 13h ; jumptable 004CB0AE case 65
+ jnz loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ mov eax, [esi+8]
+ cmp eax, 8
+ ja loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ mov [ebp+33B60h], eax
+ jmp short loc_4CB1F9
+; ---------------------------------------------------------------------------
+
+loc_4CB1E1: ; CODE XREF: sub_4CB070+3Ej
+ ; DATA XREF: .text:off_4CB218o
+ cmp word ptr [esi], 0Bh ; jumptable 004CB0AE case 144
+ jnz loc_4CB131 ; default
+ ; jumptable 004CB0AE cases 1-63,67-79,83-111,113-127,130-143
+ cmp word ptr [esi+8], 0FFFFh
+ setz cl
+ mov [ebp+33B8Ch], cl
+
+loc_4CB1F9: ; CODE XREF: sub_4CB070+5Fj
+ ; sub_4CB070+73j ...
+ add edx, 1
+ add esi, 10h
+ cmp edx, [esp+14h+numProperties]
+ mov [esp+14h+var_4], edx
+ jb loc_4CB090
+
+loc_4CB20D: ; CODE XREF: sub_4CB070+Fj
+ pop edi
+ pop esi
+ pop ebp
+ xor eax, eax
+ pop ebx
+ pop ecx
+ retn 10h
+
+off_4CB218 dd offset loc_4CB149, offset loc_4CB183, offset loc_4CB1C3
+ dd offset loc_4CB1A9, offset loc_4CB0B5, offset loc_4CB100 ; jump table for switch statement
+ dd offset loc_4CB0D4, offset loc_4CB0E8, offset loc_4CB127
+ dd offset loc_4CB13E, offset loc_4CB1E1, offset loc_4CB131
+
+ICompressSetCoderProperties_SetCoderProperties endp
+
+; =============== S U B R O U T I N E =======================================
+
+sub_4CB2E0 proc near ; CODE XREF: CEncoder_GetOptimum+1199p
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ push ebx
+ push ebp
+ push esi
+ mov esi, [esp+0Ch+arg_4]
+ lea eax, [esi+esi*4]
+ lea edx, [ecx+eax*8]
+ mov [ecx+32F08h], esi
+ mov eax, [edx+100h]
+ mov ebx, [edx+104h]
+ push edi
+
+loc_4CB300: ; CODE XREF: sub_4CB2E0+A6j
+ lea edx, [esi+esi*4]
+ cmp byte ptr [ecx+edx*8+0F1h], 0
+ lea edi, [ecx+edx*8]
+ jz short loc_4CB359
+ lea edx, [eax+eax*4+1Eh]
+ lea edx, [ecx+edx*8]
+ mov dword ptr [edx+14h], 0FFFFFFFFh
+ mov byte ptr [edx+1], 0
+ lea edx, [eax+eax*4]
+ lea edx, [ecx+edx*8]
+ lea ebp, [eax-1]
+ mov [edx+100h], ebp
+ cmp byte ptr [edi+0F2h], 0
+ jz short loc_4CB359
+ mov byte ptr [edx+0C9h], 0
+ mov ebp, [edi+0F4h]
+ mov [edx+0D8h], ebp
+ mov edi, [edi+0F8h]
+ mov [edx+0DCh], edi
+
+loc_4CB359: ; CODE XREF: sub_4CB2E0+2Ej
+ ; sub_4CB2E0+58j
+ lea edx, [eax+eax*4]
+ add edx, edx
+ add edx, edx
+ add edx, edx
+ mov edi, eax
+ test edi, edi
+ mov eax, [edx+ecx+100h]
+ mov ebp, ebx
+ mov ebx, [edx+ecx+104h]
+ mov [edx+ecx+100h], esi
+ mov [edx+ecx+104h], ebp
+ mov esi, edi
+ jnz loc_4CB300
+ mov eax, [ecx+104h]
+ mov edx, [esp+10h+arg_0]
+ pop edi
+ pop esi
+ mov [edx], eax
+ mov eax, [ecx+100h]
+ pop ebp
+ mov [ecx+32F0Ch], eax
+ pop ebx
+ retn 8
+sub_4CB2E0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CB3B0 proc near ; CODE XREF: CEncoder_GetOptimumFast+2Dp
+ ; CEncoder_GetOptimumFast+28Fp ...
+
+arg_0 = dword ptr 4
+
+ push ebx
+ push ebp
+ push esi
+ mov esi, ecx
+ mov ecx, [esi+80h]
+ mov edx, [esi+78h]
+ lea eax, [esi+32660h]
+ push eax
+ push ecx
+ xor ebx, ebx
+ call edx
+ mov ebp, [esp+14h+arg_0]
+ add esp, 8
+ test eax, eax
+ mov [ebp+0], eax
+ jbe short loc_4CB446
+ mov ebx, [esi+eax*4+32658h]
+ cmp ebx, [esi+32EF8h]
+ jnz short loc_4CB446
+ mov eax, [esi+80h]
+ mov ecx, [esi+70h]
+ push edi
+ push eax
+ call ecx
+ mov edx, [esi+80h]
+ mov edi, eax
+ mov eax, [esi+74h]
+ push edx
+ add edi, 1
+ call eax
+ mov ecx, [ebp+0]
+ mov ecx, [esi+ecx*4+3265Ch]
+ add esp, 8
+ sub eax, 1
+ add ecx, 1
+ cmp edi, 111h
+ jbe short loc_4CB425
+ mov edi, 111h
+
+loc_4CB425: ; CODE XREF: sub_4CB3B0+6Ej
+ mov edx, eax
+ sub edx, ecx
+ cmp ebx, edi
+ jnb short loc_4CB445
+ mov ebp, edx
+ lea ecx, [eax+ebx]
+ sub ebp, eax
+
+loc_4CB434: ; CODE XREF: sub_4CB3B0+93j
+ mov dl, [ecx]
+ cmp dl, [ecx+ebp]
+ jnz short loc_4CB445
+ add ebx, 1
+ add ecx, 1
+ cmp ebx, edi
+ jb short loc_4CB434
+
+loc_4CB445: ; CODE XREF: sub_4CB3B0+7Bj
+ ; sub_4CB3B0+89j
+ pop edi
+
+loc_4CB446: ; CODE XREF: sub_4CB3B0+26j
+ ; sub_4CB3B0+35j
+ add dword ptr [esi+32F04h], 1
+ pop esi
+ pop ebp
+ mov eax, ebx
+ pop ebx
+ retn 4
+sub_4CB3B0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+CEncoder_GetOptimumFast proc near ; CODE XREF: CEncoder_CodeOneBlock+1F4p
+
+var_28 = dword ptr -28h
+var_24 = dword ptr -24h
+var_20 = dword ptr -20h
+var_1C = dword ptr -1Ch
+var_18 = dword ptr -18h
+var_14 = dword ptr -14h
+var_10 = dword ptr -10h
+arg_0 = dword ptr 4
+
+ sub esp, 28h
+ push ebx
+ push esi
+ push edi
+ mov edi, ecx
+ mov eax, [edi+80h]
+ mov ecx, [edi+70h]
+ push eax
+ call ecx
+ add esp, 4
+ cmp byte ptr [edi+32F10h], 0
+ mov esi, eax
+ mov [esp+34h+var_24], esi
+ jnz short loc_4CB498
+ lea edx, [esp+34h+var_20]
+ push edx
+ mov ecx, edi
+ call sub_4CB3B0
+ mov ebx, [esp+34h+var_20]
+ jmp short loc_4CB4AF
+; ---------------------------------------------------------------------------
+
+loc_4CB498: ; CODE XREF: CEncoder_GetOptimumFast+24j
+ mov ebx, [edi+32F00h]
+ mov eax, [edi+32EFCh]
+ mov [esp+34h+var_20], ebx
+ mov byte ptr [edi+32F10h], 0
+
+loc_4CB4AF: ; CODE XREF: CEncoder_GetOptimumFast+36j
+ mov ecx, [edi+80h]
+ mov edx, [edi+74h]
+ push ecx
+ mov [esp+38h+var_28], eax
+ call edx
+ add esp, 4
+ sub eax, 1
+ cmp esi, 111h
+ jbe loc_4CB55E
+ mov [esp+34h+var_24], 111h
+
+loc_4CB4D9: ; CODE XREF: CEncoder_GetOptimumFast+101j
+ push ebp
+ xor ebp, ebp
+ lea ecx, [edi+14h]
+ mov [esp+38h+var_18], ebp
+ mov [esp+38h+var_14], ebp
+ mov [esp+38h+var_1C], ecx
+ jmp short loc_4CB4F0
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CB4F0: ; CODE XREF: CEncoder_GetOptimumFast+8Bj
+ ; CEncoder_GetOptimumFast+132j
+ mov edx, [esp+38h+var_1C]
+ mov ecx, eax
+ sub ecx, [edx]
+ mov dl, [eax]
+ sub ecx, 1
+ cmp dl, [ecx]
+ jnz short loc_4CB57F
+ mov dl, [eax+1]
+ cmp dl, [ecx+1]
+ jnz short loc_4CB57F
+ mov esi, 2
+ cmp [esp+38h+var_24], esi
+ jbe short loc_4CB537
+ lea edx, [eax+2]
+ sub ecx, eax
+ lea esp, [esp+0]
+
+loc_4CB520: ; CODE XREF: CEncoder_GetOptimumFast+D1j
+ mov bl, [edx]
+ cmp bl, [ecx+edx]
+ jnz short loc_4CB533
+ add esi, 1
+ add edx, 1
+ cmp esi, [esp+38h+var_24]
+ jb short loc_4CB520
+
+loc_4CB533: ; CODE XREF: CEncoder_GetOptimumFast+C5j
+ mov ebx, [esp+38h+var_20]
+
+loc_4CB537: ; CODE XREF: CEncoder_GetOptimumFast+B2j
+ cmp esi, [edi+32EF8h]
+ jnb short loc_4CB5B9
+ mov edx, [esp+38h+var_14]
+ lea ecx, ds:0[ebp*4]
+ mov [esp+ecx+38h+var_10], esi
+ cmp esi, [esp+edx+38h+var_10]
+ jbe short loc_4CB587
+ mov [esp+38h+var_18], ebp
+ mov [esp+38h+var_14], ecx
+ jmp short loc_4CB587
+; ---------------------------------------------------------------------------
+
+loc_4CB55E: ; CODE XREF: CEncoder_GetOptimumFast+6Bj
+ cmp esi, 2
+ jnb loc_4CB4D9
+ mov eax, [esp+34h+arg_0]
+ pop edi
+ pop esi
+ mov dword ptr [eax], 0FFFFFFFFh
+ mov eax, 1
+ pop ebx
+ add esp, 28h
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_4CB57F: ; CODE XREF: CEncoder_GetOptimumFast+9Fj
+ ; CEncoder_GetOptimumFast+A7j
+ mov [esp+ebp*4+38h+var_10], 0
+
+loc_4CB587: ; CODE XREF: CEncoder_GetOptimumFast+F2j
+ ; CEncoder_GetOptimumFast+FCj
+ add [esp+38h+var_1C], 4
+ add ebp, 1
+ cmp ebp, 4
+ jb loc_4CB4F0
+ mov esi, [esp+38h+var_28]
+ cmp esi, [edi+32EF8h]
+ jb short loc_4CB5EC
+ mov eax, [edi+ebx*4+3265Ch]
+ mov ecx, [esp+38h+arg_0]
+ add eax, 4
+ mov [ecx], eax
+ jmp loc_4CB69A
+; ---------------------------------------------------------------------------
+
+loc_4CB5B9: ; CODE XREF: CEncoder_GetOptimumFast+DDj
+ mov eax, [esp+38h+arg_0]
+ mov [eax], ebp
+ lea eax, [esi-1]
+ test eax, eax
+ jz loc_4CB82E
+ mov ecx, [edi+80h]
+ mov edx, [edi+7Ch]
+ add [edi+32F04h], eax
+ push eax
+ push ecx
+ call edx
+ add esp, 8
+ pop ebp
+ pop edi
+ mov eax, esi
+ pop esi
+ pop ebx
+ add esp, 28h
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_4CB5EC: ; CODE XREF: CEncoder_GetOptimumFast+142j
+ xor ebp, ebp
+ cmp esi, 2
+ mov [esp+38h+var_20], ebp
+ jb short loc_4CB65A
+ cmp ebx, 2
+ mov ecx, [edi+ebx*4+3265Ch]
+ mov [esp+38h+var_20], ecx
+ jbe short loc_4CB63F
+ lea eax, [edi+ebx*4+32654h]
+ mov edi, edi
+
+loc_4CB610: ; CODE XREF: CEncoder_GetOptimumFast+1DDj
+ mov edx, [eax-4]
+ add edx, 1
+ cmp esi, edx
+ jnz short loc_4CB63F
+ mov ecx, [esp+38h+var_20]
+ shr ecx, 7
+ cmp ecx, [eax]
+ jbe short loc_4CB63F
+ mov edx, [eax-4]
+ mov ecx, [eax]
+ sub eax, 8
+ sub ebx, 2
+ cmp ebx, 2
+ mov [esp+38h+var_28], edx
+ mov [esp+38h+var_20], ecx
+ mov esi, edx
+ ja short loc_4CB610
+
+loc_4CB63F: ; CODE XREF: CEncoder_GetOptimumFast+1A5j
+ ; CEncoder_GetOptimumFast+1B8j ...
+ cmp esi, 2
+ jnz short loc_4CB656
+ cmp [esp+38h+var_20], 80h
+ jb short loc_4CB656
+ mov [esp+38h+var_28], 1
+
+loc_4CB656: ; CODE XREF: CEncoder_GetOptimumFast+1E2j
+ ; CEncoder_GetOptimumFast+1ECj
+ mov ebp, [esp+38h+var_20]
+
+loc_4CB65A: ; CODE XREF: CEncoder_GetOptimumFast+195j
+ mov edx, [esp+38h+var_18]
+ mov esi, [esp+edx*4+38h+var_10]
+ cmp esi, 2
+ mov ebx, [esp+38h+var_28]
+ jb short loc_4CB6C7
+ lea eax, [esi+1]
+ cmp eax, ebx
+ jnb short loc_4CB690
+ lea ecx, [esi+2]
+ cmp ecx, ebx
+ jb short loc_4CB681
+ cmp ebp, 200h
+ ja short loc_4CB690
+
+loc_4CB681: ; CODE XREF: CEncoder_GetOptimumFast+217j
+ lea edx, [esi+3]
+ cmp edx, ebx
+ jb short loc_4CB6C7
+ cmp ebp, 8000h
+ jbe short loc_4CB6C7
+
+loc_4CB690: ; CODE XREF: CEncoder_GetOptimumFast+210j
+ ; CEncoder_GetOptimumFast+21Fj
+ mov eax, [esp+38h+arg_0]
+ mov ecx, [esp+38h+var_18]
+ mov [eax], ecx
+
+loc_4CB69A: ; CODE XREF: CEncoder_GetOptimumFast+154j
+ lea eax, [esi-1]
+ test eax, eax
+ jz loc_4CB82E
+ mov edx, [edi+80h]
+ add [edi+32F04h], eax
+ push eax
+ mov eax, [edi+7Ch]
+ push edx
+ call eax
+ add esp, 8
+ pop ebp
+ pop edi
+ mov eax, esi
+ pop esi
+ pop ebx
+ add esp, 28h
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_4CB6C7: ; CODE XREF: CEncoder_GetOptimumFast+209j
+ ; CEncoder_GetOptimumFast+226j ...
+ cmp ebx, 2
+ jb short loc_4CB73E
+ cmp [esp+38h+var_24], 2
+ jbe short loc_4CB73E
+ mov ecx, [edi+80h]
+ mov edx, [edi+70h]
+ push ecx
+ call edx
+ add esp, 4
+ lea esi, [edi+32F00h]
+ push esi
+ mov ecx, edi
+ mov [esp+3Ch+var_24], eax
+ call sub_4CB3B0
+ cmp eax, 2
+ mov [edi+32EFCh], eax
+ jb short loc_4CB757
+ cmp eax, ebx
+ mov ecx, [esi]
+ mov edx, [edi+ecx*4+3265Ch]
+ jb short loc_4CB710
+ cmp edx, ebp
+ jb short loc_4CB737
+
+loc_4CB710: ; CODE XREF: CEncoder_GetOptimumFast+2AAj
+ lea ecx, [ebx+1]
+ cmp eax, ecx
+ jnz short loc_4CB722
+ mov esi, edx
+ shr esi, 7
+ cmp esi, ebp
+ jbe short loc_4CB737
+ cmp eax, ecx
+
+loc_4CB722: ; CODE XREF: CEncoder_GetOptimumFast+2B5j
+ ja short loc_4CB737
+ add eax, 1
+ cmp eax, ebx
+ jb short loc_4CB757
+ cmp ebx, 3
+ jb short loc_4CB757
+ shr ebp, 7
+ cmp ebp, edx
+ jbe short loc_4CB757
+
+loc_4CB737: ; CODE XREF: CEncoder_GetOptimumFast+2AEj
+ ; CEncoder_GetOptimumFast+2BEj ...
+ mov byte ptr [edi+32F10h], 1
+
+loc_4CB73E: ; CODE XREF: CEncoder_GetOptimumFast+26Aj
+ ; CEncoder_GetOptimumFast+271j
+ mov edx, [esp+38h+arg_0]
+ pop ebp
+ pop edi
+ pop esi
+ mov dword ptr [edx], 0FFFFFFFFh
+ mov eax, 1
+ pop ebx
+ add esp, 28h
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_4CB757: ; CODE XREF: CEncoder_GetOptimumFast+29Dj
+ ; CEncoder_GetOptimumFast+2C9j ...
+ mov eax, [edi+80h]
+ mov ecx, [edi+74h]
+ push eax
+ call ecx
+ lea ecx, [edi+14h]
+ add esp, 4
+ sub eax, 1
+ mov [esp+38h+var_18], 0
+ mov ebx, ecx
+
+loc_4CB776: ; CODE XREF: CEncoder_GetOptimumFast+39Aj
+ mov dl, [eax+1]
+ mov ecx, eax
+ sub ecx, [ebx]
+ sub ecx, 1
+ cmp dl, [ecx+1]
+ jnz short loc_4CB7DD
+ mov dl, [eax+2]
+ cmp dl, [ecx+2]
+ lea ebp, [eax+2]
+ jnz short loc_4CB7DD
+ mov esi, 2
+ cmp [esp+38h+var_24], esi
+ jbe short loc_4CB7B4
+ mov edx, ebp
+ mov ebp, ecx
+ sub ebp, eax
+
+loc_4CB7A1: ; CODE XREF: CEncoder_GetOptimumFast+352j
+ mov cl, [edx]
+ cmp cl, [edx+ebp]
+ jnz short loc_4CB7B4
+ add esi, 1
+ add edx, 1
+ cmp esi, [esp+38h+var_24]
+ jb short loc_4CB7A1
+
+loc_4CB7B4: ; CODE XREF: CEncoder_GetOptimumFast+339j
+ ; CEncoder_GetOptimumFast+346j
+ add esi, 1
+ cmp esi, [esp+38h+var_28]
+ jb short loc_4CB7E9
+ mov eax, [esp+38h+arg_0]
+ pop ebp
+ mov byte ptr [edi+32F10h], 1
+ pop edi
+ pop esi
+ mov dword ptr [eax], 0FFFFFFFFh
+ mov eax, 1
+ pop ebx
+ add esp, 28h
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_4CB7DD: ; CODE XREF: CEncoder_GetOptimumFast+323j
+ ; CEncoder_GetOptimumFast+32Ej
+ mov edx, [esp+38h+var_18]
+ mov [esp+edx*4+38h+var_10], 0
+
+loc_4CB7E9: ; CODE XREF: CEncoder_GetOptimumFast+35Bj
+ mov ecx, [esp+38h+var_18]
+ add ecx, 1
+ add ebx, 4
+ cmp ecx, 4
+ mov [esp+38h+var_18], ecx
+ jb loc_4CB776
+ mov esi, [esp+38h+var_28]
+ mov ecx, [esp+38h+var_20]
+ mov edx, [esp+38h+arg_0]
+ add ecx, 4
+ lea eax, [esi-2]
+ test eax, eax
+ mov [edx], ecx
+ jz short loc_4CB82E
+ add [edi+32F04h], eax
+ mov ecx, [edi+7Ch]
+ push eax
+ mov eax, [edi+80h]
+ push eax
+ call ecx
+ add esp, 8
+
+loc_4CB82E: ; CODE XREF: CEncoder_GetOptimumFast+164j
+ ; CEncoder_GetOptimumFast+23Fj ...
+ pop ebp
+ pop edi
+ mov eax, esi
+ pop esi
+ pop ebx
+ add esp, 28h
+ retn 4
+CEncoder_GetOptimumFast endp
+
+; =============== S U B R O U T I N E =======================================
+
+sub_4CB8A0 proc near ; CODE XREF: sub_4CD940+37p
+
+arg_0 = dword ptr 4
+
+ push edi
+ mov edi, [esp+4+arg_0]
+ test edi, edi
+ jz short loc_4CB8EB
+ mov eax, dword_553598
+ test eax, eax
+ jnz short loc_4CB8DD
+ push 0Ch ; Size
+ call _operator_new ; operator new(uint)
+ add esp, 4
+ test eax, eax
+ jz short loc_4CB8D6
+ mov dword ptr [eax], 0
+ mov dword ptr [eax+4], 0
+ mov dword ptr [eax+8], 0
+ jmp short loc_4CB8D8
+; ---------------------------------------------------------------------------
+
+loc_4CB8D6: ; CODE XREF: sub_4CB8A0+1Ej
+ xor eax, eax
+
+loc_4CB8D8: ; CODE XREF: sub_4CB8A0+34j
+ mov dword_553598, eax
+
+loc_4CB8DD: ; CODE XREF: sub_4CB8A0+10j
+ mov eax, [eax]
+ test eax, eax
+ jz short loc_4CB8EB
+ push edi
+ call eax
+ add esp, 4
+ pop edi
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CB8EB: ; CODE XREF: sub_4CB8A0+7j
+ ; sub_4CB8A0+41j
+ xor eax, eax
+ pop edi
+ retn
+sub_4CB8A0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CB8F0 proc near ; CODE XREF: sub_4CBA60+85p
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+
+ push esi
+ mov esi, [esp+4+arg_0]
+ push edi
+ mov edi, [esi+44h]
+ add edi, [esi+40h]
+ add edi, [esp+8+arg_4]
+ cmp dword ptr [esi+4Ch], 0
+ jz short loc_4CB911
+ mov [esi+3Ch], edi
+ pop edi
+ mov eax, 1
+ pop esi
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CB911: ; CODE XREF: sub_4CB8F0+14j
+ mov eax, [esi+30h]
+ test eax, eax
+ jz short loc_4CB91D
+ cmp [esi+3Ch], edi
+ jz short loc_4CB93E
+
+loc_4CB91D: ; CODE XREF: sub_4CB8F0+26j
+ push ebx
+ mov ebx, [esp+0Ch+arg_8]
+ push eax
+ mov eax, [ebx+4]
+ call eax
+ mov dword ptr [esi+30h], 0
+ mov [esi+3Ch], edi
+ mov ecx, [ebx]
+ push edi
+ call ecx
+ add esp, 8
+ mov [esi+30h], eax
+ pop ebx
+
+loc_4CB93E: ; CODE XREF: sub_4CB8F0+2Bj
+ xor eax, eax
+ cmp [esi+30h], eax
+ pop edi
+ setnz al
+ pop esi
+ retn
+sub_4CB8F0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CB950: ; DATA XREF: sub_4CCAA0+1Co
+ mov eax, [esp+4]
+ mov eax, [eax]
+ retn
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CB960: ; DATA XREF: sub_4CCAA0+Eo
+ mov eax, [esp+4]
+ mov ecx, [eax]
+ mov edx, [esp+8]
+ mov al, [edx+ecx]
+ retn
+; ---------------------------------------------------------------------------
+ align 10h
+loc_4CB970: ; DATA XREF: sub_4CCAA0+15o
+ mov ecx, [esp+4]
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: library function
+
+; public: int __thiscall CRect::Height(void)const
+?Height@CRect@@QBEHXZ proc near
+ mov eax, [ecx+0Ch]
+ sub eax, [ecx+4]
+ retn
+?Height@CRect@@QBEHXZ endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CB980 proc near ; CODE XREF: sub_4CBC80+46p
+ ; sub_4CBD50+61p
+
+arg_0 = dword ptr 4
+
+ push esi
+ mov esi, [esp+4+arg_0]
+ cmp dword ptr [esi+38h], 0
+ jnz short loc_4CB9F0
+ cmp dword ptr [esi+68h], 0
+ jnz short loc_4CB9F0
+ mov eax, [esi]
+ sub eax, [esi+4]
+ mov ecx, [esi+30h]
+ add eax, [esi+0Ch]
+ sub ecx, eax
+ add ecx, [esi+3Ch]
+ jz short loc_4CB9F0
+ push edi
+
+loc_4CB9A4: ; CODE XREF: sub_4CB980+63j
+ mov edx, [esi+34h]
+ lea edi, [esp+8+arg_0]
+ push edi
+ push ecx
+ push eax
+ mov eax, [edx]
+ push edx
+ call eax
+ add esp, 10h
+ test eax, eax
+ mov [esi+68h], eax
+ jnz short loc_4CB9EF
+ mov eax, [esp+8+arg_0]
+ test eax, eax
+ jz short loc_4CB9E8
+ add [esi+0Ch], eax
+ mov eax, [esi+0Ch]
+ sub eax, [esi+4]
+ cmp eax, [esi+44h]
+ ja short loc_4CB9EF
+ mov eax, [esi]
+ sub eax, [esi+4]
+ mov ecx, [esi+30h]
+ add eax, [esi+0Ch]
+ sub ecx, eax
+ add ecx, [esi+3Ch]
+ jnz short loc_4CB9A4
+ pop edi
+ pop esi
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CB9E8: ; CODE XREF: sub_4CB980+43j
+ mov dword ptr [esi+38h], 1
+
+loc_4CB9EF: ; CODE XREF: sub_4CB980+3Bj
+ ; sub_4CB980+51j
+ pop edi
+
+loc_4CB9F0: ; CODE XREF: sub_4CB980+9j
+ ; sub_4CB980+Fj ...
+ pop esi
+ retn
+sub_4CB980 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CBA00 proc near ; CODE XREF: sub_4CBD50+58p
+
+arg_0 = dword ptr 4
+
+ push ebx
+ push ebp
+ push esi
+ push edi
+ mov edi, [esp+10h+arg_0]
+ mov esi, [edi+0Ch]
+ mov eax, [edi+40h]
+ sub esi, [edi+4]
+ mov ebx, [edi]
+ mov ebp, [edi+30h]
+ add esi, eax
+ sub ebx, eax
+ mov eax, dword_553598
+ test eax, eax
+ jnz short loc_4CBA44
+ push 0Ch ; Size
+ call _operator_new ; operator new(uint)
+ xor ecx, ecx
+ add esp, 4
+ cmp eax, ecx
+ jz short loc_4CBA3D
+ mov [eax], ecx
+ mov [eax+4], ecx
+ mov [eax+8], ecx
+ jmp short loc_4CBA3F
+; ---------------------------------------------------------------------------
+
+loc_4CBA3D: ; CODE XREF: sub_4CBA00+31j
+ xor eax, eax
+
+loc_4CBA3F: ; CODE XREF: sub_4CBA00+3Bj
+ mov dword_553598, eax
+
+loc_4CBA44: ; CODE XREF: sub_4CBA00+21j
+ mov eax, [eax+8]
+ test eax, eax
+ jz short loc_4CBA53
+ push esi
+ push ebx
+ push ebp
+ call eax
+ add esp, 0Ch
+
+loc_4CBA53: ; CODE XREF: sub_4CBA00+49j
+ mov eax, [edi+30h]
+ add eax, [edi+40h]
+ mov [edi], eax
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ retn
+sub_4CBA00 endp
+
+; =============== S U B R O U T I N E =======================================
+
+sub_4CBA60 proc near ; CODE XREF: sub_4D0270+D2p
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+arg_C = dword ptr 10h
+arg_10 = dword ptr 14h
+arg_14 = dword ptr 18h
+
+ push ebx
+ push esi
+ push edi
+ mov edi, [esp+0Ch+arg_4]
+ cmp edi, 0C0000000h
+ jbe short loc_4CBAA2
+ mov esi, [esp+0Ch+arg_0]
+ mov eax, [esi+20h]
+ mov edi, [esp+0Ch+arg_14]
+ mov ecx, [edi+4]
+ push eax
+ call ecx
+ xor ebx, ebx
+ add esp, 4
+ cmp [esi+4Ch], ebx
+ mov [esi+20h], ebx
+ jnz short loc_4CBA9C
+ mov edx, [esi+30h]
+ mov eax, [edi+4]
+ push edx
+ call eax
+ add esp, 4
+ mov [esi+30h], ebx
+
+loc_4CBA9C: ; CODE XREF: sub_4CBA60+2Bj
+ pop edi
+ pop esi
+ xor eax, eax
+ pop ebx
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CBAA2: ; CODE XREF: sub_4CBA60+Dj
+ mov eax, edi
+ shr eax, 1
+ cmp edi, 80000000h
+ jbe short loc_4CBAB3
+ mov eax, edi
+ shr eax, 2
+
+loc_4CBAB3: ; CODE XREF: sub_4CBA60+4Cj
+ mov ecx, [esp+0Ch+arg_8]
+ mov esi, [esp+0Ch+arg_0]
+ mov ebx, [esp+0Ch+arg_C]
+ lea edx, [edi+ecx+1]
+ push ebp
+ mov [esi+40h], edx
+ mov edx, [esp+10h+arg_10]
+ add ecx, ebx
+ lea ebp, [ebx+edx]
+ add ecx, edx
+ mov [esi+44h], ebp
+ mov ebp, [esp+10h+arg_14]
+ shr ecx, 1
+ push ebp
+ lea eax, [ecx+eax+80000h]
+ push eax
+ push esi
+ call sub_4CB8F0
+ add esp, 0Ch
+ test eax, eax
+ jz loc_4CBBEA
+ mov edx, [esi+48h]
+ mov [esi+1Ch], ebx
+ xor ebx, ebx
+ cmp edx, 2
+ lea ebp, [edi+1]
+ mov [esi+5Ch], ebx
+ jnz short loc_4CBB0F
+ mov eax, 0FFFFh
+ jmp short loc_4CBB49
+; ---------------------------------------------------------------------------
+
+loc_4CBB0F: ; CODE XREF: sub_4CBA60+A6j
+ lea ecx, [edi-1]
+ mov eax, ecx
+ shr eax, 1
+ or ecx, eax
+ mov eax, ecx
+ shr eax, 2
+ or ecx, eax
+ mov eax, ecx
+ shr eax, 4
+ or ecx, eax
+ mov eax, ecx
+ or eax, 1FFFE00h
+ shr eax, 8
+ or eax, ecx
+ shr eax, 1
+ cmp eax, 1000000h
+ jbe short loc_4CBB49
+ cmp edx, 3
+ jnz short loc_4CBB47
+ mov eax, 0FFFFFFh
+ jmp short loc_4CBB49
+; ---------------------------------------------------------------------------
+
+loc_4CBB47: ; CODE XREF: sub_4CBA60+DEj
+ shr eax, 1
+
+loc_4CBB49: ; CODE XREF: sub_4CBA60+ADj
+ ; sub_4CBA60+D9j ...
+ mov [esi+28h], eax
+ add eax, 1
+ cmp edx, 2
+ jbe short loc_4CBB5B
+ mov dword ptr [esi+5Ch], 400h
+
+loc_4CBB5B: ; CODE XREF: sub_4CBA60+F2j
+ cmp edx, 3
+ jbe short loc_4CBB67
+ add dword ptr [esi+5Ch], 10000h
+
+loc_4CBB67: ; CODE XREF: sub_4CBA60+FEj
+ cmp edx, 4
+ jbe short loc_4CBB73
+ add dword ptr [esi+5Ch], 100000h
+
+loc_4CBB73: ; CODE XREF: sub_4CBA60+10Aj
+ mov ecx, [esi+60h]
+ mov edx, [esi+5Ch]
+ add ecx, [esi+64h]
+ add eax, edx
+ cmp [esi+50h], ebx
+ mov [esi+58h], edi
+ mov [esi+60h], eax
+ mov [esi+18h], ebp
+ lea edx, [ebp+ebp+0]
+ jnz short loc_4CBB92
+ mov edx, ebp
+
+loc_4CBB92: ; CODE XREF: sub_4CBA60+12Ej
+ lea edi, [eax+edx]
+ mov eax, [esi+20h]
+ cmp eax, ebx
+ mov [esi+64h], edx
+ jz short loc_4CBBA3
+ cmp ecx, edi
+ jz short loc_4CBBE0
+
+loc_4CBBA3: ; CODE XREF: sub_4CBA60+13Dj
+ mov ebp, [esp+10h+arg_14]
+ push eax
+ mov eax, [ebp+4]
+ call eax
+ lea eax, ds:0[edi*4]
+ mov ecx, eax
+ shr ecx, 2
+ add esp, 4
+ cmp ecx, edi
+ mov [esi+20h], ebx
+ jz short loc_4CBBC7
+ xor eax, eax
+ jmp short loc_4CBBD0
+; ---------------------------------------------------------------------------
+
+loc_4CBBC7: ; CODE XREF: sub_4CBA60+161j
+ mov edx, [ebp+0]
+ push eax
+ call edx
+ add esp, 4
+
+loc_4CBBD0: ; CODE XREF: sub_4CBA60+165j
+ cmp eax, ebx
+ mov [esi+20h], eax
+ jz short loc_4CBBEC
+ mov ecx, [esi+60h]
+ lea edx, [eax+ecx*4]
+ mov [esi+24h], edx
+
+loc_4CBBE0: ; CODE XREF: sub_4CBA60+141j
+ pop ebp
+ pop edi
+ pop esi
+ mov eax, 1
+ pop ebx
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CBBEA: ; CODE XREF: sub_4CBA60+8Fj
+ xor ebx, ebx
+
+loc_4CBBEC: ; CODE XREF: sub_4CBA60+175j
+ mov eax, [esi+20h]
+ mov ecx, [ebp+4]
+ push eax
+ call ecx
+ add esp, 4
+ cmp [esi+4Ch], ebx
+ mov [esi+20h], ebx
+ jnz short loc_4CBC0F
+ mov edx, [esi+30h]
+ mov eax, [ebp+4]
+ push edx
+ call eax
+ add esp, 4
+ mov [esi+30h], ebx
+
+loc_4CBC0F: ; CODE XREF: sub_4CBA60+19Ej
+ pop ebp
+ pop edi
+ pop esi
+ xor eax, eax
+ pop ebx
+ retn
+sub_4CBA60 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CBC20 proc near ; CODE XREF: sub_4CBD50+79p
+
+arg_0 = dword ptr 4
+
+ mov eax, [esp+arg_0]
+ mov edx, [eax+18h]
+ sub edx, [eax+14h]
+ push ebx
+ mov ebx, [eax+4]
+ or ecx, 0FFFFFFFFh
+ sub ecx, ebx
+ cmp edx, ecx
+ push esi
+ jnb short loc_4CBC3A
+ mov ecx, edx
+
+loc_4CBC3A: ; CODE XREF: sub_4CBC20+16j
+ mov esi, [eax+0Ch]
+ sub esi, ebx
+ push edi
+ mov edi, [eax+44h]
+ mov edx, esi
+ cmp edx, edi
+ ja short loc_4CBC54
+ test edx, edx
+ jbe short loc_4CBC56
+ mov edx, 1
+ jmp short loc_4CBC56
+; ---------------------------------------------------------------------------
+
+loc_4CBC54: ; CODE XREF: sub_4CBC20+27j
+ sub edx, edi
+
+loc_4CBC56: ; CODE XREF: sub_4CBC20+2Bj
+ ; sub_4CBC20+32j
+ cmp edx, ecx
+ pop edi
+ jnb short loc_4CBC5D
+ mov ecx, edx
+
+loc_4CBC5D: ; CODE XREF: sub_4CBC20+39j
+ mov edx, [eax+1Ch]
+ cmp esi, edx
+ jbe short loc_4CBC66
+ mov esi, edx
+
+loc_4CBC66: ; CODE XREF: sub_4CBC20+42j
+ add ebx, ecx
+ mov [eax+10h], esi
+ pop esi
+ mov [eax+8], ebx
+ pop ebx
+ retn
+sub_4CBC20 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CBC80 proc near ; DATA XREF: sub_4CCAA0+8o
+
+arg_0 = dword ptr 4
+
+ push ebx
+ push esi
+ mov esi, [esp+8+arg_0]
+ xor eax, eax
+ cmp [esi+60h], eax
+ jbe short loc_4CBCA2
+ lea ecx, [ecx+0]
+
+loc_4CBC90: ; CODE XREF: sub_4CBC80+20j
+ mov ecx, [esi+20h]
+ mov dword ptr [ecx+eax*4], 0
+ add eax, 1
+ cmp eax, [esi+60h]
+ jb short loc_4CBC90
+
+loc_4CBCA2: ; CODE XREF: sub_4CBC80+Bj
+ mov eax, [esi+18h]
+ mov edx, [esi+30h]
+ push esi
+ mov dword ptr [esi+14h], 0
+ mov [esi], edx
+ mov [esi+0Ch], eax
+ mov [esi+4], eax
+ mov dword ptr [esi+68h], 0
+ mov dword ptr [esi+38h], 0
+ call sub_4CB980
+ mov eax, [esi+18h]
+ mov ebx, [esi+4]
+ sub eax, [esi+14h]
+ or ecx, 0FFFFFFFFh
+ sub ecx, ebx
+ add esp, 4
+ cmp eax, ecx
+ jnb short loc_4CBCE2
+ mov ecx, eax
+
+loc_4CBCE2: ; CODE XREF: sub_4CBC80+5Ej
+ mov edx, [esi+0Ch]
+ sub edx, ebx
+ push edi
+ mov edi, [esi+44h]
+ mov eax, edx
+ cmp eax, edi
+ ja short loc_4CBCFC
+ test eax, eax
+ jbe short loc_4CBCFE
+ mov eax, 1
+ jmp short loc_4CBCFE
+; ---------------------------------------------------------------------------
+
+loc_4CBCFC: ; CODE XREF: sub_4CBC80+6Fj
+ sub eax, edi
+
+loc_4CBCFE: ; CODE XREF: sub_4CBC80+73j
+ ; sub_4CBC80+7Aj
+ cmp eax, ecx
+ pop edi
+ jnb short loc_4CBD05
+ mov ecx, eax
+
+loc_4CBD05: ; CODE XREF: sub_4CBC80+81j
+ mov eax, edx
+ mov edx, [esi+1Ch]
+ cmp eax, edx
+ jbe short loc_4CBD10
+ mov eax, edx
+
+loc_4CBD10: ; CODE XREF: sub_4CBC80+8Cj
+ add ebx, ecx
+ mov [esi+8], ebx
+ mov [esi+10h], eax
+ pop esi
+ pop ebx
+ retn
+sub_4CBC80 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CBD20 proc near ; CODE XREF: sub_4CBD50+26p
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+
+ push edi
+ mov edi, [esp+4+arg_8]
+ xor eax, eax
+ test edi, edi
+ jbe short loc_4CBD4C
+ mov edx, [esp+4+arg_4]
+ push esi
+ mov esi, [esp+8+arg_0]
+
+loc_4CBD34: ; CODE XREF: sub_4CBD20+29j
+ mov ecx, [edx+eax*4]
+ cmp ecx, esi
+ ja short loc_4CBD3F
+ xor ecx, ecx
+ jmp short loc_4CBD41
+; ---------------------------------------------------------------------------
+
+loc_4CBD3F: ; CODE XREF: sub_4CBD20+19j
+ sub ecx, esi
+
+loc_4CBD41: ; CODE XREF: sub_4CBD20+1Dj
+ mov [edx+eax*4], ecx
+ add eax, 1
+ cmp eax, edi
+ jb short loc_4CBD34
+ pop esi
+
+loc_4CBD4C: ; CODE XREF: sub_4CBD20+9j
+ pop edi
+ retn
+sub_4CBD20 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+sub_4CBD50 proc near ; CODE XREF: .text:004CC1A1p
+ ; .text:004CC20Ap ...
+
+arg_0 = dword ptr 4
+
+ push esi
+ mov esi, [esp+4+arg_0]
+ cmp dword ptr [esi+4], 0FFFFFFFFh
+ jnz short loc_4CBD88
+ mov eax, [esi+64h]
+ add eax, [esi+60h]
+ mov ecx, [esi+20h]
+ push edi
+ mov edi, 0FFFFFFFEh
+ sub edi, [esi+58h]
+ push eax
+ push ecx
+ and edi, 0FFFFFC00h
+ push edi
+ call sub_4CBD20
+ sub [esi+8], edi
+ sub [esi+4], edi
+ add esp, 0Ch
+ sub [esi+0Ch], edi
+ pop edi
+
+loc_4CBD88: ; CODE XREF: sub_4CBD50+9j
+ cmp dword ptr [esi+38h], 0
+ jnz short loc_4CBDB9
+ mov edx, [esi+0Ch]
+ sub edx, [esi+4]
+ mov eax, [esi+44h]
+ cmp eax, edx
+ jnz short loc_4CBDB9
+ mov ecx, [esi+3Ch]
+ add ecx, [esi+30h]
+ sub ecx, [esi]
+ cmp ecx, eax
+ ja short loc_4CBDB0
+ push esi
+ call sub_4CBA00
+ add esp, 4
+
+loc_4CBDB0: ; CODE XREF: sub_4CBD50+55j
+ push esi
+ call sub_4CB980
+ add esp, 4
+
+loc_4CBDB9: ; CODE XREF: sub_4CBD50+3Cj
+ ; sub_4CBD50+49j
+ mov edx, [esi+14h]
+ cmp edx, [esi+18h]
+ jnz short loc_4CBDC8
+ mov dword ptr [esi+14h], 0
+
+loc_4CBDC8: ; CODE XREF: sub_4CBD50+6Fj
+ push esi
+ call sub_4CBC20
+ add esp, 4
+ pop esi
+ retn
+sub_4CBD50 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CBDE0 proc near ; CODE XREF: sub_4CC5C0+1B7p
+
+var_4 = dword ptr -4
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+arg_C = dword ptr 10h
+arg_10 = dword ptr 14h
+arg_14 = dword ptr 18h
+arg_18 = dword ptr 1Ch
+arg_1C = dword ptr 20h
+arg_20 = dword ptr 24h
+arg_24 = dword ptr 28h
+
+ push ecx
+ mov edx, [esp+4+arg_4]
+ mov ecx, [esp+4+arg_10]
+ mov eax, [esp+4+arg_14]
+ push ebx
+ mov [ecx+eax*4], edx
+ mov ecx, [esp+8+arg_8]
+ push ebp
+ push esi
+ sub ecx, edx
+ cmp [esp+10h+arg_1C], 0
+ push edi
+ jz loc_4CBEAC
+ mov ebp, [esp+14h+arg_C]
+ mov ebx, [esp+14h+arg_24]
+ jmp short loc_4CBE14
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CBE10: ; CODE XREF: sub_4CBDE0+C6j
+ mov eax, [esp+14h+arg_14]
+
+loc_4CBE14: ; CODE XREF: sub_4CBDE0+2Dj
+ mov esi, [esp+14h+arg_18]
+ sub [esp+14h+arg_1C], 1
+ cmp ecx, esi
+ jnb loc_4CBEAC
+ mov edx, ebp
+ sub edx, ecx
+ cmp eax, ecx
+ sbb edi, edi
+ and edi, esi
+ sub edi, ecx
+ add edi, eax
+ mov eax, [esp+14h+arg_10]
+ mov eax, [eax+edi*4]
+ mov [esp+14h+arg_4], eax
+ mov al, [edx+ebx]
+ cmp al, [ebx+ebp]
+ jnz short loc_4CBE99
+ mov al, [edx]
+ cmp al, [ebp+0]
+ jnz short loc_4CBE99
+ mov eax, [esp+14h+arg_0]
+ mov esi, 1
+ cmp eax, esi
+ jz short loc_4CBE7A
+ sub edx, ebp
+ lea edi, [ebp+1]
+ mov [esp+14h+var_4], edx
+ jmp short loc_4CBE69
+; ---------------------------------------------------------------------------
+
+loc_4CBE65: ; CODE XREF: sub_4CBDE0+98j
+ mov edx, [esp+14h+var_4]
+
+loc_4CBE69: ; CODE XREF: sub_4CBDE0+83j
+ mov dl, [edx+edi]
+ cmp dl, [edi]
+ jnz short loc_4CBE7A
+ add esi, 1
+ add edi, 1
+ cmp esi, eax
+ jnz short loc_4CBE65
+
+loc_4CBE7A: ; CODE XREF: sub_4CBDE0+78j
+ ; sub_4CBDE0+8Ej
+ cmp ebx, esi
+ jnb short loc_4CBE99
+ mov edx, [esp+14h+arg_20]
+ mov [edx], esi
+ add edx, 4
+ add ecx, 0FFFFFFFFh
+ mov [edx], ecx
+ add edx, 4
+ cmp esi, eax
+ mov ebx, esi
+ mov [esp+14h+arg_20], edx
+ jz short loc_4CBEB6
+
+loc_4CBE99: ; CODE XREF: sub_4CBDE0+64j
+ ; sub_4CBDE0+6Bj ...
+ mov ecx, [esp+14h+arg_8]
+ sub ecx, [esp+14h+arg_4]
+ cmp [esp+14h+arg_1C], 0
+ jnz loc_4CBE10
+
+loc_4CBEAC: ; CODE XREF: sub_4CBDE0+1Fj
+ ; sub_4CBDE0+3Fj
+ mov eax, [esp+14h+arg_20]
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ pop ecx
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CBEB6: ; CODE XREF: sub_4CBDE0+B7j
+ pop edi
+ pop esi
+ pop ebp
+ mov eax, edx
+ pop ebx
+ pop ecx
+ retn
+sub_4CBDE0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CBEC0 proc near ; CODE XREF: .text:004CC1E7p
+ ; sub_4CC220+14Ep ...
+
+var_10 = dword ptr -10h
+var_C = dword ptr -0Ch
+var_8 = dword ptr -8
+var_4 = dword ptr -4
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+arg_C = dword ptr 10h
+arg_10 = dword ptr 14h
+arg_14 = dword ptr 18h
+arg_18 = dword ptr 1Ch
+arg_1C = dword ptr 20h
+arg_20 = dword ptr 24h
+arg_24 = dword ptr 28h
+
+ sub esp, 10h
+ mov eax, [esp+10h+arg_10]
+ mov edx, [esp+10h+arg_8]
+ sub edx, [esp+10h+arg_4]
+ push ebx
+ push ebp
+ push esi
+ push edi
+ mov edi, [esp+20h+arg_14]
+ lea eax, [eax+edi*8]
+ lea ecx, [eax+4]
+ mov [esp+20h+var_C], ecx
+ xor ecx, ecx
+ xor ebx, ebx
+ cmp [esp+20h+arg_1C], ecx
+ mov ebp, eax
+ mov [esp+20h+var_10], ebp
+ mov [esp+20h+var_8], ecx
+ mov [esp+20h+var_4], ebx
+ jnz short loc_4CBF24
+
+loc_4CBEF9: ; CODE XREF: sub_4CBEC0+6Fj
+ ; sub_4CBEC0+151j
+ mov edx, [esp+20h+var_C]
+ mov eax, [esp+20h+arg_20]
+ pop edi
+ pop esi
+ mov dword ptr [ebp+0], 0
+ pop ebp
+ mov dword ptr [edx], 0
+ pop ebx
+ add esp, 10h
+ retn
+; ---------------------------------------------------------------------------
+ jmp short loc_4CBF20
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CBF20: ; CODE XREF: sub_4CBEC0+56j
+ ; sub_4CBEC0+14Bj
+ mov edi, [esp+20h+arg_14]
+
+loc_4CBF24: ; CODE XREF: sub_4CBEC0+37j
+ mov eax, [esp+20h+arg_18]
+ sub [esp+20h+arg_1C], 1
+ cmp edx, eax
+ jnb short loc_4CBEF9
+ cmp edi, edx
+ sbb esi, esi
+ and esi, eax
+ mov eax, [esp+20h+arg_10]
+ sub esi, edx
+ add esi, edi
+ lea eax, [eax+esi*8]
+ mov esi, [esp+20h+arg_C]
+ sub esi, edx
+ cmp ecx, ebx
+ jb short loc_4CBF4E
+ mov ecx, ebx
+
+loc_4CBF4E: ; CODE XREF: sub_4CBEC0+8Aj
+ mov bl, [ecx+esi]
+ mov edi, [esp+20h+arg_C]
+ cmp bl, [ecx+edi]
+ jnz short loc_4CBFB8
+ add ecx, 1
+ cmp ecx, [esp+20h+arg_0]
+ jz short loc_4CBF93
+ mov bl, [ecx+esi]
+ cmp bl, [ecx+edi]
+ jnz short loc_4CBF93
+ add ecx, 1
+ cmp ecx, [esp+20h+arg_0]
+ jz short loc_4CBF93
+ mov ebx, edi
+ mov ebp, esi
+ lea edi, [ecx+ebx]
+ sub ebp, ebx
+ lea ecx, [ecx+0]
+
+loc_4CBF80: ; CODE XREF: sub_4CBEC0+D1j
+ mov bl, [edi+ebp]
+ cmp bl, [edi]
+ jnz short loc_4CBF93
+ add ecx, 1
+ add edi, 1
+ cmp ecx, [esp+20h+arg_0]
+ jnz short loc_4CBF80
+
+loc_4CBF93: ; CODE XREF: sub_4CBEC0+A1j
+ ; sub_4CBEC0+A9j ...
+ cmp [esp+20h+arg_24], ecx
+ jnb short loc_4CBFB8
+ mov edi, [esp+20h+arg_20]
+ mov [edi], ecx
+ add edi, 4
+ add edx, 0FFFFFFFFh
+ mov [edi], edx
+ add edi, 4
+ cmp ecx, [esp+20h+arg_0]
+ mov [esp+20h+arg_24], ecx
+ mov [esp+20h+arg_20], edi
+ jz short loc_4CC016
+
+loc_4CBFB8: ; CODE XREF: sub_4CBEC0+98j
+ ; sub_4CBEC0+D7j
+ mov dl, [ecx+esi]
+ mov esi, [esp+20h+arg_C]
+ cmp dl, [ecx+esi]
+ mov edx, [esp+20h+arg_4]
+ jnb short loc_4CBFE4
+ mov esi, [esp+20h+var_10]
+ lea ebp, [eax+4]
+ mov ebx, ecx
+ mov ecx, [esp+20h+var_8]
+ mov [esi], edx
+ mov eax, [ebp+0]
+ mov [esp+20h+var_10], ebp
+ mov [esp+20h+var_4], ebx
+ jmp short loc_4CBFFC
+; ---------------------------------------------------------------------------
+
+loc_4CBFE4: ; CODE XREF: sub_4CBEC0+106j
+ mov esi, [esp+20h+var_C]
+ mov ebp, [esp+20h+var_10]
+ mov ebx, [esp+20h+var_4]
+ mov [esi], edx
+ mov [esp+20h+var_C], eax
+ mov eax, [eax]
+ mov [esp+20h+var_8], ecx
+
+loc_4CBFFC: ; CODE XREF: sub_4CBEC0+122j
+ mov edx, [esp+20h+arg_8]
+ sub edx, eax
+ cmp [esp+20h+arg_1C], 0
+ mov [esp+20h+arg_4], eax
+ jnz loc_4CBF20
+ jmp loc_4CBEF9
+; ---------------------------------------------------------------------------
+
+loc_4CC016: ; CODE XREF: sub_4CBEC0+F6j
+ mov ecx, [eax]
+ mov edx, [esp+20h+var_10]
+ mov [edx], ecx
+ mov eax, [eax+4]
+ mov ecx, [esp+20h+var_C]
+ mov [ecx], eax
+ mov eax, edi
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ add esp, 10h
+ retn
+sub_4CBEC0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CC040 proc near ; CODE XREF: sub_4CC220+F8p
+ ; sub_4CC3B0+173p ...
+
+var_10 = dword ptr -10h
+var_C = dword ptr -0Ch
+var_8 = dword ptr -8
+var_4 = dword ptr -4
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+arg_C = dword ptr 10h
+arg_10 = dword ptr 14h
+arg_14 = dword ptr 18h
+arg_18 = dword ptr 1Ch
+arg_1C = dword ptr 20h
+
+ sub esp, 10h
+ mov eax, [esp+10h+arg_10]
+ mov edx, [esp+10h+arg_4]
+ push ebx
+ push ebp
+ push esi
+ mov esi, [esp+1Ch+arg_14]
+ lea eax, [eax+esi*8]
+ lea ecx, [eax+4]
+ push edi
+ mov edi, eax
+ mov eax, [esp+20h+arg_8]
+ xor ebx, ebx
+ xor ebp, ebp
+ sub eax, edx
+ cmp [esp+20h+arg_1C], ebx
+ mov [esp+20h+var_C], ecx
+ mov [esp+20h+var_10], edi
+ mov [esp+20h+var_8], ebx
+ mov [esp+20h+var_4], ebp
+ jz loc_4CC159
+ nop
+
+loc_4CC080: ; CODE XREF: sub_4CC040+114j
+ sub [esp+20h+arg_1C], 1
+ cmp eax, [esp+20h+arg_18]
+ jnb loc_4CC159
+ cmp esi, eax
+ sbb ecx, ecx
+ and ecx, [esp+20h+arg_18]
+ sub ecx, eax
+ add ecx, esi
+ mov esi, [esp+20h+arg_10]
+ lea edi, [esi+ecx*8]
+ mov ecx, [esp+20h+arg_C]
+ sub ecx, eax
+ cmp ebx, ebp
+ mov eax, ebx
+ jb short loc_4CC0B0
+ mov eax, ebp
+
+loc_4CC0B0: ; CODE XREF: sub_4CC040+6Cj
+ mov bl, [eax+ecx]
+ mov esi, [esp+20h+arg_C]
+ cmp bl, [eax+esi]
+ jnz short loc_4CC102
+ add eax, 1
+ cmp eax, [esp+20h+arg_0]
+ jz short loc_4CC0E3
+ mov ebx, esi
+ mov ebp, ecx
+ lea esi, [eax+ebx]
+ sub ebp, ebx
+ mov edi, edi
+
+loc_4CC0D0: ; CODE XREF: sub_4CC040+A1j
+ mov bl, [esi+ebp]
+ cmp bl, [esi]
+ jnz short loc_4CC0FC
+ add eax, 1
+ add esi, 1
+ cmp eax, [esp+20h+arg_0]
+ jnz short loc_4CC0D0
+
+loc_4CC0E3: ; CODE XREF: sub_4CC040+83j
+ ; sub_4CC040+C0j
+ mov edx, [edi]
+ mov eax, [esp+20h+var_10]
+ mov [eax], edx
+ mov ecx, [edi+4]
+ mov edx, [esp+20h+var_C]
+ pop edi
+ pop esi
+ pop ebp
+ mov [edx], ecx
+ pop ebx
+ add esp, 10h
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CC0FC: ; CODE XREF: sub_4CC040+95j
+ cmp eax, [esp+20h+arg_0]
+ jz short loc_4CC0E3
+
+loc_4CC102: ; CODE XREF: sub_4CC040+7Aj
+ mov cl, [eax+ecx]
+ mov esi, [esp+20h+arg_C]
+ cmp cl, [eax+esi]
+ jnb short loc_4CC129
+ mov ecx, [esp+20h+var_10]
+ mov ebx, [esp+20h+var_8]
+ add edi, 4
+ mov ebp, eax
+ mov [ecx], edx
+ mov edx, [edi]
+ mov [esp+20h+var_10], edi
+ mov [esp+20h+var_4], ebp
+ jmp short loc_4CC143
+; ---------------------------------------------------------------------------
+
+loc_4CC129: ; CODE XREF: sub_4CC040+CCj
+ mov ecx, [esp+20h+var_C]
+ mov ebp, [esp+20h+var_4]
+ mov [ecx], edx
+ mov edx, [edi]
+ mov ebx, eax
+ mov [esp+20h+var_C], edi
+ mov edi, [esp+20h+var_10]
+ mov [esp+20h+var_8], ebx
+
+loc_4CC143: ; CODE XREF: sub_4CC040+E7j
+ mov eax, [esp+20h+arg_8]
+ sub eax, edx
+ cmp [esp+20h+arg_1C], 0
+ jz short loc_4CC159
+ mov esi, [esp+20h+arg_14]
+ jmp loc_4CC080
+; ---------------------------------------------------------------------------
+
+loc_4CC159: ; CODE XREF: sub_4CC040+39j
+ ; sub_4CC040+49j ...
+ mov eax, [esp+20h+var_C]
+ mov dword ptr [edi], 0
+ pop edi
+ pop esi
+ pop ebp
+ mov dword ptr [eax], 0
+ pop ebx
+ add esp, 10h
+ retn
+sub_4CC040 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CC180: ; DATA XREF: sub_4CCAA0+40o
+ push esi
+ mov esi, [esp+8]
+ mov edx, [esi+10h]
+ cmp edx, 2
+ jnb short loc_4CC1AD
+ add dword ptr [esi+4], 1
+ mov eax, [esi+4]
+ add dword ptr [esi+14h], 1
+ add dword ptr [esi], 1
+ cmp eax, [esi+8]
+ jnz short loc_4CC1A9
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CC1A9: ; CODE XREF: .text:004CC19Ej
+ xor eax, eax
+ pop esi
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CC1AD: ; CODE XREF: .text:004CC18Bj
+ mov eax, [esi]
+ xor ecx, ecx
+ mov ch, [eax+1]
+ push ebx
+ mov ebx, [esp+10h]
+ push edi
+ mov edi, [esi+4]
+ push 1
+ push ebx
+ mov cl, [eax]
+ mov eax, ecx
+ mov ecx, [esi+20h]
+ lea eax, [ecx+eax*4]
+ mov ecx, [eax]
+ mov [eax], edi
+ mov eax, [esi+2Ch]
+ push eax
+ mov eax, [esi+18h]
+ push eax
+ mov eax, [esi+14h]
+ push eax
+ mov eax, [esi+24h]
+ push eax
+ mov eax, [esi]
+ push eax
+ mov eax, [esi+4]
+ push eax
+ push ecx
+ push edx
+ call sub_4CBEC0
+ add dword ptr [esi+4], 1
+ add dword ptr [esi+14h], 1
+ add dword ptr [esi], 1
+ mov edi, eax
+ mov eax, [esi+4]
+ sub edi, ebx
+ add esp, 28h
+ sar edi, 2
+ cmp eax, [esi+8]
+ jnz short loc_4CC212
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CC212: ; CODE XREF: .text:004CC207j
+ mov eax, edi
+ pop edi
+ pop ebx
+ pop esi
+ retn
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CC220 proc near ; DATA XREF: sub_4CCAA0+54o
+
+var_8 = dword ptr -8
+var_4 = dword ptr -4
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ sub esp, 8
+ push esi
+ mov esi, [esp+0Ch+arg_0]
+ mov eax, [esi+10h]
+ cmp eax, 3
+ mov [esp+0Ch+arg_0], eax
+ jnb short loc_4CC259
+ mov eax, 1
+ add [esi+14h], eax
+ add [esi], eax
+ add [esi+4], eax
+ mov eax, [esi+4]
+ cmp eax, [esi+8]
+ jnz short loc_4CC252
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CC252: ; CODE XREF: sub_4CC220+27j
+ xor eax, eax
+ pop esi
+ add esp, 8
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CC259: ; CODE XREF: sub_4CC220+12j
+ push ebx
+ mov ebx, [esi+20h]
+ push ebp
+ xor edx, edx
+ push edi
+ mov edi, [esi]
+ mov dh, [edi+2]
+ movzx ecx, byte ptr [edi]
+ movzx eax, byte ptr [edi+1]
+ xor eax, dword_553198[ecx*4]
+ xor edx, eax
+ and edx, [esi+28h]
+ mov ecx, eax
+ mov ebp, [ebx+edx*4+1000h]
+ mov eax, [esi+4]
+ and ecx, 3FFh
+ sub eax, [ebx+ecx*4]
+ mov [esp+18h+var_8], ebp
+ mov ebp, [esi+4]
+ mov [ebx+edx*4+1000h], ebp
+ mov ebx, [esi+20h]
+ mov edx, [ebx+edx*4+1000h]
+ mov [ebx+ecx*4], edx
+ mov ebx, [esp+18h+arg_4]
+ xor ebp, ebp
+ cmp eax, [esi+18h]
+ mov ecx, 2
+ jnb loc_4CC348
+ mov edx, edi
+ sub edx, eax
+ mov [esp+18h+var_4], edx
+ mov dl, [edx]
+ cmp dl, [edi]
+ jnz short loc_4CC348
+ mov edx, [esp+18h+arg_0]
+ cmp edx, ecx
+ jz short loc_4CC2EA
+
+loc_4CC2D3: ; CODE XREF: sub_4CC220+C4j
+ mov ebx, [esp+18h+var_4]
+ mov bl, [ebx+ecx]
+ cmp bl, [ecx+edi]
+ jnz short loc_4CC2E6
+ add ecx, 1
+ cmp ecx, edx
+ jnz short loc_4CC2D3
+
+loc_4CC2E6: ; CODE XREF: sub_4CC220+BDj
+ mov ebx, [esp+18h+arg_4]
+
+loc_4CC2EA: ; CODE XREF: sub_4CC220+B1j
+ add eax, 0FFFFFFFFh
+ cmp ecx, edx
+ mov [ebx], ecx
+ mov [ebx+4], eax
+ mov ebp, 2
+ jnz short loc_4CC34C
+ mov eax, [esi+2Ch]
+ mov ecx, [esi+18h]
+ push eax
+ mov eax, [esi+14h]
+ push ecx
+ mov ecx, [esi+24h]
+ push eax
+ mov eax, [esi]
+ push ecx
+ mov ecx, [esi+4]
+ push eax
+ mov eax, [esp+2Ch+var_8]
+ push ecx
+ push eax
+ push edx
+ call sub_4CC040
+ mov eax, 1
+ add [esi+14h], eax
+ add [esi], eax
+ add [esi+4], eax
+ mov eax, [esi+4]
+ add esp, 20h
+ cmp eax, [esi+8]
+ jnz short loc_4CC33E
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CC33E: ; CODE XREF: sub_4CC220+113j
+ pop edi
+ mov eax, ebp
+ pop ebp
+ pop ebx
+ pop esi
+ add esp, 8
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CC348: ; CODE XREF: sub_4CC220+97j
+ ; sub_4CC220+A9j
+ mov edx, [esp+18h+arg_0]
+
+loc_4CC34C: ; CODE XREF: sub_4CC220+D9j
+ mov eax, [esi+2Ch]
+ push ecx
+ lea ecx, [ebx+ebp*4]
+ push ecx
+ mov ecx, [esi+18h]
+ push eax
+ mov eax, [esi+14h]
+ push ecx
+ mov ecx, [esi+24h]
+ push eax
+ mov eax, [esi]
+ push ecx
+ mov ecx, [esi+4]
+ push eax
+ mov eax, [esp+34h+var_8]
+ push ecx
+ push eax
+ push edx
+ call sub_4CBEC0
+ mov edi, eax
+ mov eax, 1
+ add [esi+14h], eax
+ add [esi], eax
+ add [esi+4], eax
+ mov eax, [esi+4]
+ sub edi, ebx
+ add esp, 28h
+ sar edi, 2
+ cmp eax, [esi+8]
+ jnz short loc_4CC39B
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CC39B: ; CODE XREF: sub_4CC220+170j
+ mov eax, edi
+ pop edi
+ pop ebp
+ pop ebx
+ pop esi
+ add esp, 8
+ retn
+sub_4CC220 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CC3B0 proc near ; DATA XREF: sub_4CCAA0:loc_4CCB03o
+
+var_10 = dword ptr -10h
+var_8 = dword ptr -8
+var_4 = dword ptr -4
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ sub esp, 10h
+ push esi
+ mov esi, [esp+14h+arg_0]
+ mov eax, [esi+10h]
+ cmp eax, 4
+ mov [esp+14h+arg_0], eax
+ jnb short loc_4CC3E9
+ mov eax, 1
+ add [esi+14h], eax
+ add [esi], eax
+ add [esi+4], eax
+ mov eax, [esi+4]
+ cmp eax, [esi+8]
+ jnz short loc_4CC3E2
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CC3E2: ; CODE XREF: sub_4CC3B0+27j
+ xor eax, eax
+ pop esi
+ add esp, 10h
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CC3E9: ; CODE XREF: sub_4CC3B0+12j
+ push ebx
+ push ebp
+ push edi
+ mov edi, [esi]
+ movzx eax, byte ptr [edi]
+ movzx edx, byte ptr [edi+1]
+ xor edx, dword_553198[eax*4]
+ movzx eax, byte ptr [edi+2]
+ movzx ebp, byte ptr [edi+3]
+ mov ecx, eax
+ add eax, eax
+ add eax, eax
+ add eax, eax
+ xor eax, dword_553198[ebp*4]
+ mov ebp, [esi+4]
+ shl eax, 5
+ shl ecx, 8
+ xor eax, edx
+ and eax, [esi+28h]
+ xor ecx, edx
+ mov ebx, edx
+ mov edx, [esi+20h]
+ and ebx, 3FFh
+ sub ebp, [edx+ebx*4]
+ and ecx, 0FFFFh
+ mov [esp+20h+var_4], ebp
+ mov ebp, [esi+4]
+ sub ebp, [edx+ecx*4+1000h]
+ mov [esp+20h+var_10], ebp
+ mov ebp, [edx+eax*4+41000h]
+ mov [esp+20h+var_8], ebp
+ mov ebp, [esi+4]
+ mov [edx+eax*4+41000h], ebp
+ mov edx, [esi+20h]
+ mov eax, [edx+eax*4+41000h]
+ mov [edx+ecx*4+1000h], eax
+ mov eax, [esi+20h]
+ mov ecx, [eax+ecx*4+1000h]
+ mov [eax+ebx*4], ecx
+ mov ecx, [esp+20h+var_4]
+ mov ebx, [esp+20h+arg_4]
+ xor ebp, ebp
+ cmp ecx, [esi+18h]
+ mov eax, 1
+ jnb short loc_4CC4A9
+ mov edx, edi
+ sub edx, ecx
+ mov dl, [edx]
+ cmp dl, [edi]
+ jnz short loc_4CC4A9
+ mov eax, 2
+ lea edx, [ecx-1]
+ mov [ebx], eax
+ mov [ebx+4], edx
+ mov ebp, eax
+
+loc_4CC4A9: ; CODE XREF: sub_4CC3B0+DEj
+ ; sub_4CC3B0+E8j
+ mov edx, [esp+20h+var_10]
+ cmp ecx, edx
+ jz short loc_4CC4D5
+ cmp edx, [esi+18h]
+ jnb short loc_4CC4D5
+ mov edx, edi
+ sub edx, [esp+20h+var_10]
+ mov dl, [edx]
+ cmp dl, [edi]
+ jnz short loc_4CC4D5
+ mov ecx, [esp+20h+var_10]
+ lea edx, [ecx-1]
+ mov [ebx+ebp*4+4], edx
+ mov eax, 3
+ add ebp, 2
+
+loc_4CC4D5: ; CODE XREF: sub_4CC3B0+FFj
+ ; sub_4CC3B0+104j ...
+ test ebp, ebp
+ mov edx, [esp+20h+arg_0]
+ jz short loc_4CC553
+ cmp eax, edx
+ jz short loc_4CC4FE
+ mov edx, eax
+ sub edx, ecx
+ add edx, edi
+
+loc_4CC4E7: ; CODE XREF: sub_4CC3B0+148j
+ mov cl, [edx]
+ cmp cl, [eax+edi]
+ jnz short loc_4CC4FA
+ add eax, 1
+ add edx, 1
+ cmp eax, [esp+20h+arg_0]
+ jnz short loc_4CC4E7
+
+loc_4CC4FA: ; CODE XREF: sub_4CC3B0+13Cj
+ mov edx, [esp+20h+arg_0]
+
+loc_4CC4FE: ; CODE XREF: sub_4CC3B0+12Fj
+ cmp eax, edx
+ mov [ebx+ebp*4-8], eax
+ jnz short loc_4CC553
+ mov eax, [esi+2Ch]
+ mov ecx, [esi+18h]
+ push eax
+ mov eax, [esi+14h]
+ push ecx
+ mov ecx, [esi+24h]
+ push eax
+ mov eax, [esi]
+ push ecx
+ mov ecx, [esi+4]
+ push eax
+ mov eax, [esp+34h+var_8]
+ push ecx
+ push eax
+ push edx
+ call sub_4CC040
+ mov eax, 1
+ add [esi+14h], eax
+ add [esi], eax
+ add [esi+4], eax
+ mov eax, [esi+4]
+ add esp, 20h
+ cmp eax, [esi+8]
+ jnz short loc_4CC549
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CC549: ; CODE XREF: sub_4CC3B0+18Ej
+ pop edi
+ mov eax, ebp
+ pop ebp
+ pop ebx
+ pop esi
+ add esp, 10h
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CC553: ; CODE XREF: sub_4CC3B0+12Bj
+ ; sub_4CC3B0+154j
+ cmp eax, 3
+ jnb short loc_4CC55D
+ mov eax, 3
+
+loc_4CC55D: ; CODE XREF: sub_4CC3B0+1A6j
+ push eax
+ mov eax, [esi+2Ch]
+ lea ecx, [ebx+ebp*4]
+ push ecx
+ mov ecx, [esi+18h]
+ push eax
+ mov eax, [esi+14h]
+ push ecx
+ mov ecx, [esi+24h]
+ push eax
+ mov eax, [esi]
+ push ecx
+ mov ecx, [esi+4]
+ push eax
+ mov eax, [esp+3Ch+var_8]
+ push ecx
+ push eax
+ push edx
+ call sub_4CBEC0
+ mov edi, eax
+ mov eax, 1
+ add [esi+14h], eax
+ add [esi], eax
+ add [esi+4], eax
+ mov eax, [esi+4]
+ sub edi, ebx
+ add esp, 28h
+ sar edi, 2
+ cmp eax, [esi+8]
+ jnz short loc_4CC5AC
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CC5AC: ; CODE XREF: sub_4CC3B0+1F1j
+ mov eax, edi
+ pop edi
+ pop ebp
+ pop ebx
+ pop esi
+ add esp, 10h
+ retn
+sub_4CC3B0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CC5C0 proc near ; DATA XREF: sub_4CCAA0+29o
+
+var_10 = dword ptr -10h
+var_8 = dword ptr -8
+var_4 = dword ptr -4
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ sub esp, 10h
+ push esi
+ mov esi, [esp+14h+arg_0]
+ mov eax, [esi+10h]
+ cmp eax, 4
+ mov [esp+14h+arg_0], eax
+ jnb short loc_4CC5F9
+ mov eax, 1
+ add [esi+14h], eax
+ add [esi], eax
+ add [esi+4], eax
+ mov eax, [esi+4]
+ cmp eax, [esi+8]
+ jnz short loc_4CC5F2
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CC5F2: ; CODE XREF: sub_4CC5C0+27j
+ xor eax, eax
+ pop esi
+ add esp, 10h
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CC5F9: ; CODE XREF: sub_4CC5C0+12j
+ push ebx
+ push ebp
+ push edi
+ mov edi, [esi]
+ movzx eax, byte ptr [edi]
+ movzx edx, byte ptr [edi+1]
+ xor edx, dword_553198[eax*4]
+ movzx eax, byte ptr [edi+2]
+ movzx ebp, byte ptr [edi+3]
+ mov ecx, eax
+ add eax, eax
+ add eax, eax
+ add eax, eax
+ xor eax, dword_553198[ebp*4]
+ mov ebp, [esi+4]
+ shl eax, 5
+ shl ecx, 8
+ xor eax, edx
+ and eax, [esi+28h]
+ xor ecx, edx
+ mov ebx, edx
+ mov edx, [esi+20h]
+ and ebx, 3FFh
+ sub ebp, [edx+ebx*4]
+ and ecx, 0FFFFh
+ mov [esp+20h+var_4], ebp
+ mov ebp, [esi+4]
+ sub ebp, [edx+ecx*4+1000h]
+ mov [esp+20h+var_10], ebp
+ mov ebp, [edx+eax*4+41000h]
+ mov [esp+20h+var_8], ebp
+ mov ebp, [esi+4]
+ mov [edx+eax*4+41000h], ebp
+ mov edx, [esi+20h]
+ mov eax, [edx+eax*4+41000h]
+ mov [edx+ecx*4+1000h], eax
+ mov eax, [esi+20h]
+ mov ecx, [eax+ecx*4+1000h]
+ mov [eax+ebx*4], ecx
+ mov ecx, [esp+20h+var_4]
+ mov ebx, [esp+20h+arg_4]
+ xor ebp, ebp
+ cmp ecx, [esi+18h]
+ mov eax, 1
+ jnb short loc_4CC6B9
+ mov edx, edi
+ sub edx, ecx
+ mov dl, [edx]
+ cmp dl, [edi]
+ jnz short loc_4CC6B9
+ mov eax, 2
+ lea edx, [ecx-1]
+ mov [ebx], eax
+ mov [ebx+4], edx
+ mov ebp, eax
+
+loc_4CC6B9: ; CODE XREF: sub_4CC5C0+DEj
+ ; sub_4CC5C0+E8j
+ mov edx, [esp+20h+var_10]
+ cmp ecx, edx
+ jz short loc_4CC6E5
+ cmp edx, [esi+18h]
+ jnb short loc_4CC6E5
+ mov edx, edi
+ sub edx, [esp+20h+var_10]
+ mov dl, [edx]
+ cmp dl, [edi]
+ jnz short loc_4CC6E5
+ mov ecx, [esp+20h+var_10]
+ lea edx, [ecx-1]
+ mov [ebx+ebp*4+4], edx
+ mov eax, 3
+ add ebp, 2
+
+loc_4CC6E5: ; CODE XREF: sub_4CC5C0+FFj
+ ; sub_4CC5C0+104j ...
+ test ebp, ebp
+ jz short loc_4CC747
+ cmp eax, [esp+20h+arg_0]
+ jz short loc_4CC708
+ mov edx, eax
+ sub edx, ecx
+ add edx, edi
+
+loc_4CC6F5: ; CODE XREF: sub_4CC5C0+146j
+ mov cl, [edx]
+ cmp cl, [eax+edi]
+ jnz short loc_4CC708
+ add eax, 1
+ add edx, 1
+ cmp eax, [esp+20h+arg_0]
+ jnz short loc_4CC6F5
+
+loc_4CC708: ; CODE XREF: sub_4CC5C0+12Dj
+ ; sub_4CC5C0+13Aj
+ cmp eax, [esp+20h+arg_0]
+ mov [ebx+ebp*4-8], eax
+ jnz short loc_4CC747
+ mov edx, [esi+14h]
+ mov eax, [esi+24h]
+ mov ecx, [esp+20h+var_8]
+ mov [eax+edx*4], ecx
+ mov eax, 1
+ add [esi+14h], eax
+ add [esi], eax
+ add [esi+4], eax
+ mov eax, [esi+4]
+ cmp eax, [esi+8]
+ jnz short loc_4CC73D
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CC73D: ; CODE XREF: sub_4CC5C0+172j
+ pop edi
+ mov eax, ebp
+ pop ebp
+ pop ebx
+ pop esi
+ add esp, 10h
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CC747: ; CODE XREF: sub_4CC5C0+127j
+ ; sub_4CC5C0+150j
+ cmp eax, 3
+ jnb short loc_4CC751
+ mov eax, 3
+
+loc_4CC751: ; CODE XREF: sub_4CC5C0+18Aj
+ mov ecx, [esi+18h]
+ push eax
+ mov eax, [esi+2Ch]
+ lea edx, [ebx+ebp*4]
+ push edx
+ mov edx, [esi+14h]
+ push eax
+ mov eax, [esi+24h]
+ push ecx
+ mov ecx, [esi]
+ push edx
+ mov edx, [esi+4]
+ push eax
+ mov eax, [esp+38h+var_8]
+ push ecx
+ mov ecx, [esp+3Ch+arg_0]
+ push edx
+ push eax
+ push ecx
+ call sub_4CBDE0
+ mov edi, eax
+ mov eax, 1
+ add [esi+14h], eax
+ add [esi], eax
+ add [esi+4], eax
+ mov eax, [esi+4]
+ sub edi, ebx
+ add esp, 28h
+ sar edi, 2
+ cmp eax, [esi+8]
+ jnz short loc_4CC7A4
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CC7A4: ; CODE XREF: sub_4CC5C0+1D9j
+ mov eax, edi
+ pop edi
+ pop ebp
+ pop ebx
+ pop esi
+ add esp, 10h
+ retn
+sub_4CC5C0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CC7B0 proc near ; DATA XREF: sub_4CCAA0+47o
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ push ebx
+ push ebp
+ mov ebp, [esp+8+arg_4]
+ push esi
+ mov esi, [esp+0Ch+arg_0]
+ push edi
+ mov edi, 1
+
+loc_4CC7C1: ; CODE XREF: sub_4CC7B0+6Dj
+ mov edx, [esi+10h]
+ cmp edx, 2
+ jb short loc_4CC802
+ mov eax, [esi]
+ mov ebx, [esi+4]
+ xor ecx, ecx
+ mov ch, [eax+1]
+ mov cl, [eax]
+ mov eax, ecx
+ mov ecx, [esi+20h]
+ lea eax, [ecx+eax*4]
+ mov ecx, [eax]
+ mov [eax], ebx
+ mov eax, [esi+2Ch]
+ push eax
+ mov eax, [esi+18h]
+ push eax
+ mov eax, [esi+14h]
+ push eax
+ mov eax, [esi+24h]
+ push eax
+ mov eax, [esi]
+ push eax
+ mov eax, [esi+4]
+ push eax
+ push ecx
+ push edx
+ call sub_4CC040
+ add esp, 20h
+
+loc_4CC802: ; CODE XREF: sub_4CC7B0+17j
+ add [esi+4], edi
+ mov eax, [esi+4]
+ add [esi+14h], edi
+ add [esi], edi
+ cmp eax, [esi+8]
+ jnz short loc_4CC81B
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CC81B: ; CODE XREF: sub_4CC7B0+60j
+ sub ebp, edi
+ jnz short loc_4CC7C1
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ retn
+sub_4CC7B0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CC830 proc near ; DATA XREF: sub_4CCAA0+5Bo
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ push ebx
+ push ebp
+ push esi
+ mov esi, [esp+0Ch+arg_0]
+ push edi
+ mov edi, 1
+ lea ecx, [ecx+0]
+
+loc_4CC840: ; CODE XREF: sub_4CC830+9Fj
+ mov ebp, [esi+10h]
+ cmp ebp, 3
+ jb short loc_4CC8B2
+ mov ecx, [esi]
+ movzx edx, byte ptr [ecx]
+ movzx eax, byte ptr [ecx+1]
+ xor eax, dword_553198[edx*4]
+ mov ebx, [esi+4]
+ xor edx, edx
+ mov dh, [ecx+2]
+ xor edx, eax
+ and edx, [esi+28h]
+ and eax, 3FFh
+ mov ecx, edx
+ mov edx, [esi+20h]
+ mov edi, [edx+ecx*4+1000h]
+ lea edx, [edx+ecx*4+1000h]
+ mov [edx], ebx
+ mov edx, [esi+20h]
+ mov ecx, [edx+ecx*4+1000h]
+ mov [edx+eax*4], ecx
+ mov edx, [esi+2Ch]
+ mov eax, [esi+18h]
+ mov ecx, [esi+14h]
+ push edx
+ mov edx, [esi+24h]
+ push eax
+ mov eax, [esi]
+ push ecx
+ mov ecx, [esi+4]
+ push edx
+ push eax
+ push ecx
+ push edi
+ push ebp
+ call sub_4CC040
+ add esp, 20h
+ mov edi, 1
+
+loc_4CC8B2: ; CODE XREF: sub_4CC830+16j
+ add [esi+4], edi
+ mov eax, [esi+4]
+ add [esi+14h], edi
+ add [esi], edi
+ cmp eax, [esi+8]
+ jnz short loc_4CC8CB
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CC8CB: ; CODE XREF: sub_4CC830+90j
+ sub [esp+10h+arg_4], edi
+ jnz loc_4CC840
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ retn
+sub_4CC830 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CC8E0 proc near ; DATA XREF: sub_4CCAA0+6Ao
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ push ebx
+ push ebp
+ push esi
+ mov esi, [esp+0Ch+arg_0]
+ push edi
+ mov edi, 1
+ lea ecx, [ecx+0]
+
+loc_4CC8F0: ; CODE XREF: sub_4CC8E0+D6j
+ mov eax, [esi+10h]
+ cmp eax, 4
+ mov [esp+10h+arg_0], eax
+ jb loc_4CC999
+ mov eax, [esi]
+ movzx edi, byte ptr [eax+2]
+ movzx edx, byte ptr [eax]
+ movzx ebx, byte ptr [eax+3]
+ movzx ecx, byte ptr [eax+1]
+ xor ecx, dword_553198[edx*4]
+ mov ebp, [esi+4]
+ lea eax, ds:0[edi*8]
+ xor eax, dword_553198[ebx*4]
+ mov edx, edi
+ mov edi, [esi+20h]
+ shl eax, 5
+ xor eax, ecx
+ and eax, [esi+28h]
+ shl edx, 8
+ mov ebx, [edi+eax*4+41000h]
+ xor edx, ecx
+ and edx, 0FFFFh
+ mov [edi+edx*4+1000h], ebp
+ mov edi, [esi+20h]
+ mov edx, [edi+edx*4+1000h]
+ and ecx, 3FFh
+ mov [edi+ecx*4], edx
+ mov ecx, [esi+20h]
+ mov edx, [esi+4]
+ mov [ecx+eax*4+41000h], edx
+ mov eax, [esi+2Ch]
+ mov ecx, [esi+18h]
+ mov edx, [esi+14h]
+ push eax
+ mov eax, [esi+24h]
+ push ecx
+ mov ecx, [esi]
+ push edx
+ mov edx, [esi+4]
+ push eax
+ mov eax, [esp+20h+arg_0]
+ push ecx
+ push edx
+ push ebx
+ push eax
+ call sub_4CC040
+ add esp, 20h
+ mov edi, 1
+
+loc_4CC999: ; CODE XREF: sub_4CC8E0+1Aj
+ add [esi+4], edi
+ mov eax, [esi+4]
+ add [esi+14h], edi
+ add [esi], edi
+ cmp eax, [esi+8]
+ jnz short loc_4CC9B2
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CC9B2: ; CODE XREF: sub_4CC8E0+C7j
+ sub [esp+10h+arg_4], edi
+ jnz loc_4CC8F0
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ retn
+sub_4CC8E0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CC9D0 proc near ; DATA XREF: sub_4CCAA0+30o
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ push ebx
+ push ebp
+ push esi
+ mov esi, [esp+0Ch+arg_0]
+ push edi
+ mov edi, 1
+ lea ecx, [ecx+0]
+
+loc_4CC9E0: ; CODE XREF: sub_4CC9D0+BAj
+ cmp dword ptr [esi+10h], 4
+ jb loc_4CCA6D
+ mov eax, [esi]
+ movzx edi, byte ptr [eax+2]
+ movzx edx, byte ptr [eax]
+ movzx ebx, byte ptr [eax+3]
+ movzx ecx, byte ptr [eax+1]
+ xor ecx, dword_553198[edx*4]
+ mov ebp, [esi+4]
+ lea eax, ds:0[edi*8]
+ xor eax, dword_553198[ebx*4]
+ mov edx, edi
+ mov edi, [esi+20h]
+ shl eax, 5
+ xor eax, ecx
+ and eax, [esi+28h]
+ mov ebx, [edi+eax*4+41000h]
+ lea edi, [edi+eax*4+41000h]
+ mov [edi], ebp
+ mov edi, [esi+20h]
+ mov eax, [edi+eax*4+41000h]
+ shl edx, 8
+ xor edx, ecx
+ and edx, 0FFFFh
+ mov [edi+edx*4+1000h], eax
+ mov eax, [esi+20h]
+ mov edx, [eax+edx*4+1000h]
+ and ecx, 3FFh
+ mov [eax+ecx*4], edx
+ mov eax, [esi+14h]
+ mov ecx, [esi+24h]
+ mov [ecx+eax*4], ebx
+ mov edi, 1
+
+loc_4CCA6D: ; CODE XREF: sub_4CC9D0+14j
+ add [esi+4], edi
+ mov eax, [esi+4]
+ add [esi+14h], edi
+ add [esi], edi
+ cmp eax, [esi+8]
+ jnz short loc_4CCA86
+ push esi
+ call sub_4CBD50
+ add esp, 4
+
+loc_4CCA86: ; CODE XREF: sub_4CC9D0+ABj
+ sub [esp+10h+arg_4], edi
+ jnz loc_4CC9E0
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ retn
+sub_4CC9D0 endp
+
+; =============== S U B R O U T I N E =======================================
+
+sub_4CCAA0 proc near ; CODE XREF: sub_4D0270+F3p
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ mov eax, [esp+arg_4]
+ mov ecx, [esp+arg_0]
+ mov dword ptr [eax], offset sub_4CBC80
+ mov dword ptr [eax+4], offset loc_4CB960
+ mov dword ptr [eax+8], offset loc_4CB970
+ mov dword ptr [eax+0Ch], offset loc_4CB950
+ cmp dword ptr [ecx+50h], 0
+ jnz short loc_4CCAD8
+ mov dword ptr [eax+10h], offset sub_4CC5C0
+ mov dword ptr [eax+14h], offset sub_4CC9D0
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CCAD8: ; CODE XREF: sub_4CCAA0+27j
+ mov ecx, [ecx+48h]
+ cmp ecx, 2
+ jnz short loc_4CCAEF
+ mov dword ptr [eax+10h], offset loc_4CC180
+ mov dword ptr [eax+14h], offset sub_4CC7B0
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CCAEF: ; CODE XREF: sub_4CCAA0+3Ej
+ cmp ecx, 3
+ jnz short loc_4CCB03
+ mov dword ptr [eax+10h], offset sub_4CC220
+ mov dword ptr [eax+14h], offset sub_4CC830
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CCB03: ; CODE XREF: sub_4CCAA0+52j
+ mov dword ptr [eax+10h], offset sub_4CC3B0
+ mov dword ptr [eax+14h], offset sub_4CC8E0
+ retn
+sub_4CCAA0 endp
+
+; ---------------------------------------------------------------------------
+
+Interface1_AddRef proc near ; DATA XREF: .rdata:00517A94o
+;sub_4CCB80
+
+arg_0 = dword ptr 4
+ mov eax, [esp+arg_0]
+ add dword ptr [eax+4], 1
+ mov eax, [eax+4]
+ retn 4
+Interface1_AddRef endp
+
+; ---------------------------------------------------------------------------
+
+sub_4CCB20 proc near ; DATA XREF: .rdata:00517A9Co
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+arg_C = dword ptr 10h
+
+ push esi
+ mov esi, [esp+4+arg_0]
+ mov ecx, [esi+10h]
+ sub ecx, [esi+18h]
+ mov eax, [esi+14h]
+ sbb eax, [esi+1Ch]
+ xor edx, edx
+ cmp edx, eax
+ push edi
+ mov edi, [esp+8+arg_8]
+ jb short loc_4CCB48
+ ja short loc_4CCB42
+ cmp edi, ecx
+ jbe short loc_4CCB48
+
+loc_4CCB42: ; CODE XREF: sub_4CCB20+1Cj
+ mov edi, [esi+10h]
+ sub edi, [esi+18h]
+
+loc_4CCB48: ; CODE XREF: sub_4CCB20+1Aj
+ ; sub_4CCB20+20j
+ mov eax, [esp+8+arg_C]
+ test eax, eax
+ jz short loc_4CCB52
+ mov [eax], edi
+
+loc_4CCB52: ; CODE XREF: sub_4CCB20+2Ej
+ test edi, edi
+ jz short loc_4CCB72
+ mov eax, [esi+8]
+ add eax, [esi+18h]
+ mov ecx, [esp+8+arg_4]
+ push edi ; size_t
+ push eax ; void *
+ push ecx ; void *
+ call _memcpy ; Microsoft VisualC 2-8/net runtime
+ add esp, 0Ch
+ add [esi+18h], edi
+ adc dword ptr [esi+1Ch], 0
+
+loc_4CCB72: ; CODE XREF: sub_4CCB20+34j
+ pop edi
+ xor eax, eax
+ pop esi
+ retn 10h
+sub_4CCB20 endp
+
+; ---------------------------------------------------------------------------
+
+sub_4CCB90 proc near ; DATA XREF: .rdata:00517AB0o
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+arg_C = dword ptr 10h
+
+ push ebx
+ mov ebx, [esp+4+arg_8]
+ push esi
+ mov esi, [esp+8+arg_0]
+ mov ecx, [esi+10h]
+ mov eax, [esi+14h]
+ push edi
+ xor edi, edi
+ sub ecx, [esi+18h]
+ sbb eax, [esi+1Ch]
+ cmp edi, eax
+ jb short loc_4CCBC2
+ ja short loc_4CCBB3
+ cmp ebx, ecx
+ jbe short loc_4CCBC2
+
+loc_4CCBB3: ; CODE XREF: sub_4CCB90+1Dj
+ pop edi
+ mov byte ptr [esi+20h], 1
+ pop esi
+ mov eax, 80004005h
+ pop ebx
+ retn 10h
+
+loc_4CCBC2: ; CODE XREF: sub_4CCB90+1Bj
+ ; sub_4CCB90+21j
+ mov ecx, [esi+8]
+ mov eax, [esp+0Ch+arg_4]
+ add ecx, [esi+18h]
+ push ebx ; size_t
+ push eax ; void *
+ push ecx ; void *
+ call _memcpy ; Microsoft VisualC 2-8/net runtime
+ mov eax, [esp+18h+arg_C]
+ add esp, 0Ch
+ add [esi+18h], ebx
+ adc [esi+1Ch], edi
+ test eax, eax
+ jz short loc_4CCBE7
+ mov [eax], ebx
+
+loc_4CCBE7: ; CODE XREF: sub_4CCB90+53j
+ pop edi
+ pop esi
+ xor eax, eax
+ pop ebx
+ retn 10h
+sub_4CCB90 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; ---------------------------------------------------------------------------
+
+LzmaProps_Decode proc near ; CODE XREF: Decompress_lzma_internal+35p
+;sub_4CCBF0
+
+propsRes = dword ptr 4
+propsData = dword ptr 8
+propsSize = dword ptr 0Ch
+
+ cmp [esp+propsSize], 5 ; LZMA_PROPS_SIZE
+ jge short loc_4CCBFD
+
+loc_4CCBF7: ; CODE XREF: LzmaProps_Decode+16j
+ mov eax, 1
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CCBFD: ; CODE XREF: LzmaProps_Decode+5j
+ mov eax, [esp+propsData]
+ mov cl, [eax]
+ cmp cl, 0E1h ; 9 * 5 * 5
+ jnb short loc_4CCBF7
+ cmp cl, 2Dh
+ push edi
+ mov edi, [esp+4+propsRes]
+ mov dword ptr [edi+8], 0
+ jb short loc_4CCC40
+ push esi
+ movzx esi, cl
+ mov eax, 6C16C16Dh
+ mul esi
+ mov eax, esi
+ sub eax, edx
+ shr eax, 1
+ add eax, edx
+ shr eax, 5
+ movzx eax, al
+ mov edx, eax
+ pop esi
+
+loc_4CCC35: ; CODE XREF: LzmaProps_Decode+4Bj
+ add cl, 0D3h
+ sub eax, 1
+ jnz short loc_4CCC35
+ mov [edi+8], edx
+
+loc_4CCC40: ; CODE XREF: LzmaProps_Decode+27j
+ cmp cl, 9
+ mov dword ptr [edi+4], 0
+ jb short loc_4CCC6B
+ movzx edx, cl
+ mov eax, 38E38E39h
+ mul edx
+ shr edx, 1
+ movzx eax, dl
+ mov edx, eax
+ lea ecx, [ecx+0]
+
+loc_4CCC60: ; CODE XREF: LzmaProps_Decode+76j
+ add cl, 0F7h
+ sub eax, 1
+ jnz short loc_4CCC60
+ mov [edi+4], edx
+
+loc_4CCC6B: ; CODE XREF: LzmaProps_Decode+5Aj
+ movzx eax, cl
+ mov [edi], eax
+ xor eax, eax
+ pop edi
+ retn
+LzmaProps_Decode endp
+
+sub_4CCC80 proc near ; CODE XREF: Decompress_lzma_internal+97p
+
+var_3C = dword ptr -3Ch
+var_38 = dword ptr -38h
+var_34 = dword ptr -34h
+var_30 = dword ptr -30h
+var_2C = dword ptr -2Ch
+var_28 = dword ptr -28h
+var_24 = dword ptr -24h
+var_20 = dword ptr -20h
+var_1C = dword ptr -1Ch
+var_18 = dword ptr -18h
+var_14 = dword ptr -14h
+var_10 = dword ptr -10h
+var_C = dword ptr -0Ch
+var_8 = dword ptr -8
+var_4 = dword ptr -4
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+arg_C = dword ptr 10h
+arg_10 = dword ptr 14h
+arg_14 = dword ptr 18h
+arg_18 = dword ptr 1Ch
+
+ sub esp, 3Ch
+ mov eax, [esp+3Ch+arg_0]
+ mov ecx, [eax+8]
+ push ebx
+ push ebp
+ mov ebp, 1
+ mov edx, ebp
+ shl edx, cl
+ mov ecx, [eax+4]
+ xor ebx, ebx
+ push esi
+ sub edx, ebp
+ mov [esp+48h+var_C], edx
+ mov edx, ebp
+ shl edx, cl
+ mov ecx, [esp+48h+arg_C]
+ push edi
+ mov edi, [eax+0Ch]
+ sub edx, ebp
+ mov [esp+4Ch+var_8], edx
+ mov edx, [eax]
+ mov [ecx], ebx
+ mov ecx, [esp+4Ch+arg_18]
+ mov [ecx], ebx
+ mov ecx, [eax+4]
+ add ecx, edx
+ mov eax, 300h
+ shl eax, cl
+ mov [esp+4Ch+var_20], edi
+ mov [esp+4Ch+var_2C], ebx
+ mov byte ptr [esp+4Ch+arg_0], bl
+ add eax, 736h
+ mov [esp+4Ch+var_14], edx
+ mov [esp+4Ch+var_34], ebx
+ mov [esp+4Ch+var_38], ebp
+ mov [esp+4Ch+var_24], ebp
+ mov [esp+4Ch+var_28], ebp
+ mov [esp+4Ch+var_18], ebp
+ jz short loc_4CCD04
+ mov ecx, eax
+ shr ecx, 1
+ mov eax, 4000400h
+ rep stosd
+ adc ecx, ecx
+ rep stosw
+
+loc_4CCD04: ; CODE XREF: sub_4CCC80+72j
+ mov edx, [esp+4Ch+arg_8]
+ mov ecx, [esp+4Ch+arg_4]
+ lea edi, [ecx+edx]
+ xor esi, esi
+ or eax, 0FFFFFFFFh
+ mov [esp+4Ch+var_3C], edi
+ xor edx, edx
+ lea ebx, [ebx+0]
+
+loc_4CCD20: ; CODE XREF: sub_4CCC80+BCj
+ cmp ecx, edi
+ jz loc_4CCF0B
+ movzx ebp, byte ptr [ecx]
+ shl esi, 8
+ or esi, ebp
+ mov ebp, 1
+ add edx, ebp
+ add ecx, ebp
+ cmp edx, 5
+ jl short loc_4CCD20
+ cmp [esp+4Ch+arg_14], ebx
+ mov [esp+4Ch+arg_8], ecx
+ jbe loc_4CCFCD
+ lea esp, [esp+0]
+
+loc_4CCD50: ; CODE XREF: sub_4CCC80+32Dj
+ mov edx, [esp+4Ch+var_34]
+ mov ecx, [esp+4Ch+var_C]
+ and ecx, [esp+4Ch+var_2C]
+ mov edi, [esp+4Ch+var_20]
+ mov ebx, edx
+ shl ebx, 4
+ add ebx, ecx
+ cmp eax, 1000000h
+ lea ebx, [edi+ebx*2]
+ mov [esp+4Ch+var_1C], ecx
+ mov [esp+4Ch+var_30], ebx
+ jnb short loc_4CCD99
+ mov ecx, [esp+4Ch+arg_8]
+ cmp ecx, [esp+4Ch+var_3C]
+ jz loc_4CD6E2
+ movzx ebp, byte ptr [ecx]
+ shl esi, 8
+ shl eax, 8
+ or esi, ebp
+ add ecx, 1
+ mov [esp+4Ch+arg_8], ecx
+
+loc_4CCD99: ; CODE XREF: sub_4CCC80+F7j
+ movzx ebx, word ptr [ebx]
+ movzx ebp, bx
+ mov ecx, eax
+ shr ecx, 0Bh
+ imul ecx, ebp
+ cmp esi, ecx
+ jnb loc_4CCFF4
+ mov edi, [esp+4Ch+var_30]
+ mov eax, ecx
+ mov ecx, 800h
+ sub ecx, ebp
+ mov ebp, [esp+4Ch+var_8]
+ sar ecx, 5
+ add ecx, ebx
+ movzx ebx, byte ptr [esp+4Ch+arg_0]
+ mov [edi], cx
+ mov edi, [esp+4Ch+var_2C]
+ mov ecx, 8
+ sub cl, byte ptr [esp+4Ch+var_14]
+ and ebp, edi
+ shr ebx, cl
+ mov ecx, [esp+4Ch+var_14]
+ shl ebp, cl
+ mov ecx, [esp+4Ch+var_20]
+ mov edx, 1
+ add ebx, ebp
+ imul ebx, 600h
+ cmp [esp+4Ch+var_34], 7
+ lea ebp, [ebx+ecx+0E6Ch]
+ mov [esp+4Ch+var_30], ebp
+ jl loc_4CCEB0
+ sub edi, [esp+4Ch+var_38]
+ mov ecx, [esp+4Ch+arg_10]
+ movzx ebx, byte ptr [edi+ecx]
+ jmp short loc_4CCE20
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CCE20: ; CODE XREF: sub_4CCC80+197j
+ ; sub_4CCC80+2C6j
+ add ebx, ebx
+ mov [esp+4Ch+var_10], ebx
+ and ebx, 100h
+ cmp eax, 1000000h
+ lea ecx, [ebx+edx]
+ lea ebp, [ebp+ecx*2+200h]
+ mov [esp+4Ch+arg_0], ebp
+ jnb short loc_4CCE61
+ mov ecx, [esp+4Ch+arg_8]
+ cmp ecx, [esp+4Ch+var_3C]
+ jz loc_4CD6E2
+ movzx edi, byte ptr [ecx]
+ shl esi, 8
+ shl eax, 8
+ or esi, edi
+ add ecx, 1
+ mov [esp+4Ch+arg_8], ecx
+
+loc_4CCE61: ; CODE XREF: sub_4CCC80+1BFj
+ movzx edi, word ptr [ebp+0]
+ movzx ebp, di
+ mov ecx, eax
+ shr ecx, 0Bh
+ imul ecx, ebp
+ cmp esi, ecx
+ jnb loc_4CCF15
+ mov eax, ecx
+ mov ecx, 800h
+ sub ecx, ebp
+ sar ecx, 5
+ add ecx, edi
+ mov edi, [esp+4Ch+arg_0]
+ add edx, edx
+ test ebx, ebx
+ mov [edi], cx
+ jz loc_4CCF36
+
+loc_4CCE97: ; CODE XREF: sub_4CCC80+2B0j
+ cmp edx, 100h
+ jge loc_4CCF70
+ mov ebp, [esp+4Ch+var_30]
+ jmp short loc_4CCEB0
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CCEB0: ; CODE XREF: sub_4CCC80+185j
+ ; sub_4CCC80+227j ...
+ cmp eax, 1000000h
+ lea ecx, [edx+edx]
+ mov [esp+4Ch+arg_0], ecx
+ jnb short loc_4CCEDE
+ mov edi, [esp+4Ch+arg_8]
+ cmp edi, [esp+4Ch+var_3C]
+ jz loc_4CD6E2
+ movzx ebx, byte ptr [edi]
+ shl esi, 8
+ shl eax, 8
+ or esi, ebx
+ add edi, 1
+ mov [esp+4Ch+arg_8], edi
+
+loc_4CCEDE: ; CODE XREF: sub_4CCC80+23Cj
+ movzx edi, word ptr [ecx+ebp]
+ movzx ebx, di
+ mov ecx, eax
+ shr ecx, 0Bh
+ imul ecx, ebx
+ cmp esi, ecx
+ jnb short loc_4CCF4B
+ mov eax, ecx
+ mov ecx, 800h
+ sub ecx, ebx
+ sar ecx, 5
+ add ecx, edi
+ mov edi, [esp+4Ch+arg_0]
+ mov [edi+ebp], cx
+ add edx, edx
+ jmp short loc_4CCF64
+; ---------------------------------------------------------------------------
+
+loc_4CCF0B: ; CODE XREF: sub_4CCC80+A2j
+ pop edi
+ pop esi
+ mov eax, ebp
+ pop ebp
+ pop ebx
+ add esp, 3Ch
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CCF15: ; CODE XREF: sub_4CCC80+1F2j
+ sub eax, ecx
+ sub esi, ecx
+ mov cx, di
+ shr cx, 5
+ sub di, cx
+ test ebx, ebx
+ mov ecx, [esp+4Ch+arg_0]
+ mov [ecx], di
+ lea edx, [edx+edx+1]
+ jz loc_4CCE97
+
+loc_4CCF36: ; CODE XREF: sub_4CCC80+211j
+ cmp edx, 100h
+ jge short loc_4CCF70
+ mov ebp, [esp+4Ch+var_30]
+ mov ebx, [esp+4Ch+var_10]
+ jmp loc_4CCE20
+; ---------------------------------------------------------------------------
+
+loc_4CCF4B: ; CODE XREF: sub_4CCC80+26Fj
+ mov dx, di
+ shr dx, 5
+ sub di, dx
+ mov edx, [esp+4Ch+arg_0]
+ sub eax, ecx
+ sub esi, ecx
+ mov [edx+ebp], di
+ add edx, 1
+
+loc_4CCF64: ; CODE XREF: sub_4CCC80+289j
+ cmp edx, 100h
+ jl loc_4CCEB0
+
+loc_4CCF70: ; CODE XREF: sub_4CCC80+21Dj
+ ; sub_4CCC80+2BCj
+ mov ecx, [esp+4Ch+var_2C]
+ mov edi, [esp+4Ch+arg_10]
+ mov [ecx+edi], dl
+ add ecx, 1
+ mov [esp+4Ch+var_2C], ecx
+ mov ecx, [esp+4Ch+var_34]
+ cmp ecx, 4
+ mov byte ptr [esp+4Ch+arg_0], dl
+ jge short loc_4CCF99
+ mov [esp+4Ch+var_34], 0
+ jmp short loc_4CCFA5
+; ---------------------------------------------------------------------------
+
+loc_4CCF99: ; CODE XREF: sub_4CCC80+30Dj
+ cmp ecx, 0Ah
+ jge short loc_4CCFEF
+ sub ecx, 3
+
+loc_4CCFA1: ; CODE XREF: sub_4CCC80+372j
+ mov [esp+4Ch+var_34], ecx
+
+loc_4CCFA5: ; CODE XREF: sub_4CCC80+317j
+ ; sub_4CCC80+530j ...
+ mov ecx, [esp+4Ch+var_2C]
+ cmp ecx, [esp+4Ch+arg_14]
+ jb loc_4CCD50
+
+loc_4CCFB3: ; CODE XREF: sub_4CCC80+A13j
+ ; sub_4CCC80+A5Aj
+ cmp eax, 1000000h
+ jnb short loc_4CCFCD
+ mov edx, [esp+4Ch+arg_8]
+ cmp edx, [esp+4Ch+var_3C]
+ jz loc_4CD6E2
+ add [esp+4Ch+arg_8], 1
+
+loc_4CCFCD: ; CODE XREF: sub_4CCC80+C6j
+ ; sub_4CCC80+338j
+ mov eax, [esp+4Ch+arg_8]
+ sub eax, [esp+4Ch+arg_4]
+ mov ecx, [esp+4Ch+arg_C]
+ mov edx, [esp+4Ch+var_2C]
+ pop edi
+ mov [ecx], eax
+ mov eax, [esp+48h+arg_18]
+ pop esi
+ pop ebp
+ mov [eax], edx
+ xor eax, eax
+ pop ebx
+ add esp, 3Ch
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CCFEF: ; CODE XREF: sub_4CCC80+31Cj
+ sub ecx, 6
+ jmp short loc_4CCFA1
+; ---------------------------------------------------------------------------
+
+loc_4CCFF4: ; CODE XREF: sub_4CCC80+129j
+ sub eax, ecx
+ sub esi, ecx
+ mov cx, bx
+ shr cx, 5
+ sub bx, cx
+ cmp eax, 1000000h
+ mov ecx, [esp+4Ch+var_30]
+ mov [ecx], bx
+ jnb short loc_4CD030
+ mov ecx, [esp+4Ch+arg_8]
+ cmp ecx, [esp+4Ch+var_3C]
+ jz loc_4CD6E2
+ movzx ebx, byte ptr [ecx]
+ shl esi, 8
+ shl eax, 8
+ or esi, ebx
+ add ecx, 1
+ mov [esp+4Ch+arg_8], ecx
+
+loc_4CD030: ; CODE XREF: sub_4CCC80+38Ej
+ movzx ebx, word ptr [edi+edx*2+180h]
+ movzx ebp, bx
+ mov ecx, eax
+ shr ecx, 0Bh
+ imul ecx, ebp
+ cmp esi, ecx
+ jnb short loc_4CD096
+ mov eax, ecx
+ mov ecx, 800h
+ sub ecx, ebp
+ sar ecx, 5
+ add ecx, ebx
+ mov [edi+edx*2+180h], cx
+ mov ecx, [esp+4Ch+var_28]
+ mov ebp, [esp+4Ch+var_1C]
+ mov [esp+4Ch+var_18], ecx
+ mov ecx, [esp+4Ch+var_24]
+ mov [esp+4Ch+var_28], ecx
+ mov ecx, [esp+4Ch+var_38]
+ mov [esp+4Ch+var_24], ecx
+ xor ecx, ecx
+ cmp edx, 7
+ setl cl
+ sub ecx, 1
+ and ecx, 3
+ mov [esp+4Ch+var_34], ecx
+ lea ecx, [edi+664h]
+ jmp loc_4CD30B
+; ---------------------------------------------------------------------------
+
+loc_4CD096: ; CODE XREF: sub_4CCC80+3C5j
+ sub eax, ecx
+ sub esi, ecx
+ mov cx, bx
+ shr cx, 5
+ sub bx, cx
+ cmp eax, 1000000h
+ mov [edi+edx*2+180h], bx
+ jnb short loc_4CD0D3
+ mov ecx, [esp+4Ch+arg_8]
+ cmp ecx, [esp+4Ch+var_3C]
+ jz loc_4CD6E2
+ movzx ebx, byte ptr [ecx]
+ shl esi, 8
+ shl eax, 8
+ or esi, ebx
+ add ecx, 1
+ mov [esp+4Ch+arg_8], ecx
+
+loc_4CD0D3: ; CODE XREF: sub_4CCC80+431j
+ movzx ebx, word ptr [edi+edx*2+198h]
+ movzx ebp, bx
+ mov ecx, eax
+ shr ecx, 0Bh
+ imul ecx, ebp
+ cmp esi, ecx
+ mov [esp+4Ch+arg_0], ebx
+ jnb loc_4CD1D3
+ mov ebx, 800h
+ sub ebx, ebp
+ mov ebp, [esp+4Ch+var_1C]
+ sar ebx, 5
+ add ebx, [esp+4Ch+arg_0]
+ mov eax, ecx
+ mov [edi+edx*2+198h], bx
+ lea ebx, [edx+0Fh]
+ shl ebx, 4
+ add ebx, ebp
+ cmp ecx, 1000000h
+ lea ebx, [edi+ebx*2]
+ mov [esp+4Ch+var_30], ebx
+ jnb short loc_4CD147
+ mov ebx, [esp+4Ch+arg_8]
+ cmp ebx, [esp+4Ch+var_3C]
+ jz loc_4CD6E2
+ shl ecx, 8
+ mov eax, ecx
+ movzx ecx, byte ptr [ebx]
+ shl esi, 8
+ or esi, ecx
+ add ebx, 1
+ mov [esp+4Ch+arg_8], ebx
+
+loc_4CD147: ; CODE XREF: sub_4CCC80+4A3j
+ mov ecx, [esp+4Ch+var_30]
+ movzx ecx, word ptr [ecx]
+ mov [esp+4Ch+arg_0], ecx
+ movzx ebx, cx
+ mov ecx, eax
+ shr ecx, 0Bh
+ imul ecx, ebx
+ cmp esi, ecx
+ jnb short loc_4CD1B5
+ mov edi, [esp+4Ch+var_30]
+ mov eax, ecx
+ mov ecx, 800h
+ sub ecx, ebx
+ sar ecx, 5
+ add ecx, [esp+4Ch+arg_0]
+ mov [edi], cx
+ mov edi, [esp+4Ch+var_2C]
+ test edi, edi
+ jz loc_4CD6E2
+ xor ecx, ecx
+ cmp edx, 7
+ mov edx, [esp+4Ch+arg_10]
+ setnl cl
+ lea ecx, [ecx+ecx+9]
+ mov [esp+4Ch+var_34], ecx
+ mov ecx, edi
+ sub ecx, [esp+4Ch+var_38]
+ add edi, 1
+ mov cl, [ecx+edx]
+ mov [edi+edx-1], cl
+ mov byte ptr [esp+4Ch+arg_0], cl
+ mov [esp+4Ch+var_2C], edi
+ jmp loc_4CCFA5
+; ---------------------------------------------------------------------------
+
+loc_4CD1B5: ; CODE XREF: sub_4CCC80+4DFj
+ sub eax, ecx
+ sub esi, ecx
+ mov ecx, [esp+4Ch+arg_0]
+ mov bx, cx
+ shr bx, 5
+ sub cx, bx
+ mov ebx, [esp+4Ch+var_30]
+ mov [ebx], cx
+ jmp loc_4CD2F0
+; ---------------------------------------------------------------------------
+
+loc_4CD1D3: ; CODE XREF: sub_4CCC80+46Cj
+ sub eax, ecx
+ sub esi, ecx
+ mov cx, bx
+ shr cx, 5
+ sub bx, cx
+ cmp eax, 1000000h
+ mov [edi+edx*2+198h], bx
+ jnb short loc_4CD210
+ mov ecx, [esp+4Ch+arg_8]
+ cmp ecx, [esp+4Ch+var_3C]
+ jz loc_4CD6E2
+ movzx ebx, byte ptr [ecx]
+ shl esi, 8
+ shl eax, 8
+ or esi, ebx
+ add ecx, 1
+ mov [esp+4Ch+arg_8], ecx
+
+loc_4CD210: ; CODE XREF: sub_4CCC80+56Ej
+ movzx ebx, word ptr [edi+edx*2+1B0h]
+ movzx ebp, bx
+ mov ecx, eax
+ shr ecx, 0Bh
+ imul ecx, ebp
+ cmp esi, ecx
+ jnb short loc_4CD246
+ mov eax, ecx
+ mov ecx, 800h
+ sub ecx, ebp
+ sar ecx, 5
+ add ecx, ebx
+ mov [edi+edx*2+1B0h], cx
+ mov ecx, [esp+4Ch+var_24]
+ jmp loc_4CD2E0
+; ---------------------------------------------------------------------------
+
+loc_4CD246: ; CODE XREF: sub_4CCC80+5A5j
+ sub eax, ecx
+ sub esi, ecx
+ mov cx, bx
+ shr cx, 5
+ sub bx, cx
+ cmp eax, 1000000h
+ mov [edi+edx*2+1B0h], bx
+ jnb short loc_4CD283
+ mov ecx, [esp+4Ch+arg_8]
+ cmp ecx, [esp+4Ch+var_3C]
+ jz loc_4CD6E2
+ movzx ebx, byte ptr [ecx]
+ shl esi, 8
+ shl eax, 8
+ or esi, ebx
+ add ecx, 1
+ mov [esp+4Ch+arg_8], ecx
+
+loc_4CD283: ; CODE XREF: sub_4CCC80+5E1j
+ movzx ebx, word ptr [edi+edx*2+1C8h]
+ movzx ebp, bx
+ mov ecx, eax
+ shr ecx, 0Bh
+ imul ecx, ebp
+ cmp esi, ecx
+ jnb short loc_4CD2B6
+ mov eax, ecx
+ mov ecx, 800h
+ sub ecx, ebp
+ sar ecx, 5
+ add ecx, ebx
+ mov [edi+edx*2+1C8h], cx
+ mov ecx, [esp+4Ch+var_28]
+ jmp short loc_4CD2D8
+; ---------------------------------------------------------------------------
+
+loc_4CD2B6: ; CODE XREF: sub_4CCC80+618j
+ sub eax, ecx
+ sub esi, ecx
+ mov cx, bx
+ shr cx, 5
+ sub bx, cx
+ mov ecx, [esp+4Ch+var_18]
+ mov [edi+edx*2+1C8h], bx
+ mov ebx, [esp+4Ch+var_28]
+ mov [esp+4Ch+var_18], ebx
+
+loc_4CD2D8: ; CODE XREF: sub_4CCC80+634j
+ mov ebx, [esp+4Ch+var_24]
+ mov [esp+4Ch+var_28], ebx
+
+loc_4CD2E0: ; CODE XREF: sub_4CCC80+5C1j
+ mov ebx, [esp+4Ch+var_38]
+ mov ebp, [esp+4Ch+var_1C]
+ mov [esp+4Ch+var_24], ebx
+ mov [esp+4Ch+var_38], ecx
+
+loc_4CD2F0: ; CODE XREF: sub_4CCC80+54Ej
+ xor ecx, ecx
+ cmp edx, 7
+ setnl cl
+ sub ecx, 1
+ and ecx, 0FFFFFFFDh
+ add ecx, 0Bh
+ mov [esp+4Ch+var_34], ecx
+ lea ecx, [edi+0A68h]
+
+loc_4CD30B: ; CODE XREF: sub_4CCC80+411j
+ cmp eax, 1000000h
+ jnb short loc_4CD332
+ mov edx, [esp+4Ch+arg_8]
+ cmp edx, [esp+4Ch+var_3C]
+ jz loc_4CD6E2
+ movzx edi, byte ptr [edx]
+ shl esi, 8
+ shl eax, 8
+ or esi, edi
+ add edx, 1
+ mov [esp+4Ch+arg_8], edx
+
+loc_4CD332: ; CODE XREF: sub_4CCC80+690j
+ movzx edi, word ptr [ecx]
+ movzx ebx, di
+ mov edx, eax
+ shr edx, 0Bh
+ imul edx, ebx
+ cmp esi, edx
+ jnb short loc_4CD36E
+ mov eax, edx
+ mov edx, 800h
+ sub edx, ebx
+ sar edx, 5
+ add edx, edi
+ mov [ecx], dx
+ shl ebp, 4
+ lea ecx, [ecx+ebp+4]
+ mov [esp+4Ch+var_1C], 0
+ mov edx, 3
+ jmp loc_4CD409
+; ---------------------------------------------------------------------------
+
+loc_4CD36E: ; CODE XREF: sub_4CCC80+6C2j
+ sub eax, edx
+ sub esi, edx
+ mov dx, di
+ shr dx, 5
+ sub di, dx
+ cmp eax, 1000000h
+ mov [ecx], di
+ jnb short loc_4CD3A6
+ mov edx, [esp+4Ch+arg_8]
+ cmp edx, [esp+4Ch+var_3C]
+ jz loc_4CD6E2
+ movzx edi, byte ptr [edx]
+ shl esi, 8
+ shl eax, 8
+ or esi, edi
+ add edx, 1
+ mov [esp+4Ch+arg_8], edx
+
+loc_4CD3A6: ; CODE XREF: sub_4CCC80+704j
+ movzx edx, word ptr [ecx+2]
+ movzx ebx, dx
+ mov edi, eax
+ shr edi, 0Bh
+ imul edi, ebx
+ cmp esi, edi
+ jnb short loc_4CD3E4
+ mov eax, edi
+ mov edi, 800h
+ sub edi, ebx
+ sar edi, 5
+ add edi, edx
+ shl ebp, 4
+ mov [ecx+2], di
+ lea ecx, [ecx+ebp+104h]
+ mov [esp+4Ch+var_1C], 8
+ mov edx, 3
+ jmp short loc_4CD409
+; ---------------------------------------------------------------------------
+
+loc_4CD3E4: ; CODE XREF: sub_4CCC80+737j
+ sub eax, edi
+ sub esi, edi
+ mov di, dx
+ shr di, 5
+ sub dx, di
+ mov [ecx+2], dx
+ add ecx, 204h
+ mov [esp+4Ch+var_1C], 10h
+ mov edx, 8
+
+loc_4CD409: ; CODE XREF: sub_4CCC80+6E9j
+ ; sub_4CCC80+762j
+ mov [esp+4Ch+arg_0], edx
+ mov [esp+4Ch+var_10], edx
+ mov ebx, 1
+ jmp short loc_4CD420
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CD420: ; CODE XREF: sub_4CCC80+796j
+ ; sub_4CCC80+819j
+ cmp eax, 1000000h
+ mov edx, [esp+4Ch+arg_8]
+ lea edi, [ebx+ebx]
+ mov [esp+4Ch+var_30], edi
+ jnb short loc_4CD44E
+ cmp edx, [esp+4Ch+var_3C]
+ jz loc_4CD6E2
+ movzx ebp, byte ptr [edx]
+ shl esi, 8
+ shl eax, 8
+ or esi, ebp
+ add edx, 1
+ mov [esp+4Ch+arg_8], edx
+
+loc_4CD44E: ; CODE XREF: sub_4CCC80+7B0j
+ movzx edi, word ptr [edi+ecx]
+ movzx ebp, di
+ mov edx, eax
+ shr edx, 0Bh
+ imul edx, ebp
+ cmp esi, edx
+ jnb short loc_4CD47B
+ mov eax, edx
+ mov edx, 800h
+ sub edx, ebp
+ sar edx, 5
+ add edx, edi
+ mov edi, [esp+4Ch+var_30]
+ mov [edi+ecx], dx
+ add ebx, ebx
+ jmp short loc_4CD494
+; ---------------------------------------------------------------------------
+
+loc_4CD47B: ; CODE XREF: sub_4CCC80+7DFj
+ mov ebx, [esp+4Ch+var_30]
+ sub eax, edx
+ sub esi, edx
+ mov dx, di
+ shr dx, 5
+ sub di, dx
+ mov [ebx+ecx], di
+ add ebx, 1
+
+loc_4CD494: ; CODE XREF: sub_4CCC80+7F9j
+ sub [esp+4Ch+var_10], 1
+ jnz short loc_4CD420
+ mov ecx, [esp+4Ch+arg_0]
+ mov edx, 1
+ shl edx, cl
+ mov ecx, [esp+4Ch+var_1C]
+ sub ecx, edx
+ add ebx, ecx
+ cmp [esp+4Ch+var_34], 4
+ mov [esp+4Ch+var_4], ebx
+ jge loc_4CD69D
+ add [esp+4Ch+var_34], 7
+ cmp ebx, 4
+ jl short loc_4CD4CC
+ mov ebx, 3
+
+loc_4CD4CC: ; CODE XREF: sub_4CCC80+845j
+ mov ecx, [esp+4Ch+var_20]
+ shl ebx, 7
+ lea ecx, [ebx+ecx+360h]
+ mov [esp+4Ch+var_30], ecx
+ mov [esp+4Ch+arg_0], 6
+ mov edi, 1
+ jmp short loc_4CD4F0
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CD4F0: ; CODE XREF: sub_4CCC80+86Bj
+ ; sub_4CCC80+8E3j
+ cmp eax, 1000000h
+ mov edx, [esp+4Ch+arg_8]
+ lea ebx, [edi+edi]
+ jnb short loc_4CD51A
+ cmp edx, [esp+4Ch+var_3C]
+ jz loc_4CD6E2
+ movzx ebp, byte ptr [edx]
+ shl esi, 8
+ shl eax, 8
+ or esi, ebp
+ add edx, 1
+ mov [esp+4Ch+arg_8], edx
+
+loc_4CD51A: ; CODE XREF: sub_4CCC80+87Cj
+ movzx edx, word ptr [ebx+ecx]
+ movzx ebp, dx
+ mov ecx, eax
+ shr ecx, 0Bh
+ imul ecx, ebp
+ cmp esi, ecx
+ jnb short loc_4CD545
+ mov eax, ecx
+ mov ecx, 800h
+ sub ecx, ebp
+ sar ecx, 5
+ add ecx, edx
+ mov [esp+4Ch+var_10], ecx
+ mov edx, ecx
+ add edi, edi
+ jmp short loc_4CD556
+; ---------------------------------------------------------------------------
+
+loc_4CD545: ; CODE XREF: sub_4CCC80+8ABj
+ sub eax, ecx
+ sub esi, ecx
+ mov cx, dx
+ shr cx, 5
+ sub dx, cx
+ lea edi, [ebx+1]
+
+loc_4CD556: ; CODE XREF: sub_4CCC80+8C3j
+ sub [esp+4Ch+arg_0], 1
+ mov ecx, [esp+4Ch+var_30]
+ mov [ebx+ecx], dx
+ jnz short loc_4CD4F0
+ sub edi, 40h
+ cmp edi, 4
+ jl loc_4CD68A
+ mov ebx, 1
+ mov ecx, edi
+ mov edx, edi
+ sar ecx, 1
+ and edx, ebx
+ sub ecx, ebx
+ or edx, 2
+ cmp edi, 0Eh
+ mov [esp+4Ch+var_30], ecx
+ jge short loc_4CD5A1
+ shl edx, cl
+ mov ecx, [esp+4Ch+var_20]
+ mov [esp+4Ch+var_38], edx
+ sub edx, edi
+ lea ebp, [ecx+edx*2+55Eh]
+ jmp short loc_4CD5F3
+; ---------------------------------------------------------------------------
+
+loc_4CD5A1: ; CODE XREF: sub_4CCC80+90Aj
+ mov edi, [esp+4Ch+arg_8]
+ sub ecx, 4
+
+loc_4CD5A8: ; CODE XREF: sub_4CCC80+958j
+ cmp eax, 1000000h
+ jnb short loc_4CD5CA
+ cmp edi, [esp+4Ch+var_3C]
+ jz loc_4CD6EF
+ movzx ebp, byte ptr [edi]
+ shl esi, 8
+ shl eax, 8
+ or esi, ebp
+ add edi, ebx
+ mov [esp+4Ch+arg_8], edi
+
+loc_4CD5CA: ; CODE XREF: sub_4CCC80+92Dj
+ shr eax, 1
+ add edx, edx
+ cmp esi, eax
+ jb short loc_4CD5D6
+ sub esi, eax
+ or edx, ebx
+
+loc_4CD5D6: ; CODE XREF: sub_4CCC80+950j
+ sub ecx, ebx
+ jnz short loc_4CD5A8
+ mov ebp, [esp+4Ch+var_20]
+ add ebp, 644h
+ shl edx, 4
+ mov [esp+4Ch+var_38], edx
+ mov [esp+4Ch+var_30], 4
+
+loc_4CD5F3: ; CODE XREF: sub_4CCC80+91Fj
+ mov [esp+4Ch+var_1C], ebx
+ mov [esp+4Ch+arg_0], ebx
+ jmp short loc_4CD600
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CD600: ; CODE XREF: sub_4CCC80+97Bj
+ ; sub_4CCC80+A02j
+ mov ebx, [esp+4Ch+arg_0]
+ add ebx, ebx
+ cmp eax, 1000000h
+ jnb short loc_4CD62D
+ mov ecx, [esp+4Ch+arg_8]
+ cmp ecx, [esp+4Ch+var_3C]
+ jz loc_4CD6E2
+ movzx edx, byte ptr [ecx]
+ shl esi, 8
+ shl eax, 8
+ or esi, edx
+ add ecx, 1
+ mov [esp+4Ch+arg_8], ecx
+
+loc_4CD62D: ; CODE XREF: sub_4CCC80+98Bj
+ movzx edi, word ptr [ebx+ebp]
+ movzx ecx, di
+ mov edx, eax
+ shr edx, 0Bh
+ imul edx, ecx
+ cmp esi, edx
+ jnb short loc_4CD658
+ mov eax, edx
+ mov edx, 800h
+ sub edx, ecx
+ sar edx, 5
+ add edx, edi
+ shl [esp+4Ch+arg_0], 1
+ mov [ebx+ebp], dx
+ jmp short loc_4CD679
+; ---------------------------------------------------------------------------
+
+loc_4CD658: ; CODE XREF: sub_4CCC80+9BEj
+ mov cx, di
+ shr cx, 5
+ sub di, cx
+ sub eax, edx
+ sub esi, edx
+ mov edx, [esp+4Ch+var_1C]
+ mov [ebx+ebp], di
+ add ebx, 1
+ or [esp+4Ch+var_38], edx
+ mov [esp+4Ch+arg_0], ebx
+
+loc_4CD679: ; CODE XREF: sub_4CCC80+9D6j
+ shl [esp+4Ch+var_1C], 1
+ sub [esp+4Ch+var_30], 1
+ jnz loc_4CD600
+ jmp short loc_4CD68E
+; ---------------------------------------------------------------------------
+
+loc_4CD68A: ; CODE XREF: sub_4CCC80+8EBj
+ mov [esp+4Ch+var_38], edi
+
+loc_4CD68E: ; CODE XREF: sub_4CCC80+A08j
+ add [esp+4Ch+var_38], 1
+ jz loc_4CCFB3
+ mov ebx, [esp+4Ch+var_4]
+
+loc_4CD69D: ; CODE XREF: sub_4CCC80+837j
+ mov ebp, [esp+4Ch+var_2C]
+ mov ecx, [esp+4Ch+var_38]
+ add ebx, 2
+ cmp ecx, ebp
+ ja short loc_4CD6E2
+ mov edi, ebp
+ sub edi, ecx
+ add edi, [esp+4Ch+arg_10]
+
+loc_4CD6B4: ; CODE XREF: sub_4CCC80+A60j
+ mov cl, [edi]
+ mov edx, [esp+4Ch+arg_10]
+ sub ebx, 1
+ mov [edx+ebp], cl
+ add ebp, 1
+ add edi, 1
+ test ebx, ebx
+ mov byte ptr [esp+4Ch+arg_0], cl
+ mov [esp+4Ch+var_2C], ebp
+ jz loc_4CCFA5
+ cmp ebp, [esp+4Ch+arg_14]
+ jnb loc_4CCFB3
+ jmp short loc_4CD6B4
+; ---------------------------------------------------------------------------
+
+loc_4CD6E2: ; CODE XREF: sub_4CCC80+101j
+ ; sub_4CCC80+1C9j ...
+ pop edi
+ pop esi
+ pop ebp
+ mov eax, 1
+ pop ebx
+ add esp, 3Ch
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CD6EF: ; CODE XREF: sub_4CCC80+933j
+ pop edi
+ pop esi
+ pop ebp
+ mov eax, ebx
+ pop ebx
+ add esp, 3Ch
+ retn
+sub_4CCC80 endp
+
+_starcraft_decompress_lzma PROC
+;sub_4CD700
+
+var_14 = byte ptr -14h
+var_10 = dword ptr -10h
+var_C = dword ptr -0Ch
+var_4 = dword ptr -4
+pbInBuffer = dword ptr 4
+cbInBuffer = dword ptr 8
+pbOutBuffer = dword ptr 0Ch
+cbOutBuffer = dword ptr 10h
+pcbOutBuffer = dword ptr 14h
+pfnAllocateMemory= dword ptr 18h
+pfnFreeMemory = dword ptr 1Ch
+
+ sub esp, 14h
+ push ebx
+ mov ebx, [esp+18h+cbInBuffer]
+ cmp ebx, 0Eh ; LZMA_PROPS_SIZE + 8
+ jnb short loc_4CD714
+ xor al, al
+ pop ebx
+ add esp, 14h
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CD714: ; CODE XREF: Decompress_lzma_internal+Bj
+ push ebp
+ mov ebp, [esp+1Ch+pcbOutBuffer]
+ push edi
+ mov edi, [esp+20h+pbInBuffer]
+ mov dword ptr [ebp+0], 0
+ cmp byte ptr [edi], 0
+ jnz short loc_4CD741
+ push 5
+ lea eax, [edi+1]
+ push eax
+ lea ecx, [esp+28h+var_10]
+ push ecx
+ call LzmaProps_Decode
+ add esp, 0Ch
+ test eax, eax
+ jz short loc_4CD74A
+
+loc_4CD741: ; CODE XREF: Decompress_lzma_internal+28j
+ pop edi
+ pop ebp
+ xor al, al
+ pop ebx
+ add esp, 14h
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CD74A: ; CODE XREF: Decompress_lzma_internal+3Fj
+ mov edx, [esp+20h+var_10]
+ mov eax, [esp+20h+var_C]
+ lea ecx, [eax+edx]
+ mov edx, 300h
+ shl edx, cl
+ push esi
+ lea eax, [edx+edx+0E6Ch]
+ push eax
+ call [esp+28h+pfnAllocateMemory]
+ mov esi, eax
+ add esp, 4
+ test esi, esi
+ mov [esp+24h+var_4], esi
+ jz short loc_4CD7AA
+ mov edx, [esp+24h+cbOutBuffer]
+ mov eax, [esp+24h+pbOutBuffer]
+ lea ecx, [esp+24h+cbInBuffer]
+ push ecx ; cbInBuffer
+ push edx ; cbOutBuffer
+ push eax ; pbOutBuffer
+ lea ecx, [esp+30h+var_14]
+ push ecx ; &var_14
+ add ebx, 0FFFFFFF2h
+ push ebx ; cbInBuffer - LZMA86_HEADER_SIZE
+ add edi, 0Eh
+ lea edx, [esp+38h+var_10]
+ push edi ; pbInBuffer + LZMA86_HEADER_SIZE
+ push edx ; dest
+ call sub_4CCC80
+ push esi
+ mov edi, eax
+ call [esp+44h+pfnFreeMemory]
+ add esp, 20h
+ test edi, edi
+ jz short loc_4CD7B4
+
+loc_4CD7AA: ; CODE XREF: Decompress_lzma_internal+74j
+ pop esi
+ pop edi
+ pop ebp
+ xor al, al
+ pop ebx
+ add esp, 14h
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CD7B4: ; CODE XREF: Decompress_lzma_internal+A8j
+ mov eax, [esp+24h+cbInBuffer]
+ pop esi
+ pop edi
+ mov [ebp+0], eax
+ pop ebp
+ mov al, 1
+ pop ebx
+ add esp, 14h
+ retn
+_starcraft_decompress_lzma ENDP
+
+; =============== S U B R O U T I N E =======================================
+
+sub_4CD7D0 proc near ; CODE XREF: sub_4CDC00+74p
+
+arg_0 = dword ptr 4
+
+ push esi
+ mov esi, [esp+4+arg_0]
+ or esi, 8
+ xor eax, eax
+ cmp esi, 1
+ jz short loc_4CD806
+ push edi
+
+loc_4CD7E0: ; CODE XREF: sub_4CD7D0+33j
+ mov edx, esi
+ shr esi, 1
+ mov edi, [ecx+esi*4]
+ and edx, 1
+ sub edi, edx
+ neg edx
+ xor edi, edx
+ shr edi, 2
+ and edi, 1FFh
+ add eax, dword_550998[edi*4]
+ cmp esi, 1
+ jnz short loc_4CD7E0
+ pop edi
+
+loc_4CD806: ; CODE XREF: sub_4CD7D0+Dj
+ pop esi
+ retn 4
+sub_4CD7D0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CD810 proc near ; CODE XREF: CEncoder_FillAlignPrices+17p
+
+var_4 = dword ptr -4
+arg_0 = dword ptr 4
+
+ push ecx
+ push ebx
+ push ebp
+ push esi
+ xor eax, eax
+ push edi
+ mov edi, [esp+14h+arg_0]
+ mov [esp+14h+var_4], ecx
+ lea esi, [eax+1]
+ lea ebx, [eax+4]
+
+loc_4CD825: ; CODE XREF: sub_4CD810+42j
+ mov ecx, [esp+14h+var_4]
+ mov ecx, [ecx+esi*4]
+ mov edx, edi
+ and edx, 1
+ sub ecx, edx
+ mov ebp, edx
+ neg ebp
+ xor ecx, ebp
+ shr ecx, 2
+ and ecx, 1FFh
+ add eax, dword_550998[ecx*4]
+ add esi, esi
+ shr edi, 1
+ or esi, edx
+ sub ebx, 1
+ jnz short loc_4CD825
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ pop ecx
+ retn 4
+sub_4CD810 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CD860 proc near ; CODE XREF: CEncoder_FillDistancesPrices+6Bp
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+
+ push edi
+ mov edi, [esp+4+arg_4]
+ xor eax, eax
+ test edi, edi
+ lea edx, [eax+1]
+ jz short loc_4CD8A7
+ push ebx
+ push ebp
+ push esi
+ mov esi, [esp+10h+arg_8]
+
+loc_4CD875: ; CODE XREF: sub_4CD860+42j
+ mov ebx, [esp+10h+arg_0]
+ mov ebx, [ebx+edx*4]
+ mov ecx, esi
+ and ecx, 1
+ sub ebx, ecx
+ mov ebp, ecx
+ neg ebp
+ xor ebx, ebp
+ shr ebx, 2
+ and ebx, 1FFh
+ add eax, dword_550998[ebx*4]
+ add edx, edx
+ shr esi, 1
+ or edx, ecx
+ sub edi, 1
+ jnz short loc_4CD875
+ pop esi
+ pop ebp
+ pop ebx
+
+loc_4CD8A7: ; CODE XREF: sub_4CD860+Cj
+ pop edi
+ retn
+sub_4CD860 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CD8B0 proc near ; CODE XREF: CEncoder_CodeOneBlock+7B8p
+ mov eax, [ecx+24h]
+ mov edx, [ecx+1Ch]
+ push ebx
+ push esi
+ mov esi, [ecx+30h]
+ xor ebx, ebx
+ push edi
+ mov edi, [ecx+34h]
+ sub esi, eax
+ sbb edi, ebx
+ add esi, edx
+ adc edi, ebx
+ cmp eax, edx
+ jbe short loc_4CD8D4
+ mov eax, [ecx+28h]
+ add esi, eax
+ adc edi, ebx
+
+loc_4CD8D4: ; CODE XREF: sub_4CD8B0+1Bj
+ mov eax, [ecx]
+ xor edx, edx
+ add eax, esi
+ adc edx, edi
+ pop edi
+ add eax, 4
+ pop esi
+ adc edx, ebx
+ pop ebx
+ retn
+sub_4CD8B0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CD8F0 proc near ; CODE XREF: sub_4CD940+21p
+ ; .text:loc_4CF730j ...
+ mov eax, dword_553598
+ test eax, eax
+ push esi
+ mov esi, ecx
+ push edi
+ mov edi, [esi]
+ jnz short loc_4CD92A
+ push 0Ch ; Size
+ call _operator_new ; operator new(uint)
+ add esp, 4
+ test eax, eax
+ jz short loc_4CD923
+ mov dword ptr [eax], 0
+ mov dword ptr [eax+4], 0
+ mov dword ptr [eax+8], 0
+ jmp short loc_4CD925
+; ---------------------------------------------------------------------------
+
+loc_4CD923: ; CODE XREF: sub_4CD8F0+1Bj
+ xor eax, eax
+
+loc_4CD925: ; CODE XREF: sub_4CD8F0+31j
+ mov dword_553598, eax
+
+loc_4CD92A: ; CODE XREF: sub_4CD8F0+Dj
+ mov eax, [eax+4]
+ test eax, eax
+ jz short loc_4CD937
+ push edi
+ call eax
+ add esp, 4
+
+loc_4CD937: ; CODE XREF: sub_4CD8F0+3Fj
+ pop edi
+ mov dword ptr [esi], 0
+ pop esi
+ retn
+sub_4CD8F0 endp
+
+; =============== S U B R O U T I N E =======================================
+
+sub_4CD940 proc near ; CODE XREF: sub_4D0270+74p
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ push ebx
+ mov ebx, [esp+4+arg_4]
+ push esi
+ mov esi, ecx
+ cmp dword ptr [esi], 0
+ push edi
+ mov edi, [esp+0Ch+arg_0]
+ jz short loc_4CD95F
+ mov eax, [esi+8]
+ add eax, [esi+4]
+ lea ecx, [edi+ebx]
+ cmp ecx, eax
+ jz short loc_4CD981
+
+loc_4CD95F: ; CODE XREF: sub_4CD940+10j
+ mov ecx, esi
+ call sub_4CD8F0
+ lea ecx, [edi+ebx]
+ mov edx, 1
+ shl edx, cl
+ imul edx, 0C00h
+ push edx
+ call sub_4CB8A0
+ add esp, 4
+ mov [esi], eax
+
+loc_4CD981: ; CODE XREF: sub_4CD940+1Dj
+ mov ecx, edi
+ mov eax, 1
+ shl eax, cl
+ mov [esi+8], edi
+ pop edi
+ mov [esi+4], ebx
+ sub eax, 1
+ mov [esi+0Ch], eax
+ xor eax, eax
+ cmp [esi], eax
+ pop esi
+ setnz al
+ pop ebx
+ retn 8
+sub_4CD940 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CD9B0 proc near ; CODE XREF: CEncoder_GetOptimum+436p
+ ; CEncoder_GetOptimum+AE1p
+
+arg_0 = dword ptr 4
+arg_4 = byte ptr 8
+arg_8 = dword ptr 0Ch
+
+ mov edx, [esp+arg_0]
+ test edx, edx
+ push esi
+ jnz short loc_4CD9F2
+ movzx eax, [esp+4+arg_4]
+ mov edx, eax
+ shl edx, 4
+ add edx, [esp+4+arg_8]
+ mov esi, 800h
+ sub esi, [ecx+edx*4+284B0h]
+ mov ecx, [ecx+eax*4+28420h]
+ shr esi, 2
+ mov eax, dword_550998[esi*4]
+ shr ecx, 2
+ add eax, dword_550998[ecx*4]
+ pop esi
+ retn 0Ch
+; ---------------------------------------------------------------------------
+
+loc_4CD9F2: ; CODE XREF: sub_4CD9B0+7j
+ movzx esi, [esp+4+arg_4]
+ mov eax, 800h
+ sub eax, [ecx+esi*4+28420h]
+ shr eax, 2
+ cmp edx, 1
+ mov eax, dword_550998[eax*4]
+ jnz short loc_4CDA27
+ mov ecx, [ecx+esi*4+28450h]
+ shr ecx, 2
+ add eax, dword_550998[ecx*4]
+ pop esi
+ retn 0Ch
+; ---------------------------------------------------------------------------
+
+loc_4CDA27: ; CODE XREF: sub_4CD9B0+60j
+ push edi
+ add edx, 0FFFFFFFEh
+ mov edi, 800h
+ sub edi, [ecx+esi*4+28450h]
+ mov ecx, [ecx+esi*4+28480h]
+ sub ecx, edx
+ neg edx
+ xor ecx, edx
+ shr edi, 2
+ mov edx, dword_550998[edi*4]
+ shr ecx, 2
+ and ecx, 1FFh
+ add edx, dword_550998[ecx*4]
+ pop edi
+ add eax, edx
+ pop esi
+ retn 0Ch
+sub_4CD9B0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CDA70 proc near ; CODE XREF: CEncoder_CodeReal+10Cp
+ ; CEncoder_CodeReal+134p ...
+ push esi
+ mov esi, [ecx]
+ cmp dword ptr [esi+80h], 0
+ jz short loc_4CDA8C
+ cmp byte ptr [esi+33B95h], 0
+ jz short loc_4CDA8C
+ mov byte ptr [esi+33B95h], 0
+
+loc_4CDA8C: ; CODE XREF: sub_4CDA70+Aj
+ ; sub_4CDA70+13j
+ mov eax, [esi+33B8Ch]
+ test eax, eax
+ jz short loc_4CDAA8
+ mov ecx, [eax]
+ mov edx, [ecx+8]
+ push eax
+ call edx
+ mov dword ptr [esi+33B8Ch], 0
+
+loc_4CDAA8: ; CODE XREF: sub_4CDA70+24j
+ mov ecx, [esi+4]
+ mov edx, [ecx+10h]
+ lea eax, [esi+4]
+ push eax
+ call edx
+ pop esi
+ retn
+sub_4CDA70 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CDAC0 proc near ; CODE XREF: CEncoder_GetOptimum+2C4p
+ ; CEncoder_GetOptimum+7ACp ...
+
+var_4 = dword ptr -4
+arg_0 = dword ptr 4
+arg_4 = byte ptr 8
+arg_8 = byte ptr 0Ch
+
+ push ecx
+ push ebx
+ push ebp
+ xor ebp, ebp
+ cmp byte ptr [esp+0Ch+arg_0], 0
+ push esi
+ mov eax, ecx
+ push edi
+ mov [esp+14h+var_4], eax
+ lea edi, [ebp+1]
+ lea ebx, [ebp+8]
+ jz short loc_4CDB3B
+ movzx ecx, [esp+14h+arg_8]
+ mov [esp+14h+arg_0], ecx
+
+loc_4CDAE3: ; CODE XREF: sub_4CDAC0+71j
+ movzx esi, [esp+14h+arg_4]
+ mov edx, [esp+14h+arg_0]
+ sub ebx, 1
+ movzx ecx, bl
+ shr esi, cl
+ shr edx, cl
+ and esi, 1
+ mov ecx, esi
+ shl ecx, 8
+ add ecx, edi
+ mov eax, [eax+ecx*4+400h]
+ and edx, 1
+ sub eax, edx
+ mov ecx, edx
+ neg ecx
+ xor eax, ecx
+ shr eax, 2
+ and eax, 1FFh
+ add ebp, dword_550998[eax*4]
+ add edi, edi
+ or edi, edx
+ cmp esi, edx
+ jnz short loc_4CDB33
+ test ebx, ebx
+ jz short loc_4CDB75
+ mov eax, [esp+14h+var_4]
+ jmp short loc_4CDAE3
+; ---------------------------------------------------------------------------
+
+loc_4CDB33: ; CODE XREF: sub_4CDAC0+67j
+ test ebx, ebx
+ jz short loc_4CDB75
+ mov eax, [esp+14h+var_4]
+
+loc_4CDB3B: ; CODE XREF: sub_4CDAC0+18j
+ movzx edx, [esp+14h+arg_8]
+ mov [esp+14h+arg_0], edx
+
+loc_4CDB44: ; CODE XREF: sub_4CDAC0+B3j
+ mov edx, [esp+14h+arg_0]
+ sub ebx, 1
+ mov cl, bl
+ shr edx, cl
+ mov ecx, [eax+edi*4]
+ add edi, edi
+ and edx, 1
+ sub ecx, edx
+ mov esi, edx
+ neg esi
+ xor ecx, esi
+ shr ecx, 2
+ and ecx, 1FFh
+ add ebp, dword_550998[ecx*4]
+ or edi, edx
+ test ebx, ebx
+ jnz short loc_4CDB44
+
+loc_4CDB75: ; CODE XREF: sub_4CDAC0+6Bj
+ ; sub_4CDAC0+75j
+ pop edi
+ pop esi
+ mov eax, ebp
+ pop ebp
+ pop ebx
+ pop ecx
+ retn 0Ch
+sub_4CDAC0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CDB80 proc near ; CODE XREF: sub_4CDEA0+11Ep
+ ; sub_4CDEA0+137p
+
+arg_0 = dword ptr 4
+
+ push esi
+ mov esi, [esp+4+arg_0]
+ test esi, esi
+ mov edx, 400h
+ push edi
+ mov [ecx], edx
+ mov [ecx+4], edx
+ jbe short loc_4CDBE6
+ lea eax, [ecx+20Ch]
+ lea ebx, [ebx+0]
+
+loc_4CDBA0: ; CODE XREF: sub_4CDB80+64j
+ mov [eax-200h], edx
+ mov [eax-1FCh], edx
+ mov [eax-1F8h], edx
+ mov [eax-1F4h], edx
+ mov [eax-1F0h], edx
+ mov [eax-1ECh], edx
+ mov [eax-1E8h], edx
+ mov [eax], edx
+ mov [eax+4], edx
+ mov [eax+8], edx
+ mov [eax+0Ch], edx
+ mov [eax+10h], edx
+ mov [eax+14h], edx
+ mov [eax+18h], edx
+ add eax, 20h
+ sub esi, 1
+ jnz short loc_4CDBA0
+
+loc_4CDBE6: ; CODE XREF: sub_4CDB80+12j
+ lea edi, [ecx+40Ch]
+ mov ecx, 0FFh
+ mov eax, edx
+ rep stosd
+ pop edi
+ pop esi
+ retn 4
+sub_4CDB80 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CDC00 proc near ; CODE XREF: sub_4CF740+22p
+ ; sub_4CF780+2Bp
+
+var_C = dword ptr -0Ch
+var_8 = dword ptr -8
+var_4 = dword ptr -4
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+
+ sub esp, 0Ch
+ push ebx
+ push ebp
+ push esi
+ push edi
+ mov edi, ecx
+ mov eax, [edi]
+ mov ebx, [esp+1Ch+arg_0]
+ mov ecx, eax
+ shr ecx, 2
+ mov edx, dword_550998[ecx*4]
+ mov ecx, 800h
+ sub ecx, eax
+ shr ecx, 2
+ mov eax, dword_550998[ecx*4]
+ mov ecx, [edi+4]
+ mov [esp+1Ch+var_C], edx
+ mov edx, ecx
+ shr edx, 2
+ mov ebp, dword_550998[edx*4]
+ mov edx, 800h
+ sub edx, ecx
+ shr edx, 2
+ mov ecx, dword_550998[edx*4]
+ add ebp, eax
+ add ecx, eax
+ mov [esp+1Ch+var_8], ebp
+ mov [esp+1Ch+var_4], ecx
+ xor esi, esi
+ mov edi, edi
+
+loc_4CDC60: ; CODE XREF: sub_4CDC00+8Aj
+ cmp esi, [esp+1Ch+arg_4]
+ jnb loc_4CDD62
+ mov eax, ebx
+ shl eax, 5
+ push esi
+ lea ecx, [eax+edi+8]
+ call sub_4CD7D0
+ add eax, [esp+1Ch+var_C]
+ mov ecx, [esp+1Ch+arg_8]
+ mov [ecx+esi*4], eax
+ add esi, 1
+ cmp esi, 8
+ jb short loc_4CDC60
+ cmp esi, 10h
+ jnb short loc_4CDD00
+ lea ecx, [esi-8]
+ mov [esp+1Ch+arg_0], ecx
+ jmp short loc_4CDCA0
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CDCA0: ; CODE XREF: sub_4CDC00+98j
+ ; sub_4CDC00+FEj
+ cmp esi, [esp+1Ch+arg_4]
+ jnb loc_4CDD62
+ or ecx, 8
+ xor edx, edx
+ cmp ecx, 1
+ jz short loc_4CDCE4
+
+loc_4CDCB4: ; CODE XREF: sub_4CDC00+DEj
+ mov eax, ecx
+ shr ecx, 1
+ and eax, 1
+ lea ebp, [ecx+ebx*8]
+ mov ebp, [edi+ebp*4+208h]
+ sub ebp, eax
+ neg eax
+ xor ebp, eax
+ shr ebp, 2
+ and ebp, 1FFh
+ add edx, dword_550998[ebp*4]
+ cmp ecx, 1
+ jnz short loc_4CDCB4
+ mov ebp, [esp+1Ch+var_8]
+
+loc_4CDCE4: ; CODE XREF: sub_4CDC00+B2j
+ mov eax, [esp+1Ch+arg_8]
+ mov ecx, [esp+1Ch+arg_0]
+ add edx, ebp
+ mov [eax+esi*4], edx
+ add esi, 1
+ add ecx, 1
+ cmp esi, 10h
+ mov [esp+1Ch+arg_0], ecx
+ jb short loc_4CDCA0
+
+loc_4CDD00: ; CODE XREF: sub_4CDC00+8Fj
+ cmp esi, [esp+1Ch+arg_4]
+ jnb short loc_4CDD62
+ lea ebx, [esi-10h]
+ lea esp, [esp+0]
+
+loc_4CDD10: ; CODE XREF: sub_4CDC00+160j
+ mov ecx, ebx
+ or ecx, 100h
+ xor edx, edx
+ cmp ecx, 1
+ jz short loc_4CDD49
+ nop
+
+loc_4CDD20: ; CODE XREF: sub_4CDC00+147j
+ mov eax, ecx
+ shr ecx, 1
+ mov ebp, [edi+ecx*4+408h]
+ and eax, 1
+ sub ebp, eax
+ neg eax
+ xor ebp, eax
+ shr ebp, 2
+ and ebp, 1FFh
+ add edx, dword_550998[ebp*4]
+ cmp ecx, 1
+ jnz short loc_4CDD20
+
+loc_4CDD49: ; CODE XREF: sub_4CDC00+11Dj
+ mov ecx, [esp+1Ch+var_4]
+ mov eax, [esp+1Ch+arg_8]
+ add edx, ecx
+ mov [eax+esi*4], edx
+ add esi, 1
+ add ebx, 1
+ cmp esi, [esp+1Ch+arg_4]
+ jb short loc_4CDD10
+
+loc_4CDD62: ; CODE XREF: sub_4CDC00+64j
+ ; sub_4CDC00+A4j ...
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ add esp, 0Ch
+ retn 0Ch
+sub_4CDC00 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+; int __cdecl sub_4CDD70(SIZE_T dwSize)
+sub_4CDD70 proc near ; DATA XREF: .data:off_546E20o
+
+dwSize = dword ptr 4
+
+ mov eax, [esp+dwSize]
+ test eax, eax
+ jnz short loc_4CDD79
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4CDD79: ; CODE XREF: sub_4CDD70+6j
+ push 4 ; flProtect
+ push 1000h ; flAllocationType
+ push eax ; dwSize
+ push 0 ; lpAddress
+ call ds:VirtualAlloc
+ retn
+sub_4CDD70 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+
+; int __cdecl sub_4CDD90(void * lpAddress)
+sub_4CDD90 proc near ; CODE XREF: sub_4CF810+53p
+ ; sub_4CF810+73p
+ ; DATA XREF: ...
+
+lpAddress = dword ptr 4
+
+ mov eax, [esp+lpAddress]
+ test eax, eax
+ jz short locret_4CDDA6
+ push 8000h ; dwFreeType
+ push 0 ; dwSize
+ push eax ; lpAddress
+ call ds:VirtualFree
+
+locret_4CDDA6: ; CODE XREF: sub_4CDD90+6j
+ retn
+sub_4CDD90 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CDDB0 proc near ; DATA XREF: .rdata:00517AC8o
+
+var_10 = dword ptr -10h
+var_C = byte ptr -0Ch
+var_B = byte ptr -0Bh
+var_A = byte ptr -0Ah
+var_9 = byte ptr -9
+var_8 = byte ptr -8
+var_4 = dword ptr -4
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ sub esp, 10h
+ mov eax, dword_544960
+ xor eax, esp
+ mov [esp+10h+var_4], eax
+ mov ecx, [esp+10h+arg_0]
+ mov al, [ecx+33B50h]
+ mov dl, 5
+ imul dl
+ add al, [ecx+33B58h]
+ mov dl, 9
+ imul dl
+ add al, [ecx+33B5Ch]
+ push ebp
+ mov ebp, [esp+14h+arg_4]
+ mov [esp+14h+var_C], al
+ mov eax, [ecx+33B60h]
+ mov ecx, eax
+ mov edx, eax
+ push esi
+ shr ecx, 8
+ shr edx, 10h
+ mov [esp+18h+var_B], al
+ shr eax, 18h
+ push edi
+ mov [esp+1Ch+var_A], cl
+ mov [esp+1Ch+var_9], dl
+ mov [esp+1Ch+var_8], al
+ mov esi, 5
+ lea edi, [esp+1Ch+var_C]
+
+loc_4CDE13: ; CODE XREF: sub_4CDDB0+85j
+ mov eax, [ebp+0]
+ mov edx, [eax+0Ch]
+ lea ecx, [esp+1Ch+var_10]
+ push ecx
+ push esi
+ push edi
+ push ebp
+ call edx
+ mov ecx, [esp+1Ch+var_10]
+ add edi, ecx
+ sub esi, ecx
+ test eax, eax
+ jnz short loc_4CDE37
+ test ecx, ecx
+ jz short loc_4CDE4B
+ test esi, esi
+ jnz short loc_4CDE13
+
+loc_4CDE37: ; CODE XREF: sub_4CDDB0+7Dj
+ pop edi
+ pop esi
+ pop ebp
+ mov ecx, [esp+10h+var_4]
+ xor ecx, esp
+ call sub_4A0686
+ add esp, 10h
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_4CDE4B: ; CODE XREF: sub_4CDDB0+81j
+ mov ecx, [esp+1Ch+var_4]
+ pop edi
+ pop esi
+ pop ebp
+ xor ecx, esp
+ mov eax, 80004005h
+ call sub_4A0686
+ add esp, 10h
+ retn 8
+sub_4CDDB0 endp
+
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+sub_4CDE70 proc near ; DATA XREF: .rdata:00517AF4o
+
+arg_0 = dword ptr 4
+
+ push esi
+ mov esi, [esp+4+arg_0]
+ mov eax, [esi+50h]
+ test eax, eax
+ jz short loc_4CDE8B
+ mov ecx, [eax]
+ mov edx, [ecx+8]
+ push eax
+ call edx
+ mov dword ptr [esi+50h], 0
+
+loc_4CDE8B: ; CODE XREF: sub_4CDE70+Aj
+ xor eax, eax
+ pop esi
+ retn 4
+sub_4CDE70 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CDEA0 proc near ; CODE XREF: CEncoder_SetStreams+3Cp
+
+var_4 = dword ptr -4
+
+ push ecx
+ push ebx
+ xor ebx, ebx
+ push ebp
+ push esi
+ mov esi, ecx
+ mov byte ptr [esi+10h], 0
+ mov byte ptr [esi+11h], 0
+ mov [esi+14h], ebx
+ mov [esi+18h], ebx
+ mov [esi+1Ch], ebx
+ mov [esi+20h], ebx
+ mov eax, [esi+50h]
+ mov [esi+4Ch], ebx
+ mov [esi+48h], eax
+ mov [esi+44h], ebx
+ mov [esi+58h], ebx
+ mov [esi+5Ch], ebx
+ mov [esi+64h], bl
+ push edi
+ mov [esi+30h], ebx
+ mov [esi+34h], ebx
+ mov dword ptr [esi+38h], 0FFFFFFFFh
+ mov dword ptr [esi+28h], 1
+ mov [esi+2Ch], bl
+ lea ecx, [esi+28420h]
+ lea edi, [esi+284B0h]
+ mov [esp+14h+var_4], 0Ch
+ mov ebp, 400h
+
+loc_4CDF02: ; CODE XREF: sub_4CDEA0+9Cj
+ xor edx, edx
+ mov eax, edi
+ jmp short loc_4CDF10
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CDF10: ; CODE XREF: sub_4CDEA0+66j
+ ; sub_4CDEA0+84j
+ mov [eax-3C0h], ebp
+ mov [eax], ebp
+ add edx, 1
+ add eax, 4
+ cmp edx, [esi+33B60h]
+ jbe short loc_4CDF10
+ mov [ecx-30h], ebp
+ mov [ecx], ebp
+ mov [ecx+30h], ebp
+ mov [ecx+60h], ebp
+ add ecx, 4
+ add edi, 40h
+ sub [esp+14h+var_4], 1
+ jnz short loc_4CDF02
+ mov ecx, [esi+32658h]
+ add ecx, [esi+32654h]
+ mov eax, 1
+ shl eax, cl
+ cmp eax, ebx
+ jbe short loc_4CDF7C
+ xor edx, edx
+ mov ebx, eax
+ lea esp, [esp+0]
+
+loc_4CDF60: ; CODE XREF: sub_4CDEA0+DAj
+ mov edi, [esi+32650h]
+ add edi, edx
+ mov ecx, 300h
+ mov eax, ebp
+ add edx, 0C00h
+ sub ebx, 1
+ rep stosd
+ jnz short loc_4CDF60
+
+loc_4CDF7C: ; CODE XREF: sub_4CDEA0+B3j
+ lea edx, [esi+287B4h]
+ mov ebx, 4
+
+loc_4CDF87: ; CODE XREF: sub_4CDEA0+FBj
+ mov edi, edx
+ mov ecx, 3Fh
+ mov eax, ebp
+ add edx, 100h
+ sub ebx, 1
+ rep stosd
+ jnz short loc_4CDF87
+ lea edi, [esi+28BB0h]
+ mov ecx, 72h
+ rep stosd
+ mov ecx, [esi+33B5Ch]
+ mov edx, 1
+ shl edx, cl
+ lea ecx, [esi+28DB8h]
+ push edx
+ call sub_4CDB80
+ mov ecx, [esi+33B5Ch]
+ mov eax, 1
+ shl eax, cl
+ lea ecx, [esi+2DA04h]
+ push eax
+ call sub_4CDB80
+ mov eax, ebp
+ mov [esi+28D7Ch], eax
+ mov [esi+28D80h], eax
+ mov [esi+28D84h], eax
+ mov [esi+28D88h], eax
+ mov [esi+28D8Ch], eax
+ mov [esi+28D90h], eax
+ mov [esi+28D94h], eax
+ mov [esi+28D98h], eax
+ mov [esi+28D9Ch], eax
+ mov [esi+28DA0h], eax
+ mov [esi+28DA4h], eax
+ mov [esi+28DA8h], eax
+ mov [esi+28DACh], eax
+ mov [esi+28DB0h], eax
+ mov [esi+28DB4h], eax
+ xor eax, eax
+ pop edi
+ mov [esi+32F10h], bl
+ mov [esi+32F08h], eax
+ mov [esi+32F0Ch], eax
+ mov [esi+32F04h], eax
+ pop esi
+ pop ebp
+ pop ebx
+ pop ecx
+ retn
+sub_4CDEA0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CF450 proc near ; CODE XREF: .text:004CF692p
+ ; CEncoder_Flush+42p
+
+var_8 = dword ptr -8
+var_4 = dword ptr -4
+
+ sub esp, 8
+ push esi
+ mov esi, ecx
+ mov eax, [esi+0Ch]
+ push edi
+ mov edi, [esi+4]
+ cmp eax, edi
+ jb short loc_4CF464
+ mov edi, [esi+10h]
+
+loc_4CF464: ; CODE XREF: sub_4CF450+Fj
+ push ebp
+ mov ebp, [esi+20h]
+ xor edx, edx
+ sub edi, eax
+ cmp ebp, edx
+ mov [esp+14h+var_4], edx
+ jz short loc_4CF4BA
+ push ebx
+ mov ebx, [esi]
+ add ebx, eax
+ mov eax, dword_553598
+ cmp eax, edx
+ jnz short loc_4CF4A5
+ push 0Ch ; Size
+ call _operator_new ; operator new(uint)
+ xor ecx, ecx
+ add esp, 4
+ cmp eax, ecx
+ jz short loc_4CF49C
+ mov [eax], ecx
+ mov [eax+4], ecx
+ mov [eax+8], ecx
+ jmp short loc_4CF49E
+; ---------------------------------------------------------------------------
+
+loc_4CF49C: ; CODE XREF: sub_4CF450+40j
+ xor eax, eax
+
+loc_4CF49E: ; CODE XREF: sub_4CF450+4Aj
+ mov dword_553598, eax
+ xor edx, edx
+
+loc_4CF4A5: ; CODE XREF: sub_4CF450+30j
+ mov eax, [eax+8]
+ cmp eax, edx
+ jz short loc_4CF4B6
+ push edi
+ push ebx
+ push ebp
+ call eax
+ add esp, 0Ch
+ xor edx, edx
+
+loc_4CF4B6: ; CODE XREF: sub_4CF450+5Aj
+ add [esi+20h], edi
+ pop ebx
+
+loc_4CF4BA: ; CODE XREF: sub_4CF450+22j
+ mov eax, [esi+14h]
+ cmp eax, edx
+ pop ebp
+ jz short loc_4CF4E4
+ mov [esp+10h+var_8], edx
+ mov ecx, [eax]
+ lea edx, [esp+10h+var_8]
+ push edx
+ mov edx, [esi]
+ add edx, [esi+0Ch]
+ push edi
+ push edx
+ push eax
+ mov eax, [ecx+0Ch]
+ call eax
+ mov edi, [esp+10h+var_8]
+ mov [esp+10h+var_4], eax
+ xor edx, edx
+
+loc_4CF4E4: ; CODE XREF: sub_4CF450+70j
+ add [esi+0Ch], edi
+ mov ecx, [esi+0Ch]
+ mov eax, [esi+10h]
+ cmp ecx, eax
+ jnz short loc_4CF4F4
+ mov [esi+0Ch], edx
+
+loc_4CF4F4: ; CODE XREF: sub_4CF450+9Fj
+ cmp [esi+4], eax
+ jnz short loc_4CF500
+ mov byte ptr [esi+24h], 1
+ mov [esi+4], edx
+
+loc_4CF500: ; CODE XREF: sub_4CF450+A7j
+ mov ecx, [esi+0Ch]
+ cmp ecx, [esi+4]
+ jbe short loc_4CF50A
+ mov eax, ecx
+
+loc_4CF50A: ; CODE XREF: sub_4CF450+B6j
+ add [esi+18h], edi
+ mov [esi+8], eax
+ mov eax, [esp+10h+var_4]
+ adc [esi+1Ch], edx
+ pop edi
+ pop esi
+ add esp, 8
+ retn
+sub_4CF450 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+
+; ---------------------------------------------------------------------------
+
+; int __stdcall Interface1_QueryInterface(int, void *Buf1, int)
+Interface1_QueryInterface proc near ; DATA XREF: .rdata:off_517A90o
+; sub_4CF520
+
+arg_0 = dword ptr 4
+Buf1 = dword ptr 8
+arg_8 = dword ptr 0Ch
+
+ mov eax, [esp+Buf1]
+ push offset dword_512730 ; Buf2
+ push eax ; Buf1
+ call unknown_libname_324 ; MFC 3.1/4.0/4.2/8.0 32bit
+ add esp, 8
+ test eax, eax
+ jz short loc_4CF54D
+ mov eax, [esp+arg_0]
+ mov ecx, [esp+arg_8]
+ mov [ecx], eax
+ mov edx, [eax]
+ push eax
+ mov eax, [edx+4]
+ call eax
+ xor eax, eax
+ retn 0Ch
+loc_4CF54D: ; CODE XREF: Interface1_QueryInterface+14j
+ mov eax, 80004002h
+ retn 0Ch
+Interface1_QueryInterface endp
+
+; ---------------------------------------------------------------------------
+
+; int __stdcall Interface1_Release(void *pUnknown)
+Interface1_Release proc near ; DATA XREF: .rdata:00517A98o
+
+pUnknown = dword ptr 4
+
+ mov ecx, [esp+pUnknown]
+ add dword ptr [ecx+4], 0FFFFFFFFh
+ mov eax, [ecx+4]
+ jnz short locret_4CF585
+ push ecx ; Memory
+ mov dword ptr [ecx], offset off_517A90
+ mov dword ptr [ecx+8], 0
+ call j__free
+ add esp, 4
+ xor eax, eax
+
+locret_4CF585: ; CODE XREF: Interface1_Release+Bj
+ retn 4
+Interface1_Release endp
+
+; ---------------------------------------------------------------------------
+
+sub_4CF590 proc near ; DATA XREF: .rdata:00517AB4o
+
+arg_0 = dword ptr 4
+arg_4 = byte ptr 8
+arg_8 = dword ptr 0Ch
+arg_C = dword ptr 10h
+
+ mov eax, [esp+arg_0]
+ mov edx, [eax+10h]
+ sub edx, [eax+18h]
+ mov ecx, [eax+14h]
+ sbb ecx, [eax+1Ch]
+ push ebx
+ mov ebx, [esp+4+arg_8]
+ push edi
+ mov edi, [esp+8+arg_C]
+ cmp edi, ecx
+ jb short loc_4CF5C2
+ ja short loc_4CF5B4
+ cmp ebx, edx
+ jbe short loc_4CF5C2
+
+loc_4CF5B4: ; CODE XREF: sub_4CF590+1Ej
+ pop edi
+ mov byte ptr [eax+20h], 1
+ mov eax, 80004005h
+ pop ebx
+ retn 10h
+; ---------------------------------------------------------------------------
+
+loc_4CF5C2: ; CODE XREF: sub_4CF590+1Cj
+ ; sub_4CF590+22j
+ push esi
+ xor esi, esi
+ xor ecx, ecx
+ test edi, edi
+ jb short loc_4CF5FA
+ ja short loc_4CF5D1
+ test ebx, ebx
+ jbe short loc_4CF5FA
+
+loc_4CF5D1: ; CODE XREF: sub_4CF590+3Bj
+ mov dl, [esp+0Ch+arg_4]
+ push ebp
+
+loc_4CF5D6: ; CODE XREF: sub_4CF590+5Fj
+ ; sub_4CF590+67j
+ mov ebp, [eax+18h]
+ mov ebx, [eax+8]
+ mov [ebx+ebp], dl
+ add dword ptr [eax+18h], 1
+ adc dword ptr [eax+1Ch], 0
+ add esi, 1
+ adc ecx, 0
+ cmp ecx, edi
+ jb short loc_4CF5D6
+ ja short loc_4CF5F9
+ cmp esi, [esp+10h+arg_8]
+ jb short loc_4CF5D6
+
+loc_4CF5F9: ; CODE XREF: sub_4CF590+61j
+ pop ebp
+
+loc_4CF5FA: ; CODE XREF: sub_4CF590+39j
+ ; sub_4CF590+3Fj
+ pop esi
+ pop edi
+ xor eax, eax
+ pop ebx
+ retn 10h
+sub_4CF590 endp
+
+; =============== S U B R O U T I N E =======================================
+
+; int __stdcall Interface2_Release(void *pUnknown)
+Interface2_Release proc near ; DATA XREF: .rdata:00517AACo
+; sub_4CF610
+
+pUnknown = dword ptr 4
+
+ mov ecx, [esp+pUnknown]
+ add dword ptr [ecx+4], 0FFFFFFFFh
+ mov eax, [ecx+4]
+ jnz short locret_4CF635
+ push ecx ; Memory
+ mov dword ptr [ecx], offset off_517AA4
+ mov dword ptr [ecx+8], 0
+ call j__free
+ add esp, 4
+ xor eax, eax
+
+locret_4CF635: ; CODE XREF: Interface2_Release+Bj
+ retn 4
+Interface2_Release endp
+
+; =============== S U B R O U T I N E =======================================
+
+loc_4CF640: ; CODE XREF: sub_4CF6E0+39p
+ ; sub_4CFAC0+57p ...
+ push ecx
+ push ebx
+ push esi
+ push edi
+ mov edi, ecx
+ mov esi, [edi+8]
+ cmp esi, 0FF000000h
+ jb short loc_4CF661
+ mov edx, [edi+0Ch]
+ mov eax, esi
+ mov cl, 20h
+ call __allshr ; Microsoft VisualC 2-8/net runtime
+ test eax, eax
+ jz short loc_4CF6B6
+
+loc_4CF661: ; CODE XREF: .text:004CF64Fj
+ mov bl, [edi+4]
+ lea esi, [edi+18h]
+
+loc_4CF667: ; CODE XREF: .text:004CF6A9j
+ mov eax, [edi+8]
+ mov edx, [edi+0Ch]
+ mov cl, 20h
+ call __allshr ; Microsoft VisualC 2-8/net runtime
+ mov ecx, [esi+4]
+ mov edx, [esi]
+ add al, bl
+ mov [ecx+edx], al
+ add dword ptr [esi+4], 1
+ mov eax, [esi+4]
+ cmp eax, [esi+8]
+ jnz short loc_4CF6A3
+ cmp [esi+0Ch], eax
+ jz short loc_4CF6A3
+ nop
+
+loc_4CF690: ; CODE XREF: .text:004CF6A1j
+ mov ecx, esi
+ call sub_4CF450
+ test eax, eax
+ jnz short loc_4CF6CB
+ mov eax, [esi+0Ch]
+ cmp eax, [esi+4]
+ jnz short loc_4CF690
+
+loc_4CF6A3: ; CODE XREF: .text:004CF688j
+ ; .text:004CF68Dj
+ or bl, 0FFh
+ add dword ptr [edi], 0FFFFFFFFh
+ jnz short loc_4CF667
+ mov esi, [edi+8]
+ mov edx, esi
+ shr edx, 18h
+ mov [edi+4], dl
+
+loc_4CF6B6: ; CODE XREF: .text:004CF65Fj
+ add dword ptr [edi], 1
+ shl esi, 8
+ mov [edi+8], esi
+ mov dword ptr [edi+0Ch], 0
+ pop edi
+ pop esi
+ pop ebx
+ pop ecx
+ retn
+
+; ---------------------------------------------------------------------------
+
+loc_4CF6CB: ; CODE XREF: .text:004CF699j
+ push offset dword_526DD0
+ lea ecx, [esp+10h]
+ push ecx
+ mov [esp+14h], eax
+ int 3
+; call __CxxThrowException@8 ; _CxxThrowException(x,x)
+; ---------------------------------------------------------------------------
+
+ db 2 dup(0CCh)
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CF6E0 proc near ; CODE XREF: sub_4D0770+FBp
+ ; CEncoder_CodeOneBlock+6C5p
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ push esi
+ push edi
+ mov edi, [esp+8+arg_4]
+ add edi, 0FFFFFFFFh
+ mov esi, ecx
+ js short loc_4CF724
+ push ebp
+ mov ebp, [esp+0Ch+arg_0]
+
+loc_4CF6F2: ; CODE XREF: sub_4CF6E0+41j
+ shr dword ptr [esi+10h], 1
+ mov eax, [esi+10h]
+ mov edx, ebp
+ mov ecx, edi
+ shr edx, cl
+ test dl, 1
+ jz short loc_4CF70A
+ add [esi+8], eax
+ adc dword ptr [esi+0Ch], 0
+
+loc_4CF70A: ; CODE XREF: sub_4CF6E0+21j
+ cmp eax, 1000000h
+ jnb short loc_4CF71E
+ shl eax, 8
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+
+loc_4CF71E: ; CODE XREF: sub_4CF6E0+2Fj
+ sub edi, 1
+ jns short loc_4CF6F2
+ pop ebp
+
+loc_4CF724: ; CODE XREF: sub_4CF6E0+Bj
+ pop edi
+ pop esi
+ retn 8
+sub_4CF6E0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CF740 proc near ; CODE XREF: sub_4D0770+DFp
+ ; CEncoder_CodeOneBlock+58Ap ...
+
+arg_0 = dword ptr 4
+
+ push esi
+ push edi
+ mov edi, [esp+8+arg_0]
+ mov eax, edi
+ imul eax, 440h
+ mov esi, ecx
+ mov edx, [esi+4C08h]
+ lea ecx, [eax+esi+808h]
+ push ecx
+ push edx
+ push edi
+ mov ecx, esi
+ call sub_4CDC00
+ mov eax, [esi+4C08h]
+ mov [esi+edi*4+4C0Ch], eax
+ pop edi
+ pop esi
+ retn 4
+sub_4CF740 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CF780 proc near ; CODE XREF: CEncoder_SetStreams+7Ep
+ ; CEncoder_SetStreams+A6p
+
+arg_0 = dword ptr 4
+
+ push esi
+ push edi
+ xor edi, edi
+ cmp [esp+8+arg_0], edi
+ mov esi, ecx
+ jbe short loc_4CF7CC
+ push ebx
+ push ebp
+ lea ebx, [esi+4C0Ch]
+ lea ebp, [esi+808h]
+ lea ebx, [ebx+0]
+
+loc_4CF7A0: ; CODE XREF: sub_4CF780+48j
+ mov eax, [esi+4C08h]
+ push ebp
+ push eax
+ push edi
+ mov ecx, esi
+ call sub_4CDC00
+ mov ecx, [esi+4C08h]
+ mov [ebx], ecx
+ add edi, 1
+ add ebx, 4
+ add ebp, 440h
+ cmp edi, [esp+10h+arg_0]
+ jb short loc_4CF7A0
+ pop ebp
+ pop ebx
+
+loc_4CF7CC: ; CODE XREF: sub_4CF780+Aj
+ pop edi
+ pop esi
+ retn 4
+sub_4CF780 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+CEncoder_GetOptimum proc near ; CODE XREF: CEncoder_CodeOneBlock+201p
+
+var_7D = byte ptr -7Dh
+var_7C = dword ptr -7Ch
+var_78 = dword ptr -78h
+var_74 = dword ptr -74h
+var_70 = dword ptr -70h
+var_6C = dword ptr -6Ch
+var_68 = dword ptr -68h
+var_64 = dword ptr -64h
+var_60 = dword ptr -60h
+var_5C = dword ptr -5Ch
+var_58 = dword ptr -58h
+var_54 = dword ptr -54h
+var_50 = dword ptr -50h
+var_4C = dword ptr -4Ch
+var_48 = dword ptr -48h
+var_44 = dword ptr -44h
+var_40 = dword ptr -40h
+var_3C = dword ptr -3Ch
+var_38 = dword ptr -38h
+var_34 = dword ptr -34h
+var_30 = dword ptr -30h
+var_2C = dword ptr -2Ch
+var_28 = dword ptr -28h
+var_24 = dword ptr -24h
+var_20 = dword ptr -20h
+var_1C = dword ptr -1Ch
+var_18 = dword ptr -18h
+var_14 = dword ptr -14h
+var_10 = dword ptr -10h
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ sub esp, 80h
+ push ebp
+ mov ebp, ecx
+ mov edx, [ebp+32F0Ch]
+ cmp [ebp+32F08h], edx
+ push esi
+ jz short loc_4CE0A5
+ mov esi, [esp+88h+arg_4]
+ lea eax, [edx+edx*4+1Eh]
+ lea ecx, [ebp+eax*8+0]
+ mov eax, [ecx+10h]
+ sub eax, edx
+ mov edx, [ecx+14h]
+ mov [esi], edx
+ mov ecx, [ecx+10h]
+ pop esi
+ mov [ebp+32F0Ch], ecx
+ pop ebp
+ add esp, 80h
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_4CE0A5: ; CODE XREF: CEncoder_GetOptimum+16j
+ mov edx, [ebp+80h]
+ mov eax, [ebp+70h]
+ push ebx
+ xor esi, esi
+ push edx
+ mov [ebp+32F08h], esi
+ mov [ebp+32F0Ch], esi
+ call eax
+ add esp, 4
+ cmp byte ptr [ebp+32F10h], 0
+ mov ebx, eax
+ mov [esp+8Ch+var_60], eax
+ jnz short loc_4CE0E4
+ lea ecx, [esp+8Ch+var_70]
+ push ecx
+ mov ecx, ebp
+ call sub_4CB3B0
+ mov [esp+8Ch+var_68], eax
+ jmp short loc_4CE0FF
+; ---------------------------------------------------------------------------
+
+loc_4CE0E4: ; CODE XREF: CEncoder_GetOptimum+70j
+ mov edx, [ebp+32EFCh]
+ mov eax, [ebp+32F00h]
+ mov [esp+8Ch+var_68], edx
+ mov [esp+8Ch+var_70], eax
+ mov byte ptr [ebp+32F10h], 0
+
+loc_4CE0FF: ; CODE XREF: CEncoder_GetOptimum+82j
+ mov ecx, [ebp+80h]
+ mov edx, [ebp+74h]
+ push edi
+ push ecx
+ call edx
+ mov edi, eax
+ add esp, 4
+ sub edi, 1
+ cmp ebx, 2
+ jnb short loc_4CE138
+ mov eax, [esp+90h+arg_4]
+ pop edi
+ pop ebx
+ pop esi
+ mov dword ptr [eax], 0FFFFFFFFh
+ mov eax, 1
+ pop ebp
+ add esp, 80h
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_4CE138: ; CODE XREF: CEncoder_GetOptimum+B7j
+ cmp ebx, 111h
+ jbe short loc_4CE149
+ mov ebx, 111h
+ mov [esp+90h+var_60], ebx
+
+loc_4CE149: ; CODE XREF: CEncoder_GetOptimum+DEj
+ lea ecx, [ebp+14h]
+ mov [esp+90h+var_50], esi
+ mov [esp+90h+var_64], esi
+ xor edx, edx
+ mov [esp+90h+var_4C], esi
+ mov [esp+90h+var_6C], ecx
+ mov edi, edi
+
+loc_4CE160: ; CODE XREF: CEncoder_GetOptimum+180j
+ mov eax, [esp+90h+var_6C]
+ mov eax, [eax]
+ mov ecx, edi
+ sub ecx, eax
+ mov [esp+edx+90h+var_20], eax
+ mov al, [edi]
+ sub ecx, 1
+ cmp al, [ecx]
+ jnz short loc_4CE1C9
+ mov al, [edi+1]
+ cmp al, [ecx+1]
+ jnz short loc_4CE1C9
+ mov eax, 2
+ cmp ebx, eax
+ jbe short loc_4CE1A7
+ lea esi, [edi+2]
+ sub ecx, edi
+ lea ecx, [ecx+0]
+
+loc_4CE190: ; CODE XREF: CEncoder_GetOptimum+143j
+ mov bl, [esi]
+ cmp bl, [ecx+esi]
+ mov ebx, [esp+90h+var_60]
+ jnz short loc_4CE1A5
+ add eax, 1
+ add esi, 1
+ cmp eax, ebx
+ jb short loc_4CE190
+
+loc_4CE1A5: ; CODE XREF: CEncoder_GetOptimum+139j
+ xor esi, esi
+
+loc_4CE1A7: ; CODE XREF: CEncoder_GetOptimum+126j
+ mov ecx, [esp+90h+var_4C]
+ mov [esp+edx+90h+var_10], eax
+ cmp eax, [esp+ecx+90h+var_10]
+ jbe short loc_4CE1D0
+ mov eax, [esp+90h+var_64]
+ mov [esp+90h+var_50], eax
+ mov [esp+90h+var_4C], edx
+ jmp short loc_4CE1D0
+; ---------------------------------------------------------------------------
+
+loc_4CE1C9: ; CODE XREF: CEncoder_GetOptimum+115j
+ ; CEncoder_GetOptimum+11Dj
+ mov [esp+edx+90h+var_10], esi
+
+loc_4CE1D0: ; CODE XREF: CEncoder_GetOptimum+159j
+ ; CEncoder_GetOptimum+167j
+ add [esp+90h+var_64], 1
+ add [esp+90h+var_6C], 4
+ add edx, 4
+ cmp edx, 10h
+ jb loc_4CE160
+ mov ecx, [esp+90h+var_50]
+ mov ebx, [esp+ecx*4+90h+var_10]
+ mov eax, [ebp+32EF8h]
+ cmp ebx, eax
+ mov [esp+90h+var_40], ebx
+ jb short loc_4CE234
+ mov edx, [esp+90h+arg_4]
+ lea eax, [ebx-1]
+ cmp eax, esi
+ mov [edx], ecx
+ jz short loc_4CE225
+ add [ebp+32F04h], eax
+ mov ecx, [ebp+7Ch]
+ push eax
+ mov eax, [ebp+80h]
+ push eax
+ call ecx
+ add esp, 8
+
+loc_4CE225: ; CODE XREF: CEncoder_GetOptimum+1ADj
+ pop edi
+ mov eax, ebx
+ pop ebx
+ pop esi
+ pop ebp
+ add esp, 80h
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_4CE234: ; CODE XREF: CEncoder_GetOptimum+19Dj
+ mov esi, [esp+90h+var_68]
+ cmp esi, eax
+ jb short loc_4CE27F
+ mov edx, [esp+90h+var_70]
+ mov eax, [ebp+edx*4+3265Ch]
+ mov ecx, [esp+90h+arg_4]
+ add eax, 4
+ mov [ecx], eax
+ lea eax, [esi-1]
+ test eax, eax
+ jz short loc_4CE270
+ mov edx, [ebp+80h]
+ add [ebp+32F04h], eax
+ push eax
+ mov eax, [ebp+7Ch]
+ push edx
+ call eax
+ add esp, 8
+
+loc_4CE270: ; CODE XREF: CEncoder_GetOptimum+1F8j
+ pop edi
+ pop ebx
+ mov eax, esi
+ pop esi
+ pop ebp
+ add esp, 80h
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_4CE27F: ; CODE XREF: CEncoder_GetOptimum+1DAj
+ mov al, [edi]
+ mov esi, [esp+90h+var_20]
+ sub edi, esi
+ cmp [esp+90h+var_68], 2
+ mov cl, [edi-1]
+ mov byte ptr [esp+90h+var_4C], al
+ mov byte ptr [esp+90h+var_50], cl
+ jnb short loc_4CE2C1
+ cmp al, cl
+ jz short loc_4CE2C1
+ cmp ebx, 2
+ jnb short loc_4CE2C1
+ mov ecx, [esp+90h+arg_4]
+ pop edi
+ pop ebx
+ pop esi
+ mov dword ptr [ecx], 0FFFFFFFFh
+ mov eax, 1
+ pop ebp
+ add esp, 80h
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_4CE2C1: ; CODE XREF: CEncoder_GetOptimum+237j
+ ; CEncoder_GetOptimum+23Bj ...
+ mov edx, [esp+90h+var_4C]
+ mov bl, [ebp+10h]
+ mov edi, [ebp+33B60h]
+ and edi, [esp+90h+arg_0]
+ mov ecx, [esp+90h+var_50]
+ push edx
+ cmp bl, 7
+ setnb dl
+ push ecx
+ mov [ebp+0F0h], bl
+ mov eax, [ebp+32654h]
+ mov ecx, 8
+ sub cl, al
+ push edx
+ movzx edx, byte ptr [ebp+11h]
+ shr edx, cl
+ mov ecx, [ebp+3265Ch]
+ and ecx, [esp+9Ch+arg_0]
+ mov [esp+9Ch+var_3C], ecx
+ mov ecx, eax
+ mov eax, [esp+9Ch+var_3C]
+ shl eax, cl
+ add edx, eax
+ imul edx, 0C00h
+ add edx, [ebp+32650h]
+ mov ecx, edx
+ call sub_4CDAC0
+ movzx ecx, bl
+ shl ecx, 4
+ add ecx, edi
+ mov edx, [ebp+ecx*4+280F0h]
+ shr edx, 2
+ add eax, dword_550998[edx*4]
+ mov ebx, 800h
+ mov [ebp+124h], eax
+ mov dword ptr [ebp+12Ch], 0FFFFFFFFh
+ mov byte ptr [ebp+119h], 0
+ mov cl, [ebp+10h]
+ movzx eax, cl
+ mov edx, eax
+ shl edx, 4
+ add edx, edi
+ sub ebx, [ebp+edx*4+280F0h]
+ mov edx, 800h
+ sub edx, [ebp+eax*4+283F0h]
+ mov al, byte ptr [esp+90h+var_4C]
+ shr edx, 2
+ mov edx, dword_550998[edx*4]
+ shr ebx, 2
+ mov ebx, dword_550998[ebx*4]
+ add edx, ebx
+ cmp byte ptr [esp+90h+var_50], al
+ mov [esp+90h+var_44], ebx
+ mov [esp+90h+var_3C], edx
+ jnz short loc_4CE3F3
+ movzx eax, cl
+ mov ebx, [ebp+eax*4+28420h]
+ mov ecx, eax
+ shl ecx, 4
+ add ecx, edi
+ mov ecx, [ebp+ecx*4+284B0h]
+ shr ecx, 2
+ mov eax, dword_550998[ecx*4]
+ shr ebx, 2
+ add eax, dword_550998[ebx*4]
+ add eax, edx
+ cmp eax, [ebp+124h]
+ jnb short loc_4CE3F3
+ mov [ebp+124h], eax
+ mov dword ptr [ebp+12Ch], 0
+ mov byte ptr [ebp+119h], 0
+
+loc_4CE3F3: ; CODE XREF: CEncoder_GetOptimum+344j
+ ; CEncoder_GetOptimum+37Aj
+ mov eax, [esp+90h+var_68]
+ mov ecx, [esp+90h+var_40]
+ cmp eax, ecx
+ jb short loc_4CE405
+ mov [esp+90h+var_7C], eax
+ jmp short loc_4CE40B
+; ---------------------------------------------------------------------------
+
+loc_4CE405: ; CODE XREF: CEncoder_GetOptimum+39Dj
+ mov [esp+90h+var_7C], ecx
+ mov eax, ecx
+
+loc_4CE40B: ; CODE XREF: CEncoder_GetOptimum+3A3j
+ cmp eax, 2
+ jnb short loc_4CE431
+ mov edx, [ebp+12Ch]
+ mov eax, [esp+90h+arg_4]
+ pop edi
+ pop ebx
+ pop esi
+ mov [eax], edx
+ mov eax, 1
+ pop ebp
+ add esp, 80h
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_4CE431: ; CODE XREF: CEncoder_GetOptimum+3AEj
+ mov ecx, [esp+90h+var_1C]
+ mov edx, [esp+90h+var_18]
+ xor ebx, ebx
+ mov [ebp+128h], ebx
+ mov [ebp+10Ch], ecx
+ mov ecx, [esp+90h+var_14]
+ mov [ebp+110h], edx
+ lea edx, [eax+eax*4]
+ mov [ebp+114h], ecx
+ mov [ebp+108h], esi
+ lea ecx, [ebp+edx*8+0FCh]
+ jmp short loc_4CE470
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CE470: ; CODE XREF: CEncoder_GetOptimum+407j
+ ; CEncoder_GetOptimum+41Fj
+ mov dword ptr [ecx], 0FFFFFFFh
+ sub eax, 1
+ sub ecx, 28h
+ cmp eax, 2
+ jnb short loc_4CE470
+
+loc_4CE481: ; CODE XREF: CEncoder_GetOptimum+48Ej
+ mov esi, [esp+ebx*4+90h+var_10]
+ cmp esi, 2
+ jb short loc_4CE4E8
+ movzx eax, byte ptr [ebp+10h]
+ push edi
+ push eax
+ push ebx
+ mov ecx, ebp
+ call sub_4CD9B0
+ add eax, [esp+90h+var_3C]
+ mov ecx, edi
+ imul ecx, 110h
+ add ecx, esi
+ mov [esp+90h+var_40], eax
+ lea edx, [esi+esi*4]
+ lea eax, [ebp+ecx*4+2E204h]
+ lea ecx, [ebp+edx*8+0FCh]
+ mov edi, edi
+
+loc_4CE4C0: ; CODE XREF: CEncoder_GetOptimum+486j
+ mov edx, [eax]
+ add edx, [esp+90h+var_40]
+ cmp edx, [ecx]
+ jnb short loc_4CE4DA
+ mov [ecx], edx
+ mov dword ptr [ecx+4], 0
+ mov [ecx+8], ebx
+ mov byte ptr [ecx-0Bh], 0
+
+loc_4CE4DA: ; CODE XREF: CEncoder_GetOptimum+468j
+ sub esi, 1
+ sub eax, 4
+ sub ecx, 28h
+ cmp esi, 2
+ jnb short loc_4CE4C0
+
+loc_4CE4E8: ; CODE XREF: CEncoder_GetOptimum+42Bj
+ add ebx, 1
+ cmp ebx, 4
+ jb short loc_4CE481
+ movzx eax, byte ptr [ebp+10h]
+ mov ecx, [ebp+eax*4+283F0h]
+ shr ecx, 2
+ mov eax, dword_550998[ecx*4]
+ add eax, [esp+90h+var_44]
+ mov [esp+90h+var_3C], eax
+ mov eax, [esp+90h+var_10]
+ cmp eax, 2
+ lea ebx, [eax+1]
+ jnb short loc_4CE521
+ mov ebx, 2
+
+loc_4CE521: ; CODE XREF: CEncoder_GetOptimum+4BAj
+ cmp ebx, [esp+90h+var_68]
+ ja loc_4CE5BA
+ xor eax, eax
+ cmp ebx, [ebp+32660h]
+ mov [esp+90h+var_60], eax
+ jbe short loc_4CE550
+ lea esp, [esp+0]
+
+loc_4CE540: ; CODE XREF: CEncoder_GetOptimum+4EAj
+ add eax, 2
+ cmp ebx, [ebp+eax*4+32660h]
+ ja short loc_4CE540
+ mov [esp+90h+var_60], eax
+
+loc_4CE550: ; CODE XREF: CEncoder_GetOptimum+4D7j
+ lea edx, [ebx+ebx*4]
+ lea esi, [ebp+edx*8+0FCh]
+ lea ebx, [ebx+0]
+
+loc_4CE560: ; CODE XREF: CEncoder_GetOptimum+558j
+ mov eax, [esp+90h+var_60]
+ mov eax, [ebp+eax*4+32664h]
+ push edi
+ push ebx
+ push eax
+ mov ecx, ebp
+ mov [esp+9Ch+var_40], eax
+ call sub_4CAEC0
+ add eax, [esp+90h+var_3C]
+ cmp eax, [esi]
+ jnb short loc_4CE598
+ mov ecx, [esp+90h+var_40]
+ add ecx, 4
+ mov [esi], eax
+ mov dword ptr [esi+4], 0
+ mov [esi+8], ecx
+ mov byte ptr [esi-0Bh], 0
+
+loc_4CE598: ; CODE XREF: CEncoder_GetOptimum+51Fj
+ mov eax, [esp+90h+var_60]
+ cmp ebx, [ebp+eax*4+32660h]
+ jnz short loc_4CE5B2
+ add eax, 2
+ cmp eax, [esp+90h+var_70]
+ mov [esp+90h+var_60], eax
+ jz short loc_4CE5BA
+
+loc_4CE5B2: ; CODE XREF: CEncoder_GetOptimum+543j
+ add ebx, 1
+ add esi, 28h
+ jmp short loc_4CE560
+; ---------------------------------------------------------------------------
+
+loc_4CE5BA: ; CODE XREF: CEncoder_GetOptimum+4C5j
+ ; CEncoder_GetOptimum+550j
+ mov eax, 1
+ cmp [esp+90h+var_7C], eax
+ mov [esp+90h+var_78], eax
+ jz loc_4CF1D0
+ mov esi, eax
+ jmp short loc_4CE5D5
+; ---------------------------------------------------------------------------
+
+loc_4CE5D1: ; CODE XREF: CEncoder_GetOptimum+116Aj
+ mov esi, [esp+90h+var_78]
+
+loc_4CE5D5: ; CODE XREF: CEncoder_GetOptimum+56Fj
+ mov edx, [ebp+80h]
+ mov eax, [ebp+70h]
+ push edx
+ call eax
+ add esp, 4
+ lea ecx, [esp+90h+var_4C]
+ push ecx
+ mov ecx, ebp
+ mov [esp+94h+var_60], eax
+ call sub_4CB3B0
+ cmp eax, [ebp+32EF8h]
+ mov [esp+90h+var_28], eax
+ jnb loc_4CF1D7
+ add [esp+90h+arg_0], 1
+ lea edx, [esi+esi*4+1Eh]
+ mov bl, [ebp+edx*8+1]
+ test bl, bl
+ lea eax, [ebp+edx*8+0]
+ mov edx, [eax+10h]
+ jz short loc_4CE673
+ sub edx, 1
+ cmp byte ptr [eax+2], 0
+ jz short loc_4CE660
+ mov ecx, [eax+4]
+ add ecx, 6
+ cmp dword ptr [eax+8], 4
+ lea ecx, [ecx+ecx*4]
+ mov cl, [ebp+ecx*8+0]
+ movzx ecx, cl
+ jnb short loc_4CE64F
+ mov cl, ds:kRepNextStates[ecx]
+ movzx ecx, cl
+ mov cl, ds:kLiteralNextStates[ecx]
+ jmp short loc_4CE67B
+; ---------------------------------------------------------------------------
+
+loc_4CE64F: ; CODE XREF: CEncoder_GetOptimum+5DCj
+ mov cl, ds:kMatchNextStates[ecx]
+ movzx ecx, cl
+ mov cl, ds:kLiteralNextStates[ecx]
+ jmp short loc_4CE67B
+; ---------------------------------------------------------------------------
+
+loc_4CE660: ; CODE XREF: CEncoder_GetOptimum+5C6j
+ lea ecx, [edx+edx*4+1Eh]
+ mov cl, [ebp+ecx*8+0]
+ movzx ecx, cl
+ mov cl, ds:kLiteralNextStates[ecx]
+ jmp short loc_4CE67B
+; ---------------------------------------------------------------------------
+
+loc_4CE673: ; CODE XREF: CEncoder_GetOptimum+5BDj
+ lea ecx, [edx+edx*4+1Eh]
+ mov cl, [ebp+ecx*8+0]
+
+loc_4CE67B: ; CODE XREF: CEncoder_GetOptimum+5EDj
+ ; CEncoder_GetOptimum+5FEj ...
+ add esi, 0FFFFFFFFh
+ cmp edx, esi
+ jnz short loc_4CE6AC
+ cmp dword ptr [eax+14h], 0
+ jnz short loc_4CE69A
+ movzx edx, cl
+ mov bl, ds:kShortRepNextStates[edx]
+ mov byte ptr [esp+90h+var_64], bl
+ jmp loc_4CE754
+; ---------------------------------------------------------------------------
+
+loc_4CE69A: ; CODE XREF: CEncoder_GetOptimum+626j
+ movzx ecx, cl
+ mov bl, ds:kLiteralNextStates[ecx]
+ mov byte ptr [esp+90h+var_64], bl
+ jmp loc_4CE754
+; ---------------------------------------------------------------------------
+
+loc_4CE6AC: ; CODE XREF: CEncoder_GetOptimum+620j
+ test bl, bl
+ jz short loc_4CE6CB
+ cmp byte ptr [eax+2], 0
+ jz short loc_4CE6CB
+ mov edi, [eax+8]
+ mov edx, [eax+4]
+ movzx ecx, cl
+ mov bl, ds:kRepNextStates[ecx]
+ mov [esp+90h+var_68], edi
+ jmp short loc_4CE6EA
+; ---------------------------------------------------------------------------
+
+loc_4CE6CB: ; CODE XREF: CEncoder_GetOptimum+64Ej
+ ; CEncoder_GetOptimum+654j
+ mov esi, [eax+14h]
+ cmp esi, 4
+ mov [esp+90h+var_68], esi
+ movzx ecx, cl
+ mov edi, esi
+ jnb short loc_4CE6E4
+ mov bl, ds:kRepNextStates[ecx]
+ jmp short loc_4CE6EA
+; ---------------------------------------------------------------------------
+
+loc_4CE6E4: ; CODE XREF: CEncoder_GetOptimum+67Aj
+ mov bl, ds:kMatchNextStates[ecx]
+
+loc_4CE6EA: ; CODE XREF: CEncoder_GetOptimum+669j
+ ; CEncoder_GetOptimum+682j
+ cmp edi, 4
+ lea edx, [edx+edx*4+1Eh]
+ mov byte ptr [esp+90h+var_64], bl
+ lea edx, [ebp+edx*8+0]
+ jnb short loc_4CE738
+ mov ecx, [edx+edi*4+18h]
+ mov esi, 1
+ cmp edi, esi
+ mov [esp+90h+var_20], ecx
+ jb short loc_4CE723
+ mov ecx, edi
+ lea esi, [edx+18h]
+ lea edi, [esp+90h+var_1C]
+ rep movsd
+ mov esi, [esp+90h+var_68]
+ add esi, 1
+ cmp esi, 4
+ jnb short loc_4CE754
+
+loc_4CE723: ; CODE XREF: CEncoder_GetOptimum+6AAj
+ lea edx, [edx+esi*4+18h]
+ mov ecx, 4
+ lea edi, [esp+esi*4+90h+var_20]
+ sub ecx, esi
+ mov esi, edx
+ rep movsd
+ jmp short loc_4CE754
+; ---------------------------------------------------------------------------
+
+loc_4CE738: ; CODE XREF: CEncoder_GetOptimum+699j
+ mov ecx, [edx+18h]
+ mov [esp+90h+var_1C], ecx
+ mov ecx, [edx+1Ch]
+ mov edx, [edx+20h]
+ add edi, 0FFFFFFFCh
+ mov [esp+90h+var_20], edi
+ mov [esp+90h+var_18], ecx
+ mov [esp+90h+var_14], edx
+
+loc_4CE754: ; CODE XREF: CEncoder_GetOptimum+635j
+ ; CEncoder_GetOptimum+647j ...
+ mov ecx, [esp+90h+var_1C]
+ mov edx, [esp+90h+var_18]
+ mov edi, [esp+90h+var_20]
+ mov [eax], bl
+ mov [eax+1Ch], ecx
+ mov ecx, [esp+90h+var_14]
+ mov [eax+18h], edi
+ mov [eax+20h], edx
+ mov [eax+24h], ecx
+ mov esi, [eax+0Ch]
+ mov edx, [ebp+80h]
+ mov eax, [ebp+74h]
+ push edx
+ mov [esp+94h+var_3C], esi
+ call eax
+ movzx ecx, byte ptr [eax-1]
+ sub eax, 1
+ mov edx, eax
+ mov byte ptr [esp+94h+var_5C], cl
+ sub edx, edi
+ movzx ecx, byte ptr [edx-1]
+ lea edi, [edx-1]
+ mov edx, [ebp+32654h]
+ mov byte ptr [esp+94h+var_58], cl
+ mov ecx, [ebp+33B60h]
+ and ecx, [esp+94h+arg_0]
+ mov [esp+94h+var_40], edi
+ movzx edi, bl
+ mov [esp+94h+var_54], ecx
+ mov [esp+94h+var_68], edi
+ add esp, 4
+ shl edi, 4
+ add edi, ecx
+ mov ecx, [esp+90h+var_5C]
+ push ecx
+ mov ecx, [esp+94h+var_58]
+ push ecx
+ cmp bl, 7
+ mov ebx, [ebp+3265Ch]
+ setnb cl
+ and ebx, [esp+98h+arg_0]
+ mov [esp+98h+var_74], eax
+ movzx eax, byte ptr [eax-1]
+ push ecx
+ mov ecx, 8
+ sub cl, dl
+ shr eax, cl
+ mov ecx, edx
+ shl ebx, cl
+ add eax, ebx
+ imul eax, 0C00h
+ add eax, [ebp+32650h]
+ mov ecx, eax
+ call sub_4CDAC0
+ mov ecx, [ebp+edi*4+280F0h]
+ shr ecx, 2
+ add eax, dword_550998[ecx*4]
+ mov ecx, [esp+90h+var_78]
+ add eax, esi
+ lea edx, [ecx+ecx*4+23h]
+ cmp eax, [ebp+edx*8+0Ch]
+ lea esi, [ebp+edx*8+0]
+ mov [esp+90h+var_7D], 0
+ jnb short loc_4CE851
+ mov [esi+0Ch], eax
+ mov [esi+10h], ecx
+ mov dword ptr [esi+14h], 0FFFFFFFFh
+ mov byte ptr [esi+1], 0
+ mov [esp+90h+var_7D], 1
+
+loc_4CE851: ; CODE XREF: CEncoder_GetOptimum+7D9j
+ mov ebx, [esp+90h+var_68]
+ mov edx, 800h
+ sub edx, [ebp+edi*4+280F0h]
+ shr edx, 2
+ mov ecx, dword_550998[edx*4]
+ add ecx, [esp+90h+var_3C]
+ mov edx, 800h
+ sub edx, [ebp+ebx*4+283F0h]
+ mov ebx, [esp+90h+var_78]
+ shr edx, 2
+ mov edx, dword_550998[edx*4]
+ add edx, ecx
+ mov [esp+90h+var_24], ecx
+ mov cl, byte ptr [esp+90h+var_58]
+ cmp cl, byte ptr [esp+90h+var_5C]
+ mov [esp+90h+var_38], edx
+ jnz short loc_4CE8EB
+ cmp [esi+10h], ebx
+ jnb short loc_4CE8A8
+ cmp dword ptr [esi+14h], 0
+ jz short loc_4CE8EB
+
+loc_4CE8A8: ; CODE XREF: CEncoder_GetOptimum+840j
+ mov ecx, [esp+90h+var_68]
+ mov ecx, [ebp+ecx*4+28420h]
+ mov edi, [ebp+edi*4+284B0h]
+ shr ecx, 2
+ mov ecx, dword_550998[ecx*4]
+ shr edi, 2
+ add ecx, dword_550998[edi*4]
+ add ecx, edx
+ cmp ecx, [esi+0Ch]
+ ja short loc_4CE8EB
+ mov [esi+0Ch], ecx
+ mov [esi+10h], ebx
+ mov dword ptr [esi+14h], 0
+ mov byte ptr [esi+1], 0
+ mov [esp+90h+var_7D], 1
+
+loc_4CE8EB: ; CODE XREF: CEncoder_GetOptimum+83Bj
+ ; CEncoder_GetOptimum+846j ...
+ mov edx, [esp+90h+var_60]
+ mov ecx, 0FFFh
+ sub ecx, ebx
+ cmp ecx, edx
+ jnb short loc_4CE900
+ mov edx, ecx
+ mov [esp+90h+var_60], edx
+
+loc_4CE900: ; CODE XREF: CEncoder_GetOptimum+898j
+ cmp edx, 2
+ mov ebx, edx
+ mov [esp+90h+var_6C], ebx
+ jb loc_4CF1BB
+ mov esi, [ebp+32EF8h]
+ mov edi, [esp+90h+var_60]
+ cmp edi, esi
+ jbe short loc_4CE923
+ mov ebx, esi
+ mov [esp+90h+var_6C], esi
+
+loc_4CE923: ; CODE XREF: CEncoder_GetOptimum+8BBj
+ cmp [esp+90h+var_7D], 0
+ jnz loc_4CEA90
+ mov dl, byte ptr [esp+90h+var_5C]
+ cmp byte ptr [esp+90h+var_58], dl
+ jz loc_4CEA90
+ lea ecx, [esi+1]
+ cmp edi, ecx
+ jb short loc_4CE945
+ mov edi, ecx
+
+loc_4CE945: ; CODE XREF: CEncoder_GetOptimum+8E1j
+ mov esi, 1
+ cmp edi, esi
+ jbe short loc_4CE975
+ mov ebx, [esp+90h+var_74]
+ mov edx, [esp+90h+var_40]
+ lea ecx, [ebx+1]
+ sub edx, ebx
+ jmp short loc_4CE960
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CE960: ; CODE XREF: CEncoder_GetOptimum+8FBj
+ ; CEncoder_GetOptimum+90Fj
+ mov bl, [ecx]
+ cmp bl, [edx+ecx]
+ jnz short loc_4CE971
+ add esi, 1
+ add ecx, 1
+ cmp esi, edi
+ jb short loc_4CE960
+
+loc_4CE971: ; CODE XREF: CEncoder_GetOptimum+905j
+ mov ebx, [esp+90h+var_6C]
+
+loc_4CE975: ; CODE XREF: CEncoder_GetOptimum+8ECj
+ add esi, 0FFFFFFFFh
+ cmp esi, 2
+ mov [esp+90h+var_50], esi
+ jb loc_4CEA90
+ mov ecx, [esp+90h+var_68]
+ mov dl, ds:kLiteralNextStates[ecx]
+ mov ecx, [esp+90h+arg_0]
+ movzx ebx, dl
+ add ecx, 1
+ and ecx, [ebp+33B60h]
+ mov edx, ebx
+ shl edx, 4
+ lea esi, [edx+ecx]
+ mov edx, 800h
+ sub edx, [ebp+ebx*4+283F0h]
+ mov edi, 800h
+ sub edi, [ebp+esi*4+280F0h]
+ shr edx, 2
+ mov edx, dword_550998[edx*4]
+ shr edi, 2
+ add edx, dword_550998[edi*4]
+ mov edi, [esp+90h+var_78]
+ add edx, eax
+ mov eax, [esp+90h+var_50]
+ lea edi, [eax+edi+1]
+ mov eax, [esp+90h+var_7C]
+ cmp eax, edi
+ mov [esp+90h+var_40], esi
+ jnb short loc_4CEA22
+ mov esi, [esp+90h+var_7C]
+ lea eax, [eax+eax*4]
+ lea eax, [ebp+eax*8+0FCh]
+ mov [esp+90h+var_3C], eax
+ mov eax, edi
+ sub eax, esi
+ add esi, eax
+ mov [esp+90h+var_7C], esi
+ mov esi, [esp+90h+var_3C]
+
+loc_4CEA10: ; CODE XREF: CEncoder_GetOptimum+9BCj
+ add esi, 28h
+ sub eax, 1
+ mov dword ptr [esi], 0FFFFFFFh
+ jnz short loc_4CEA10
+ mov esi, [esp+90h+var_40]
+
+loc_4CEA22: ; CODE XREF: CEncoder_GetOptimum+98Ej
+ imul ecx, 110h
+ add ecx, [esp+90h+var_50]
+ mov eax, 800h
+ sub eax, [ebp+esi*4+284B0h]
+ mov esi, [ebp+ebx*4+28420h]
+ mov ebx, [esp+90h+var_6C]
+ shr eax, 2
+ mov eax, dword_550998[eax*4]
+ shr esi, 2
+ add eax, dword_550998[esi*4]
+ mov esi, [esp+90h+var_7C]
+ add eax, [ebp+ecx*4+2E204h]
+ lea ecx, [edi+edi*4+1Eh]
+ add eax, edx
+ cmp eax, [ebp+ecx*8+0Ch]
+ lea ecx, [ebp+ecx*8+0]
+ jnb short loc_4CEA94
+ mov edx, [esp+90h+var_78]
+ add edx, 1
+ mov [ecx+0Ch], eax
+ mov [ecx+10h], edx
+ mov dword ptr [ecx+14h], 0
+ mov byte ptr [ecx+1], 1
+ mov byte ptr [ecx+2], 0
+ jmp short loc_4CEA94
+; ---------------------------------------------------------------------------
+
+loc_4CEA90: ; CODE XREF: CEncoder_GetOptimum+8C8j
+ ; CEncoder_GetOptimum+8D6j ...
+ mov esi, [esp+90h+var_7C]
+
+loc_4CEA94: ; CODE XREF: CEncoder_GetOptimum+A10j
+ ; CEncoder_GetOptimum+A2Ej
+ mov [esp+90h+var_70], 0
+ mov ecx, [esp+90h+var_70]
+ mov [esp+90h+var_40], 2
+ jmp short loc_4CEAB8
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CEAB0: ; CODE XREF: CEncoder_GetOptimum+D63j
+ mov ebx, [esp+90h+var_6C]
+ mov esi, [esp+90h+var_7C]
+
+loc_4CEAB8: ; CODE XREF: CEncoder_GetOptimum+A48j
+ mov edx, [esp+90h+var_74]
+ mov eax, edx
+ sub eax, [esp+ecx*4+90h+var_20]
+ mov cl, [edx]
+ sub eax, 1
+ cmp cl, [eax]
+ mov [esp+90h+var_48], eax
+ jnz loc_4CEDB5
+ mov cl, [edx+1]
+ cmp cl, [eax+1]
+ jnz loc_4CEDB5
+ mov edi, 2
+ cmp ebx, edi
+ jbe short loc_4CEB01
+ lea ecx, [edx+2]
+ sub eax, edx
+ lea ecx, [ecx+0]
+
+loc_4CEAF0: ; CODE XREF: CEncoder_GetOptimum+A9Fj
+ mov dl, [ecx]
+ cmp dl, [eax+ecx]
+ jnz short loc_4CEB01
+ add edi, 1
+ add ecx, 1
+ cmp edi, ebx
+ jb short loc_4CEAF0
+
+loc_4CEB01: ; CODE XREF: CEncoder_GetOptimum+A86j
+ ; CEncoder_GetOptimum+A95j
+ mov eax, [esp+90h+var_78]
+ lea ebx, [edi+eax]
+ cmp esi, ebx
+ jnb short loc_4CEB2E
+ mov eax, ebx
+ lea ecx, [esi+esi*4]
+ sub eax, esi
+ add esi, eax
+ lea ecx, [ebp+ecx*8+0FCh]
+ mov [esp+90h+var_7C], esi
+
+loc_4CEB20: ; CODE XREF: CEncoder_GetOptimum+ACCj
+ add ecx, 28h
+ sub eax, 1
+ mov dword ptr [ecx], 0FFFFFFFh
+ jnz short loc_4CEB20
+
+loc_4CEB2E: ; CODE XREF: CEncoder_GetOptimum+AAAj
+ mov edx, [esp+90h+var_54]
+ mov eax, [esp+90h+var_64]
+ mov ecx, [esp+90h+var_70]
+ push edx
+ push eax
+ push ecx
+ mov ecx, ebp
+ mov esi, edi
+ call sub_4CD9B0
+ add eax, [esp+90h+var_38]
+ mov ecx, [esp+90h+var_54]
+ imul ecx, 110h
+ lea edx, [edi+ecx]
+ mov [esp+90h+var_34], ecx
+ lea ecx, [ebp+edx*4+2E204h]
+ mov [esp+90h+var_50], ecx
+ lea edx, [ebx+ebx*4]
+ mov ebx, [esp+90h+var_50]
+ mov [esp+90h+var_2C], eax
+ lea ecx, [ebp+edx*8+0FCh]
+
+loc_4CEB78: ; CODE XREF: CEncoder_GetOptimum+B40j
+ mov edx, [ebx]
+ add edx, eax
+ cmp edx, [ecx]
+ jnb short loc_4CEB94
+ mov [ecx], edx
+ mov edx, [esp+90h+var_78]
+ mov [ecx+4], edx
+ mov edx, [esp+90h+var_70]
+ mov [ecx+8], edx
+ mov byte ptr [ecx-0Bh], 0
+
+loc_4CEB94: ; CODE XREF: CEncoder_GetOptimum+B1Ej
+ sub edi, 1
+ sub ebx, 4
+ sub ecx, 28h
+ cmp edi, 2
+ jnb short loc_4CEB78
+ cmp [esp+90h+var_70], 0
+ jnz short loc_4CEBB0
+ lea eax, [esi+1]
+ mov [esp+90h+var_40], eax
+
+loc_4CEBB0: ; CODE XREF: CEncoder_GetOptimum+B47j
+ mov ecx, [ebp+32EF8h]
+ mov edx, [esp+90h+var_60]
+ lea eax, [esi+1]
+ add ecx, eax
+ cmp edx, ecx
+ jnb short loc_4CEBC5
+ mov ecx, edx
+
+loc_4CEBC5: ; CODE XREF: CEncoder_GetOptimum+B61j
+ cmp eax, ecx
+ jnb short loc_4CEBE7
+ mov ebx, [esp+90h+var_74]
+ mov edi, [esp+90h+var_48]
+ lea edx, [eax+ebx]
+ sub edi, ebx
+
+loc_4CEBD6: ; CODE XREF: CEncoder_GetOptimum+B85j
+ mov bl, [edx]
+ cmp bl, [edx+edi]
+ jnz short loc_4CEBE7
+ add eax, 1
+ add edx, 1
+ cmp eax, ecx
+ jb short loc_4CEBD6
+
+loc_4CEBE7: ; CODE XREF: CEncoder_GetOptimum+B67j
+ ; CEncoder_GetOptimum+B7Bj
+ or ecx, 0FFFFFFFFh
+ sub ecx, esi
+ add eax, ecx
+ cmp eax, 2
+ mov [esp+90h+var_44], eax
+ jb loc_4CEDB5
+ mov edx, [esp+90h+var_68]
+ mov cl, ds:kRepNextStates[edx]
+ mov eax, [ebp+33B60h]
+ mov edi, [esp+90h+arg_0]
+ movzx ecx, cl
+ mov ebx, eax
+ lea edx, [esi+edi]
+ and ebx, edx
+ mov edx, ecx
+ mov cl, ds:kLiteralNextStates[ecx]
+ shl edx, 4
+ add ebx, edx
+ mov edx, [ebp+ebx*4+280F0h]
+ movzx ebx, cl
+ shr edx, 2
+ mov edx, dword_550998[edx*4]
+ mov [esp+90h+var_30], edx
+ lea edi, [esi+edi+1]
+ and edi, eax
+ mov eax, [ebp+32654h]
+ mov ecx, ebx
+ shl ecx, 4
+ add ecx, edi
+ mov [esp+90h+var_50], ecx
+ mov ecx, [esp+90h+var_74]
+ movzx edx, byte ptr [esi+ecx]
+ push edx
+ mov edx, [esp+94h+var_48]
+ movzx edx, byte ptr [esi+edx]
+ push edx
+ movzx edx, byte ptr [ecx+esi-1]
+ mov ecx, 8
+ sub cl, al
+ shr edx, cl
+ mov ecx, [esp+98h+arg_0]
+ lea eax, [esi+ecx]
+ mov ecx, [ebp+3265Ch]
+ and ecx, eax
+ mov eax, ecx
+ mov ecx, [ebp+32654h]
+ shl eax, cl
+ push 1
+ add edx, eax
+ imul edx, 0C00h
+ add edx, [ebp+32650h]
+ mov ecx, edx
+ call sub_4CDAC0
+ mov ecx, [esp+90h+var_50]
+ mov edx, 800h
+ sub edx, [ebp+ecx*4+280F0h]
+ mov ecx, [esp+90h+var_34]
+ shr edx, 2
+ add eax, dword_550998[edx*4]
+ mov edx, 800h
+ sub edx, [ebp+ebx*4+283F0h]
+ shr edx, 2
+ add eax, dword_550998[edx*4]
+ lea edx, [esi+ecx]
+ add eax, [ebp+edx*4+2E204h]
+ mov ecx, [esp+90h+var_44]
+ add eax, [esp+90h+var_30]
+ mov edx, [esp+90h+var_78]
+ add eax, [esp+90h+var_2C]
+ add ecx, esi
+ lea ecx, [ecx+edx+1]
+ cmp [esp+90h+var_7C], ecx
+ mov [esp+90h+var_30], ecx
+ jnb short loc_4CED3E
+ mov edx, [esp+90h+var_7C]
+ lea edx, [edx+edx*4]
+ lea edx, [ebp+edx*8+0FCh]
+ mov [esp+90h+var_2C], edx
+ mov edx, [esp+90h+var_7C]
+ sub ecx, edx
+ add edx, ecx
+ mov [esp+90h+var_7C], edx
+ mov edx, [esp+90h+var_2C]
+ jmp short loc_4CED30
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CED30: ; CODE XREF: CEncoder_GetOptimum+CCBj
+ ; CEncoder_GetOptimum+CDCj
+ add edx, 28h
+ sub ecx, 1
+ mov dword ptr [edx], 0FFFFFFFh
+ jnz short loc_4CED30
+
+loc_4CED3E: ; CODE XREF: CEncoder_GetOptimum+CA7j
+ mov edx, [esp+90h+var_50]
+ imul edi, 110h
+ add edi, [esp+90h+var_44]
+ mov ecx, 800h
+ sub ecx, [ebp+edx*4+284B0h]
+ mov edx, [ebp+ebx*4+28420h]
+ shr ecx, 2
+ mov ecx, dword_550998[ecx*4]
+ shr edx, 2
+ add ecx, dword_550998[edx*4]
+ add ecx, [ebp+edi*4+2E204h]
+ add ecx, eax
+ mov eax, [esp+90h+var_30]
+ lea eax, [eax+eax*4+1Eh]
+ cmp ecx, [ebp+eax*8+0Ch]
+ lea eax, [ebp+eax*8+0]
+ jnb short loc_4CEDB5
+ mov [eax+0Ch], ecx
+ mov ecx, [esp+90h+var_78]
+ lea edx, [esi+ecx+1]
+ mov [eax+4], ecx
+ mov ecx, [esp+90h+var_70]
+ mov [eax+10h], edx
+ mov dword ptr [eax+14h], 0
+ mov byte ptr [eax+1], 1
+ mov byte ptr [eax+2], 1
+ mov [eax+8], ecx
+
+loc_4CEDB5: ; CODE XREF: CEncoder_GetOptimum+A6Dj
+ ; CEncoder_GetOptimum+A79j ...
+ mov ecx, [esp+90h+var_70]
+ add ecx, 1
+ cmp ecx, 4
+ mov [esp+90h+var_70], ecx
+ jb loc_4CEAB0
+ mov edx, [esp+90h+var_28]
+ mov ecx, [esp+90h+var_6C]
+ cmp edx, ecx
+ jbe short loc_4CEDFB
+ xor eax, eax
+ cmp ecx, [ebp+32660h]
+ mov edx, ecx
+ jbe short loc_4CEDED
+
+loc_4CEDE1: ; CODE XREF: CEncoder_GetOptimum+D8Bj
+ add eax, 2
+ cmp ecx, [ebp+eax*4+32660h]
+ ja short loc_4CEDE1
+
+loc_4CEDED: ; CODE XREF: CEncoder_GetOptimum+D7Fj
+ mov [ebp+eax*4+32660h], ecx
+ add eax, 2
+ mov [esp+90h+var_4C], eax
+
+loc_4CEDFB: ; CODE XREF: CEncoder_GetOptimum+D73j
+ mov esi, [esp+90h+var_40]
+ cmp edx, esi
+ jb loc_4CF1BB
+ mov eax, [esp+90h+var_68]
+ mov ecx, [ebp+eax*4+283F0h]
+ shr ecx, 2
+ mov eax, dword_550998[ecx*4]
+ add eax, [esp+90h+var_24]
+ mov ecx, [esp+90h+var_7C]
+ mov [esp+90h+var_40], eax
+ mov eax, [esp+90h+var_78]
+ add eax, edx
+ cmp ecx, eax
+ jnb short loc_4CEE52
+ lea edx, [ecx+ecx*4]
+ sub eax, ecx
+ add ecx, eax
+ lea edx, [ebp+edx*8+0FCh]
+ mov [esp+90h+var_7C], ecx
+
+loc_4CEE44: ; CODE XREF: CEncoder_GetOptimum+DF0j
+ add edx, 28h
+ sub eax, 1
+ mov dword ptr [edx], 0FFFFFFFh
+ jnz short loc_4CEE44
+
+loc_4CEE52: ; CODE XREF: CEncoder_GetOptimum+DD0j
+ xor eax, eax
+ cmp esi, [ebp+32660h]
+ mov [esp+90h+var_70], eax
+ jbe short loc_4CEE70
+
+loc_4CEE60: ; CODE XREF: CEncoder_GetOptimum+E0Aj
+ add eax, 2
+ cmp esi, [ebp+eax*4+32660h]
+ ja short loc_4CEE60
+ mov [esp+90h+var_70], eax
+
+loc_4CEE70: ; CODE XREF: CEncoder_GetOptimum+DFEj
+ lea ebx, ds:0[eax*4]
+ mov edx, [ebx+ebp+32664h]
+ mov ecx, 7FFFFh
+ sub ecx, edx
+ sar ecx, 1Fh
+ and ecx, 0Ch
+ add ecx, 6
+ mov eax, edx
+ shr eax, cl
+ mov [esp+90h+var_6C], edx
+ lea edi, [esi+1]
+ movzx eax, byte ptr dword_551198[eax]
+ lea ecx, [eax+ecx*2]
+ mov eax, [esp+90h+var_54]
+ imul eax, 110h
+ add eax, esi
+ lea eax, [ebp+eax*4+295B8h]
+ mov [esp+90h+var_3C], ecx
+ mov ecx, [esp+90h+var_78]
+ mov [esp+90h+var_54], eax
+ lea eax, [esi+ecx]
+ lea eax, [eax+eax*4]
+ lea ecx, [ebp+eax*8+0FCh]
+ mov [esp+90h+var_50], ecx
+
+loc_4CEED3: ; CODE XREF: CEncoder_GetOptimum+1156j
+ lea eax, [edi-3]
+ cmp eax, 4
+ jb short loc_4CEEE0
+ mov eax, 3
+
+loc_4CEEE0: ; CODE XREF: CEncoder_GetOptimum+E79j
+ cmp edx, 80h
+ jnb short loc_4CEEF6
+ shl eax, 7
+ add eax, edx
+ mov eax, [ebp+eax*4+33314h]
+ jmp short loc_4CEF10
+; ---------------------------------------------------------------------------
+
+loc_4CEEF6: ; CODE XREF: CEncoder_GetOptimum+E86j
+ shl eax, 6
+ add eax, [esp+90h+var_3C]
+ mov esi, edx
+ mov eax, [ebp+eax*4+32F14h]
+ and esi, 0Fh
+ add eax, [ebp+esi*4+33B14h]
+
+loc_4CEF10: ; CODE XREF: CEncoder_GetOptimum+E94j
+ add eax, [esp+90h+var_40]
+ mov esi, [esp+90h+var_54]
+ add eax, [esi]
+ cmp eax, [ecx]
+ mov [esp+90h+var_2C], eax
+ jnb short loc_4CEF35
+ mov [ecx], eax
+ mov eax, [esp+90h+var_78]
+ add edx, 4
+ mov [ecx+4], eax
+ mov [ecx+8], edx
+ mov byte ptr [ecx-0Bh], 0
+
+loc_4CEF35: ; CODE XREF: CEncoder_GetOptimum+EC0j
+ lea eax, [edi-1]
+ cmp eax, [ebx+ebp+32660h]
+ jnz loc_4CF1A1
+ mov ebx, [esp+90h+var_74]
+ mov eax, [ebp+32EF8h]
+ mov esi, [esp+90h+var_60]
+ mov edx, ebx
+ sub edx, [esp+90h+var_6C]
+ add eax, edi
+ sub edx, 1
+ cmp esi, eax
+ mov ecx, edi
+ jnb short loc_4CEF6C
+ mov eax, esi
+ mov [esp+90h+var_44], esi
+ jmp short loc_4CEF70
+; ---------------------------------------------------------------------------
+
+loc_4CEF6C: ; CODE XREF: CEncoder_GetOptimum+F02j
+ mov [esp+90h+var_44], eax
+
+loc_4CEF70: ; CODE XREF: CEncoder_GetOptimum+F0Aj
+ cmp edi, eax
+ jnb short loc_4CEF93
+ lea esi, [edi+edx]
+ sub ebx, edx
+ lea esp, [esp+0]
+
+loc_4CEF80: ; CODE XREF: CEncoder_GetOptimum+F31j
+ mov al, [ebx+esi]
+ cmp al, [esi]
+ jnz short loc_4CEF93
+ add ecx, 1
+ add esi, 1
+ cmp ecx, [esp+90h+var_44]
+ jb short loc_4CEF80
+
+loc_4CEF93: ; CODE XREF: CEncoder_GetOptimum+F12j
+ ; CEncoder_GetOptimum+F25j
+ or esi, 0FFFFFFFFh
+ lea eax, [edi-1]
+ sub esi, eax
+ add ecx, esi
+ cmp ecx, 2
+ mov [esp+90h+var_48], ecx
+ jb loc_4CF157
+ mov ecx, [esp+90h+var_68]
+ mov bl, ds:kMatchNextStates[ecx]
+ mov ecx, [ebp+33B60h]
+ mov eax, [esp+90h+arg_0]
+ lea esi, [edi+eax-1]
+ mov eax, ecx
+ and eax, esi
+ movzx esi, bl
+ movzx edx, byte ptr [edi+edx-1]
+ mov ebx, esi
+ shl ebx, 4
+ add ebx, eax
+ mov ebx, [ebp+ebx*4+280F0h]
+ shr ebx, 2
+ mov ebx, dword_550998[ebx*4]
+ mov [esp+90h+var_28], ebx
+ mov bl, ds:kLiteralNextStates[esi]
+ lea esi, [eax+1]
+ mov eax, [ebp+32654h]
+ and esi, ecx
+ movzx ebx, bl
+ mov ecx, ebx
+ shl ecx, 4
+ add ecx, esi
+ mov [esp+90h+var_44], ecx
+ mov ecx, [esp+90h+var_74]
+ movzx ecx, byte ptr [ecx+edi-1]
+ push ecx
+ mov ecx, [esp+94h+var_74]
+ push edx
+ movzx edx, byte ptr [edi+ecx-2]
+ mov ecx, 8
+ sub cl, al
+ shr edx, cl
+ mov ecx, [esp+98h+arg_0]
+ lea eax, [edi+ecx-1]
+ mov ecx, [ebp+3265Ch]
+ and ecx, eax
+ mov eax, ecx
+ mov ecx, [ebp+32654h]
+ shl eax, cl
+ push 1
+ add edx, eax
+ imul edx, 0C00h
+ add edx, [ebp+32650h]
+ mov ecx, edx
+ call sub_4CDAC0
+ mov edx, 800h
+ sub edx, [ebp+ebx*4+283F0h]
+ mov ecx, 800h
+ shr edx, 2
+ add eax, dword_550998[edx*4]
+ mov edx, [esp+90h+var_44]
+ sub ecx, [ebp+edx*4+280F0h]
+ mov edx, [esp+90h+var_78]
+ shr ecx, 2
+ add eax, dword_550998[ecx*4]
+ mov ecx, [esp+90h+var_48]
+ add eax, [esp+90h+var_28]
+ add ecx, edx
+ add eax, [esp+90h+var_2C]
+ add ecx, edi
+ cmp [esp+90h+var_7C], ecx
+ mov [esp+90h+var_28], ecx
+ jnb short loc_4CF0DE
+ mov edx, [esp+90h+var_7C]
+ lea edx, [edx+edx*4]
+ lea edx, [ebp+edx*8+0FCh]
+ mov [esp+90h+var_24], edx
+ mov edx, [esp+90h+var_7C]
+ sub ecx, edx
+ add edx, ecx
+ mov [esp+90h+var_7C], edx
+ mov edx, [esp+90h+var_24]
+ lea ecx, [ecx+0]
+
+loc_4CF0D0: ; CODE XREF: CEncoder_GetOptimum+107Cj
+ add edx, 28h
+ sub ecx, 1
+ mov dword ptr [edx], 0FFFFFFFh
+ jnz short loc_4CF0D0
+
+loc_4CF0DE: ; CODE XREF: CEncoder_GetOptimum+1049j
+ mov edx, [esp+90h+var_44]
+ imul esi, 110h
+ add esi, [esp+90h+var_48]
+ mov ecx, 800h
+ sub ecx, [ebp+edx*4+284B0h]
+ mov edx, [ebp+ebx*4+28420h]
+ shr ecx, 2
+ mov ecx, dword_550998[ecx*4]
+ shr edx, 2
+ add ecx, dword_550998[edx*4]
+ add ecx, [ebp+esi*4+2E204h]
+ add ecx, eax
+ mov eax, [esp+90h+var_28]
+ lea eax, [eax+eax*4+1Eh]
+ cmp ecx, [ebp+eax*8+0Ch]
+ lea eax, [ebp+eax*8+0]
+ jnb short loc_4CF157
+ mov [eax+0Ch], ecx
+ mov ecx, [esp+90h+var_78]
+ lea edx, [ecx+edi]
+ mov [eax+4], ecx
+ mov ecx, [esp+90h+var_6C]
+ add ecx, 4
+ mov [eax+10h], edx
+ mov dword ptr [eax+14h], 0
+ mov byte ptr [eax+1], 1
+ mov byte ptr [eax+2], 1
+ mov [eax+8], ecx
+
+loc_4CF157: ; CODE XREF: CEncoder_GetOptimum+F44j
+ ; CEncoder_GetOptimum+10CCj
+ mov eax, [esp+90h+var_70]
+ add eax, 2
+ cmp eax, [esp+90h+var_4C]
+ mov [esp+90h+var_70], eax
+ jz short loc_4CF1BB
+ lea ebx, ds:0[eax*4]
+ mov eax, [ebx+ebp+32664h]
+ cmp eax, 80h
+ mov [esp+90h+var_6C], eax
+ jb short loc_4CF1A1
+ mov ecx, 7FFFFh
+ sub ecx, eax
+ sar ecx, 1Fh
+ and ecx, 0Ch
+ add ecx, 6
+ shr eax, cl
+ movzx edx, byte ptr dword_551198[eax]
+ lea eax, [edx+ecx*2]
+ mov [esp+90h+var_3C], eax
+
+loc_4CF1A1: ; CODE XREF: CEncoder_GetOptimum+EDFj
+ ; CEncoder_GetOptimum+111Fj
+ add [esp+90h+var_50], 28h
+ add [esp+90h+var_54], 4
+ mov ecx, [esp+90h+var_50]
+ mov edx, [esp+90h+var_6C]
+ add edi, 1
+ jmp loc_4CEED3
+; ---------------------------------------------------------------------------
+
+loc_4CF1BB: ; CODE XREF: CEncoder_GetOptimum+8A9j
+ ; CEncoder_GetOptimum+DA1j ...
+ mov eax, [esp+90h+var_78]
+ add eax, 1
+ cmp eax, [esp+90h+var_7C]
+ mov [esp+90h+var_78], eax
+ jnz loc_4CE5D1
+
+loc_4CF1D0: ; CODE XREF: CEncoder_GetOptimum+567j
+ mov ecx, [esp+90h+var_78]
+ push ecx
+ jmp short loc_4CF1EF
+; ---------------------------------------------------------------------------
+
+loc_4CF1D7: ; CODE XREF: CEncoder_GetOptimum+59Ej
+ mov ecx, [esp+90h+var_4C]
+ mov [ebp+32F00h], ecx
+ mov [ebp+32EFCh], eax
+ mov byte ptr [ebp+32F10h], 1
+ push esi
+
+loc_4CF1EF: ; CODE XREF: CEncoder_GetOptimum+1175j
+ mov edx, [esp+94h+arg_4]
+ push edx
+ mov ecx, ebp
+ call sub_4CB2E0
+ pop edi
+ pop ebx
+ pop esi
+ pop ebp
+ add esp, 80h
+ retn 8
+CEncoder_GetOptimum endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CF210: ; DATA XREF: CEncoder_CodeOneBlock+44o
+ mov edx, [esp+10h]
+ mov eax, [esp+4]
+ mov eax, [eax+4]
+ mov ecx, [eax]
+ push edx
+ mov edx, [esp+10h]
+ push edx
+ mov edx, [esp+10h]
+ push edx
+ push eax
+ mov eax, [ecx+0Ch]
+ call eax
+ retn
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+CEncoder_FillDistancesPrices proc near ; CODE XREF: CEncoder_SetStreams+4Fp
+ ; CEncoder_CodeOneBlock+751p
+
+var_20C = dword ptr -20Ch
+var_208 = dword ptr -208h
+var_204 = dword ptr -204h
+var_200 = dword ptr -200h
+
+ sub esp, 20Ch
+ push ebx
+ push ebp
+ push esi
+ push edi
+ mov ebx, ecx
+ mov esi, 4
+
+loc_4CF241: ; CODE XREF: CEncoder_FillDistancesPrices+80j
+ cmp esi, 2000h
+ jnb short loc_4CF252
+ movzx edx, byte ptr dword_551198[esi]
+ jmp short loc_4CF27A
+; ---------------------------------------------------------------------------
+
+loc_4CF252: ; CODE XREF: CEncoder_FillDistancesPrices+17j
+ cmp esi, 2000000h
+ jnb short loc_4CF26B
+ mov eax, esi
+ shr eax, 0Ch
+ movzx edx, byte ptr dword_551198[eax]
+ add edx, 18h
+ jmp short loc_4CF27A
+; ---------------------------------------------------------------------------
+
+loc_4CF26B: ; CODE XREF: CEncoder_FillDistancesPrices+28j
+ mov ecx, esi
+ shr ecx, 18h
+ movzx edx, byte ptr dword_551198[ecx]
+ add edx, 30h
+
+loc_4CF27A: ; CODE XREF: CEncoder_FillDistancesPrices+20j
+ ; CEncoder_FillDistancesPrices+39j
+ mov ecx, edx
+ mov eax, edx
+ and eax, 1
+ shr ecx, 1
+ sub ecx, 1
+ or eax, 2
+ shl eax, cl
+ mov edi, esi
+ sub edi, eax
+ push edi
+ sub eax, edx
+ push ecx
+ lea edx, [ebx+eax*4+28BACh]
+ push edx
+ call sub_4CD860
+ mov [esp+esi*4+228h+var_200], eax
+ add esi, 1
+ add esp, 0Ch
+ cmp esi, 80h
+ jb short loc_4CF241
+ lea ebp, [esp+21Ch+var_200]
+ sub ebp, ebx
+ lea esi, [ebx+3331Ch]
+ sub ebp, 33314h
+ lea edx, [ebx+32F14h]
+ mov [esp+21Ch+var_20C], esi
+ mov [esp+21Ch+var_208], ebp
+ mov [esp+21Ch+var_204], 4
+ jmp short loc_4CF2E4
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CF2E0: ; CODE XREF: CEncoder_FillDistancesPrices+1BDj
+ mov esi, [esp+21Ch+var_20C]
+
+loc_4CF2E4: ; CODE XREF: CEncoder_FillDistancesPrices+AAj
+ xor edi, edi
+ cmp [ebx+33B58h], edi
+ jbe short loc_4CF33F
+ mov edi, edi
+
+loc_4CF2F0: ; CODE XREF: CEncoder_FillDistancesPrices+109j
+ mov ecx, edi
+ or ecx, 40h
+ xor esi, esi
+ cmp ecx, 1
+ jz short loc_4CF32D
+ lea esp, [esp+0]
+
+loc_4CF300: ; CODE XREF: CEncoder_FillDistancesPrices+F7j
+ mov eax, ecx
+ shr ecx, 1
+ mov ebp, [edx+ecx*4-0A764h]
+ and eax, 1
+ sub ebp, eax
+ neg eax
+ xor ebp, eax
+ shr ebp, 2
+ and ebp, 1FFh
+ add esi, dword_550998[ebp*4]
+ cmp ecx, 1
+ jnz short loc_4CF300
+ mov ebp, [esp+21Ch+var_208]
+
+loc_4CF32D: ; CODE XREF: CEncoder_FillDistancesPrices+CAj
+ mov [edx+edi*4], esi
+ add edi, 1
+ cmp edi, [ebx+33B58h]
+ jb short loc_4CF2F0
+ mov esi, [esp+21Ch+var_20C]
+
+loc_4CF33F: ; CODE XREF: CEncoder_FillDistancesPrices+BCj
+ mov eax, 0Eh
+ cmp [ebx+33B58h], eax
+ jbe short loc_4CF368
+ lea esp, [esp+0]
+
+loc_4CF350: ; CODE XREF: CEncoder_FillDistancesPrices+136j
+ mov ecx, eax
+ shr ecx, 1
+ sub ecx, 5
+ shl ecx, 6
+ add [edx+eax*4], ecx
+ add eax, 1
+ cmp eax, [ebx+33B58h]
+ jb short loc_4CF350
+
+loc_4CF368: ; CODE XREF: CEncoder_FillDistancesPrices+11Aj
+ mov eax, [edx]
+ mov [esi-8], eax
+ mov ecx, [edx+4]
+ mov [esi-4], ecx
+ mov eax, [edx+8]
+ mov [esi], eax
+ mov ecx, [edx+0Ch]
+ mov [esi+4], ecx
+ mov eax, 4
+ add esi, 8
+
+loc_4CF386: ; CODE XREF: CEncoder_FillDistancesPrices+19Ej
+ cmp eax, 2000h
+ jnb short loc_4CF396
+ movzx ecx, byte ptr dword_551198[eax]
+ jmp short loc_4CF3BB
+; ---------------------------------------------------------------------------
+
+loc_4CF396: ; CODE XREF: CEncoder_FillDistancesPrices+15Bj
+ cmp eax, 2000000h
+ mov ecx, eax
+ jnb short loc_4CF3AE
+ shr ecx, 0Ch
+ movzx ecx, byte ptr dword_551198[ecx]
+ add ecx, 18h
+ jmp short loc_4CF3BB
+; ---------------------------------------------------------------------------
+
+loc_4CF3AE: ; CODE XREF: CEncoder_FillDistancesPrices+16Dj
+ shr ecx, 18h
+ movzx ecx, byte ptr dword_551198[ecx]
+ add ecx, 30h
+
+loc_4CF3BB: ; CODE XREF: CEncoder_FillDistancesPrices+164j
+ ; CEncoder_FillDistancesPrices+17Cj
+ mov ecx, [edx+ecx*4]
+ add ecx, [esi+ebp]
+ add eax, 1
+ mov [esi], ecx
+ add esi, 4
+ cmp eax, 80h
+ jb short loc_4CF386
+ add [esp+21Ch+var_20C], 200h
+ sub ebp, 200h
+ add edx, 100h
+ sub [esp+21Ch+var_204], 1
+ mov [esp+21Ch+var_208], ebp
+ jnz loc_4CF2E0
+ pop edi
+ pop esi
+ pop ebp
+ mov dword ptr [ebx+33B70h], 0
+ pop ebx
+ add esp, 20Ch
+ retn
+CEncoder_FillDistancesPrices endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+CEncoder_FillAlignPrices proc near ; CODE XREF: CEncoder_SetStreams+56p
+ ; CEncoder_CodeOneBlock+761p
+ push ebx
+ push ebp
+ push esi
+ mov ebp, ecx
+ push edi
+ xor esi, esi
+ lea ebx, [ebp+28D78h]
+ lea edi, [ebp+33B14h]
+
+loc_4CF424: ; CODE XREF: CEncoder_FillAlignPrices+27j
+ push esi
+ mov ecx, ebx
+ call sub_4CD810
+ mov [edi], eax
+ add esi, 1
+ add edi, 4
+ cmp esi, 10h
+ jb short loc_4CF424
+ pop edi
+ pop esi
+ mov dword ptr [ebp+33B54h], 0
+ pop ebp
+ pop ebx
+ retn
+CEncoder_FillAlignPrices endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CF810 proc near ; CODE XREF: sub_4D0250+3p
+
+var_10 = dword ptr -10h
+var_C = dword ptr -0Ch
+var_4 = dword ptr -4
+
+ push 0FFFFFFFFh
+ push offset loc_4DA0C9
+ mov eax, dword ptr fs:[0]
+ push eax
+ push ecx
+ push ebx
+ push esi
+ mov eax, dword_544960
+ xor eax, esp
+ push eax
+ lea eax, [esp+1Ch+var_C]
+ mov dword ptr fs:[0], eax
+ mov esi, ecx
+ mov [esp+1Ch+var_10], esi
+ mov dword ptr [esi], offset NCompress_NLZMA_CEncoder_vftable
+ mov dword ptr [esi+4], offset NCompress_NLZMA_CEncoder_vftable_ICompressSetOutStream
+ mov dword ptr [esi+8], offset NCompress_NLZMA_CEncoder_vftable_ICompressSetCoderProperties
+ mov dword ptr [esi+0Ch], offset NCompress_NLZMA_CEncoder_vftable_ICompressWriteCoderProperties
+ mov eax, [esi+0A4h]
+ push eax ; lpAddress
+ mov [esp+20h+var_4], 1
+ call off_546E24
+ xor ebx, ebx
+ add esp, 4
+ cmp [esi+0D0h], ebx
+ mov [esi+0A4h], ebx
+ jnz short loc_4CF892
+ mov ecx, [esi+0B4h]
+ push ecx ; lpAddress
+ call off_546E24
+ add esp, 4
+ mov [esi+0B4h], ebx
+
+loc_4CF892: ; CODE XREF: sub_4CF810+6Aj
+ mov eax, [esi+33B8Ch]
+ cmp eax, ebx
+ jz short loc_4CF8A4
+ mov edx, [eax]
+ push eax
+ mov eax, [edx+8]
+ call eax
+
+loc_4CF8A4: ; CODE XREF: sub_4CF810+8Aj
+ lea ecx, [esi+32650h]
+ mov byte ptr [esp+1Ch+var_4], bl
+ call sub_4CD8F0
+ mov eax, [esi+40h]
+ cmp eax, ebx
+ mov [esp+1Ch+var_4], 0FFFFFFFFh
+ jz short loc_4CF8CF
+ push 8000h ; dwFreeType
+ push ebx ; dwSize
+ push eax ; lpAddress
+ call ds:VirtualFree
+
+loc_4CF8CF: ; CODE XREF: sub_4CF810+B0j
+ mov [esi+40h], ebx
+ mov esi, [esi+54h]
+ cmp esi, ebx
+ jz short loc_4CF8E1
+ mov ecx, [esi]
+ mov edx, [ecx+8]
+ push esi
+ call edx
+
+loc_4CF8E1: ; CODE XREF: sub_4CF810+C7j
+ mov ecx, [esp+1Ch+var_C]
+ mov dword ptr fs:[0], ecx
+ pop ecx
+ pop esi
+ pop ebx
+ add esp, 10h
+ retn
+sub_4CF810 endp
+
+; =============== S U B R O U T I N E =======================================
+
+; int __stdcall sub_4CF900(int, void *Buf1, int)
+sub_4CF900 proc near ; CODE XREF: sub_4CFA20+5j
+ ; ICompressSetCoderProperties_QueryInterface+5j ...
+
+arg_0 = dword ptr 4
+Buf1 = dword ptr 8
+arg_8 = dword ptr 0Ch
+
+ push esi
+ mov esi, [esp+4+Buf1]
+ push offset dword_512730 ; Buf2
+ push esi ; Buf1
+ call unknown_libname_324 ; MFC 3.1/4.0/4.2/8.0 32bit
+ add esp, 8
+ test eax, eax
+ jz short loc_4CF94C
+
+loc_4CF917: ; CODE XREF: sub_4CF900+5Cj
+ mov eax, [esp+4+arg_0]
+ test eax, eax
+ jz short loc_4CF936
+ mov edx, [esp+4+arg_8]
+ lea ecx, [eax+4]
+ mov [edx], ecx
+ mov ecx, [eax]
+ mov edx, [ecx+4]
+ push eax
+ call edx
+ xor eax, eax
+ pop esi
+ retn 0Ch
+; ---------------------------------------------------------------------------
+
+loc_4CF936: ; CODE XREF: sub_4CF900+1Dj
+ ; sub_4CF900+76j ...
+ mov edx, [esp+4+arg_8]
+ xor ecx, ecx
+ mov [edx], ecx
+ mov ecx, [eax]
+ mov edx, [ecx+4]
+ push eax
+ call edx
+ xor eax, eax
+ pop esi
+ retn 0Ch
+; ---------------------------------------------------------------------------
+
+loc_4CF94C: ; CODE XREF: sub_4CF900+15j
+ push offset dword_5535A0 ; Buf2
+ push esi ; Buf1
+ call unknown_libname_324 ; MFC 3.1/4.0/4.2/8.0 32bit
+ add esp, 8
+ test eax, eax
+ jnz short loc_4CF917
+ push offset dword_5535B0 ; Buf2
+ push esi ; Buf1
+ call unknown_libname_324 ; MFC 3.1/4.0/4.2/8.0 32bit
+ add esp, 8
+ test eax, eax
+ jz short loc_4CF98F
+ mov eax, [esp+4+arg_0]
+ test eax, eax
+ jz short loc_4CF936
+ mov edx, [esp+4+arg_8]
+ lea ecx, [eax+8]
+ mov [edx], ecx
+ mov ecx, [eax]
+ mov edx, [ecx+4]
+ push eax
+ call edx
+ xor eax, eax
+ pop esi
+ retn 0Ch
+; ---------------------------------------------------------------------------
+
+loc_4CF98F: ; CODE XREF: sub_4CF900+6Ej
+ push offset dword_5535C0 ; Buf2
+ push esi ; Buf1
+ call unknown_libname_324 ; MFC 3.1/4.0/4.2/8.0 32bit
+ add esp, 8
+ test eax, eax
+ jz short loc_4CF9C0
+ mov eax, [esp+4+arg_0]
+ test eax, eax
+ jz short loc_4CF936
+ mov edx, [esp+4+arg_8]
+ lea ecx, [eax+0Ch]
+ mov [edx], ecx
+ mov ecx, [eax]
+ mov edx, [ecx+4]
+ push eax
+ call edx
+ xor eax, eax
+ pop esi
+ retn 0Ch
+; ---------------------------------------------------------------------------
+
+loc_4CF9C0: ; CODE XREF: sub_4CF900+9Fj
+ mov eax, 80004002h
+ pop esi
+ retn 0Ch
+sub_4CF900 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CF9D0 proc near ; CODE XREF: ICompressSetCoderProperties_AddRef+5j
+ ; sub_4CFA10+5j ...
+
+arg_0 = dword ptr 4
+
+ mov eax, [esp+arg_0]
+ add dword ptr [eax+24h], 1
+ mov eax, [eax+24h]
+ retn 4
+sub_4CF9D0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CF9E0 proc near ; CODE XREF: sub_4CFA40+5j
+ ; ICompressSetCoderProperties_Release+5j ...
+
+arg_0 = dword ptr 4
+
+ mov ecx, [esp+arg_0]
+ add dword ptr [ecx+24h], 0FFFFFFFFh
+ mov eax, [ecx+24h]
+ jnz short locret_4CF9F8
+ mov eax, [ecx]
+ mov edx, [eax+10h]
+ push 1
+ call edx
+ xor eax, eax
+
+locret_4CF9F8: ; CODE XREF: sub_4CF9E0+Bj
+ retn 4
+sub_4CF9E0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+ICompressSetCoderProperties_AddRef proc near ; DATA XREF: .rdata:00517AD4o
+
+arg_0 = dword ptr 4
+
+ sub [esp+arg_0], 8
+ jmp sub_4CF9D0
+ICompressSetCoderProperties_AddRef endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CFA10 proc near ; DATA XREF: .rdata:00517AC0o
+
+arg_0 = dword ptr 4
+
+ sub [esp+arg_0], 0Ch
+ jmp sub_4CF9D0
+sub_4CFA10 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CFA20 proc near ; DATA XREF: .rdata:NCompress_NLZMA_CEncoder_vftable_ICompressSetOutStreamo
+
+arg_0 = dword ptr 4
+
+ sub [esp+arg_0], 4
+ jmp sub_4CF900
+sub_4CFA20 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+ICompressSetCoderProperties_QueryInterface proc near ; DATA XREF: .rdata:NCompress_NLZMA_CEncoder_vftable_ICompressSetCoderPropertieso
+
+arg_0 = dword ptr 4
+
+ sub [esp+arg_0], 8
+ jmp sub_4CF900
+ICompressSetCoderProperties_QueryInterface endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CFA40 proc near ; DATA XREF: .rdata:00517AECo
+
+arg_0 = dword ptr 4
+
+ sub [esp+arg_0], 4
+ jmp sub_4CF9E0
+sub_4CFA40 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CFA50 proc near ; DATA XREF: .rdata:NCompress_NLZMA_CEncoder_vftable_ICompressWriteCoderPropertieso
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+
+ sub [esp+arg_0], 0Ch
+ jmp sub_4CF900
+sub_4CFA50 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+ICompressSetCoderProperties_Release proc near ; DATA XREF: .rdata:00517AD8o
+
+arg_0 = dword ptr 4
+
+ sub [esp+arg_0], 8
+ jmp sub_4CF9E0
+ICompressSetCoderProperties_Release endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CFA70 proc near ; DATA XREF: .rdata:00517AC4o
+
+arg_0 = dword ptr 4
+
+ sub [esp+arg_0], 0Ch
+ jmp sub_4CF9E0
+sub_4CFA70 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CFA80 proc near ; DATA XREF: .rdata:00517AE8o
+
+arg_0 = dword ptr 4
+
+ sub [esp+arg_0], 4
+ jmp sub_4CF9D0
+sub_4CFA80 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CFA90 proc near ; DATA XREF: .rdata:00517AF0o
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ push esi
+ mov esi, [esp+4+arg_4]
+ test esi, esi
+ push edi
+ mov edi, [esp+8+arg_0]
+ jz short loc_4CFAA6
+ mov eax, [esi]
+ mov ecx, [eax+4]
+ push esi
+ call ecx
+
+loc_4CFAA6: ; CODE XREF: sub_4CFA90+Cj
+ mov eax, [edi+50h]
+ test eax, eax
+ jz short loc_4CFAB5
+ mov edx, [eax]
+ push eax
+ mov eax, [edx+8]
+ call eax
+
+loc_4CFAB5: ; CODE XREF: sub_4CFA90+1Bj
+ mov [edi+50h], esi
+ pop edi
+ xor eax, eax
+ pop esi
+ retn 8
+sub_4CFA90 endp
+
+; =============== S U B R O U T I N E =======================================
+
+sub_4CFAC0 proc near ; CODE XREF: CEncoder_CodeOneBlock+42Ap
+ ; CEncoder_CodeOneBlock+517p
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ mov eax, [esp+arg_0]
+ push esi
+ mov esi, [eax+10h]
+ mov edx, esi
+ shr edx, 0Bh
+ imul edx, [ecx]
+ cmp [esp+4+arg_4], 0
+ jnz short loc_4CFAEC
+ mov [eax+10h], edx
+ mov edx, [ecx]
+ mov esi, 800h
+ sub esi, edx
+ shr esi, 5
+ add esi, edx
+ mov [ecx], esi
+ jmp short loc_4CFB03
+; ---------------------------------------------------------------------------
+
+loc_4CFAEC: ; CODE XREF: sub_4CFAC0+15j
+ add [eax+8], edx
+ adc dword ptr [eax+0Ch], 0
+ sub esi, edx
+ mov [eax+10h], esi
+ mov edx, [ecx]
+ mov esi, edx
+ shr esi, 5
+ sub edx, esi
+ mov [ecx], edx
+
+loc_4CFB03: ; CODE XREF: sub_4CFAC0+2Aj
+ mov ecx, [eax+10h]
+ cmp ecx, 1000000h
+ pop esi
+ jnb short locret_4CFB1C
+ shl ecx, 8
+ mov [eax+10h], ecx
+ mov ecx, eax
+ call loc_4CF640
+
+locret_4CFB1C: ; CODE XREF: sub_4CFAC0+4Dj
+ retn 8
+sub_4CFAC0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CFB20 proc near ; CODE XREF: sub_4D0020+52p
+ ; sub_4D0020+E4p
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ push ebx
+ push ebp
+ push esi
+ mov esi, [esp+0Ch+arg_0]
+ push edi
+ mov ebp, ecx
+ mov ebx, 1
+ mov edx, 3
+
+loc_4CFB34: ; CODE XREF: sub_4CFB20+8Cj
+ mov edi, [esp+10h+arg_4]
+ sub edx, 1
+ mov ecx, edx
+ shr edi, cl
+ mov ecx, [esi+10h]
+ mov eax, ecx
+ shr eax, 0Bh
+ imul eax, [ebp+ebx*4+0]
+ and edi, 1
+ test edi, edi
+ mov [esp+10h+arg_0], edx
+ jnz short loc_4CFB70
+ mov [esi+10h], eax
+ mov eax, [ebp+ebx*4+0]
+ mov ecx, 800h
+ sub ecx, eax
+ shr ecx, 5
+ add ecx, eax
+ mov [ebp+ebx*4+0], ecx
+ jmp short loc_4CFB8B
+; ---------------------------------------------------------------------------
+
+loc_4CFB70: ; CODE XREF: sub_4CFB20+35j
+ add [esi+8], eax
+ adc dword ptr [esi+0Ch], 0
+ sub ecx, eax
+ mov [esi+10h], ecx
+ mov eax, [ebp+ebx*4+0]
+ mov ecx, eax
+ shr ecx, 5
+ sub eax, ecx
+ mov [ebp+ebx*4+0], eax
+
+loc_4CFB8B: ; CODE XREF: sub_4CFB20+4Ej
+ mov eax, [esi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4CFBA6
+ shl eax, 8
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+ mov edx, [esp+10h+arg_0]
+
+loc_4CFBA6: ; CODE XREF: sub_4CFB20+73j
+ add ebx, ebx
+ or ebx, edi
+ test edx, edx
+ jnz short loc_4CFB34
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ retn 8
+sub_4CFB20 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CFBC0 proc near ; CODE XREF: sub_4D0020+136p
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ push ebx
+ push ebp
+ push esi
+ mov esi, [esp+0Ch+arg_0]
+ push edi
+ mov ebp, ecx
+ mov ebx, 1
+ mov edx, 8
+
+loc_4CFBD4: ; CODE XREF: sub_4CFBC0+8Cj
+ mov edi, [esp+10h+arg_4]
+ sub edx, 1
+ mov ecx, edx
+ shr edi, cl
+ mov ecx, [esi+10h]
+ mov eax, ecx
+ shr eax, 0Bh
+ imul eax, [ebp+ebx*4+0]
+ and edi, 1
+ test edi, edi
+ mov [esp+10h+arg_0], edx
+ jnz short loc_4CFC10
+ mov [esi+10h], eax
+ mov eax, [ebp+ebx*4+0]
+ mov ecx, 800h
+ sub ecx, eax
+ shr ecx, 5
+ add ecx, eax
+ mov [ebp+ebx*4+0], ecx
+ jmp short loc_4CFC2B
+; ---------------------------------------------------------------------------
+
+loc_4CFC10: ; CODE XREF: sub_4CFBC0+35j
+ add [esi+8], eax
+ adc dword ptr [esi+0Ch], 0
+ sub ecx, eax
+ mov [esi+10h], ecx
+ mov eax, [ebp+ebx*4+0]
+ mov ecx, eax
+ shr ecx, 5
+ sub eax, ecx
+ mov [ebp+ebx*4+0], eax
+
+loc_4CFC2B: ; CODE XREF: sub_4CFBC0+4Ej
+ mov eax, [esi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4CFC46
+ shl eax, 8
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+ mov edx, [esp+10h+arg_0]
+
+loc_4CFC46: ; CODE XREF: sub_4CFBC0+73j
+ add ebx, ebx
+ or ebx, edi
+ test edx, edx
+ jnz short loc_4CFBD4
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ retn 8
+sub_4CFBC0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CFC60 proc near ; CODE XREF: sub_4D0770+EDp
+ ; CEncoder_CodeOneBlock+67Cp
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ push ebx
+ push ebp
+ push esi
+ mov esi, [esp+0Ch+arg_0]
+ push edi
+ mov ebp, ecx
+ mov ebx, 1
+ mov edx, 6
+
+loc_4CFC74: ; CODE XREF: sub_4CFC60+8Cj
+ mov edi, [esp+10h+arg_4]
+ sub edx, 1
+ mov ecx, edx
+ shr edi, cl
+ mov ecx, [esi+10h]
+ mov eax, ecx
+ shr eax, 0Bh
+ imul eax, [ebp+ebx*4+0]
+ and edi, 1
+ test edi, edi
+ mov [esp+10h+arg_0], edx
+ jnz short loc_4CFCB0
+ mov [esi+10h], eax
+ mov eax, [ebp+ebx*4+0]
+ mov ecx, 800h
+ sub ecx, eax
+ shr ecx, 5
+ add ecx, eax
+ mov [ebp+ebx*4+0], ecx
+ jmp short loc_4CFCCB
+; ---------------------------------------------------------------------------
+
+loc_4CFCB0: ; CODE XREF: sub_4CFC60+35j
+ add [esi+8], eax
+ adc dword ptr [esi+0Ch], 0
+ sub ecx, eax
+ mov [esi+10h], ecx
+ mov eax, [ebp+ebx*4+0]
+ mov ecx, eax
+ shr ecx, 5
+ sub eax, ecx
+ mov [ebp+ebx*4+0], eax
+
+loc_4CFCCB: ; CODE XREF: sub_4CFC60+4Ej
+ mov eax, [esi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4CFCE6
+ shl eax, 8
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+ mov edx, [esp+10h+arg_0]
+
+loc_4CFCE6: ; CODE XREF: sub_4CFC60+73j
+ add ebx, ebx
+ or ebx, edi
+ test edx, edx
+ jnz short loc_4CFC74
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ retn 8
+sub_4CFC60 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CFD00 proc near ; CODE XREF: sub_4D0770+109p
+ ; CEncoder_CodeOneBlock+6D5p
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ push ebx
+ push ebp
+ push esi
+ mov esi, [esp+0Ch+arg_0]
+ push edi
+ mov ebp, ecx
+ mov edi, 1
+ mov [esp+10h+arg_0], 4
+
+loc_4CFD17: ; CODE XREF: sub_4CFD00+87j
+ mov ecx, [esi+10h]
+ mov ebx, [esp+10h+arg_4]
+ mov eax, ecx
+ shr eax, 0Bh
+ imul eax, [ebp+edi*4+0]
+ and ebx, 1
+ test ebx, ebx
+ jnz short loc_4CFD48
+ mov [esi+10h], eax
+ mov eax, [ebp+edi*4+0]
+ mov ecx, 800h
+ sub ecx, eax
+ shr ecx, 5
+ add ecx, eax
+ mov [ebp+edi*4+0], ecx
+ jmp short loc_4CFD63
+; ---------------------------------------------------------------------------
+
+loc_4CFD48: ; CODE XREF: sub_4CFD00+2Dj
+ add [esi+8], eax
+ adc dword ptr [esi+0Ch], 0
+ sub ecx, eax
+ mov [esi+10h], ecx
+ mov eax, [ebp+edi*4+0]
+ mov edx, eax
+ shr edx, 5
+ sub eax, edx
+ mov [ebp+edi*4+0], eax
+
+loc_4CFD63: ; CODE XREF: sub_4CFD00+46j
+ mov eax, [esi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4CFD7A
+ shl eax, 8
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+
+loc_4CFD7A: ; CODE XREF: sub_4CFD00+6Bj
+ shr [esp+10h+arg_4], 1
+ add edi, edi
+ or edi, ebx
+ sub [esp+10h+arg_0], 1
+ jnz short loc_4CFD17
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ retn 8
+sub_4CFD00 endp
+
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CFD90 proc near ; CODE XREF: CEncoder_CodeOneBlock+6AFp
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+arg_C = dword ptr 10h
+
+ mov eax, [esp+arg_8]
+ test eax, eax
+ push edi
+ mov edi, 1
+ jle loc_4CFE26
+ push ebx
+ push ebp
+ mov ebp, [esp+0Ch+arg_0]
+ push esi
+ mov esi, [esp+10h+arg_4]
+ mov [esp+10h+arg_8], eax
+
+loc_4CFDB1: ; CODE XREF: sub_4CFD90+91j
+ mov ecx, [esi+10h]
+ mov ebx, [esp+10h+arg_C]
+ mov eax, ecx
+ shr eax, 0Bh
+ imul eax, [ebp+edi*4+0]
+ and ebx, 1
+ test ebx, ebx
+ jnz short loc_4CFDE2
+ mov [esi+10h], eax
+ mov eax, [ebp+edi*4+0]
+ mov ecx, 800h
+ sub ecx, eax
+ shr ecx, 5
+ add ecx, eax
+ mov [ebp+edi*4+0], ecx
+ jmp short loc_4CFDFD
+; ---------------------------------------------------------------------------
+
+loc_4CFDE2: ; CODE XREF: sub_4CFD90+37j
+ add [esi+8], eax
+ adc dword ptr [esi+0Ch], 0
+ sub ecx, eax
+ mov [esi+10h], ecx
+ mov eax, [ebp+edi*4+0]
+ mov edx, eax
+ shr edx, 5
+ sub eax, edx
+ mov [ebp+edi*4+0], eax
+
+loc_4CFDFD: ; CODE XREF: sub_4CFD90+50j
+ mov eax, [esi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4CFE14
+ shl eax, 8
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+
+loc_4CFE14: ; CODE XREF: sub_4CFD90+75j
+ shr [esp+10h+arg_C], 1
+ add edi, edi
+ or edi, ebx
+ sub [esp+10h+arg_8], 1
+ jnz short loc_4CFDB1
+ pop esi
+ pop ebp
+ pop ebx
+
+loc_4CFE26: ; CODE XREF: sub_4CFD90+Cj
+ pop edi
+ retn
+sub_4CFD90 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+
+; =============== S U B R O U T I N E =======================================
+
+
+sub_4CFE30 proc near ; CODE XREF: CEncoder_CodeOneBlock+190p
+ ; CEncoder_CodeOneBlock+2CCp
+
+arg_0 = dword ptr 4
+arg_4 = byte ptr 8
+
+ push ebx
+ push ebp
+ push esi
+ mov esi, [esp+0Ch+arg_0]
+ push edi
+ mov ebx, ecx
+ mov ebp, 1
+ mov edx, 8
+
+loc_4CFE44: ; CODE XREF: sub_4CFE30+88j
+ movzx edi, [esp+10h+arg_4]
+ sub edx, 1
+ mov cl, dl
+ shr edi, cl
+ mov ecx, [esi+10h]
+ mov eax, ecx
+ shr eax, 0Bh
+ imul eax, [ebx+ebp*4]
+ and edi, 1
+ test edi, edi
+ mov [esp+10h+arg_0], edx
+ jnz short loc_4CFE7E
+ mov [esi+10h], eax
+ mov eax, [ebx+ebp*4]
+ mov ecx, 800h
+ sub ecx, eax
+ shr ecx, 5
+ add ecx, eax
+ mov [ebx+ebp*4], ecx
+ jmp short loc_4CFE97
+; ---------------------------------------------------------------------------
+
+loc_4CFE7E: ; CODE XREF: sub_4CFE30+35j
+ add [esi+8], eax
+ adc dword ptr [esi+0Ch], 0
+ sub ecx, eax
+ mov [esi+10h], ecx
+ mov eax, [ebx+ebp*4]
+ mov ecx, eax
+ shr ecx, 5
+ sub eax, ecx
+ mov [ebx+ebp*4], eax
+
+loc_4CFE97: ; CODE XREF: sub_4CFE30+4Cj
+ mov eax, [esi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4CFEB2
+ shl eax, 8
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+ mov edx, [esp+10h+arg_0]
+
+loc_4CFEB2: ; CODE XREF: sub_4CFE30+6Fj
+ add ebp, ebp
+ or ebp, edi
+ test edx, edx
+ jnz short loc_4CFE44
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ retn 8
+sub_4CFE30 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4CFED0 proc near ; CODE XREF: CEncoder_CodeOneBlock+300p
+
+var_4 = dword ptr -4
+arg_0 = dword ptr 4
+arg_4 = byte ptr 8
+arg_8 = byte ptr 0Ch
+
+ push ecx
+ push ebx
+ push ebp
+ push esi
+ mov esi, [esp+10h+arg_0]
+ push edi
+ mov [esp+14h+var_4], ecx
+ mov ebx, 1
+ mov edx, 8
+ jmp short loc_4CFEF0
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4CFEF0: ; CODE XREF: sub_4CFED0+17j
+ ; sub_4CFED0+ADj
+ movzx ebp, [esp+14h+arg_4]
+ movzx edi, [esp+14h+arg_8]
+ sub edx, 1
+ movzx ecx, dl
+ shr ebp, cl
+ shr edi, cl
+ mov ecx, [esp+14h+var_4]
+ mov [esp+14h+arg_0], edx
+ mov edx, [esi+10h]
+ and ebp, 1
+ lea eax, [ebp+1]
+ shl eax, 8
+ add eax, ebx
+ lea ecx, [ecx+eax*4]
+ mov eax, edx
+ shr eax, 0Bh
+ imul eax, [ecx]
+ and edi, 1
+ test edi, edi
+ jnz short loc_4CFF41
+ mov [esi+10h], eax
+ mov eax, [ecx]
+ mov edx, 800h
+ sub edx, eax
+ shr edx, 5
+ add edx, eax
+ mov [ecx], edx
+ jmp short loc_4CFF58
+; ---------------------------------------------------------------------------
+
+loc_4CFF41: ; CODE XREF: sub_4CFED0+5Aj
+ add [esi+8], eax
+ adc dword ptr [esi+0Ch], 0
+ sub edx, eax
+ mov [esi+10h], edx
+ mov eax, [ecx]
+ mov edx, eax
+ shr edx, 5
+ sub eax, edx
+ mov [ecx], eax
+
+loc_4CFF58: ; CODE XREF: sub_4CFED0+6Fj
+ mov eax, [esi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4CFF6F
+ shl eax, 8
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+
+loc_4CFF6F: ; CODE XREF: sub_4CFED0+90j
+ mov edx, [esp+14h+arg_0]
+ add ebx, ebx
+ or ebx, edi
+ cmp ebp, edi
+ jnz short loc_4CFF8B
+ test edx, edx
+ jnz loc_4CFEF0
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ pop ecx
+ retn 0Ch
+; ---------------------------------------------------------------------------
+
+loc_4CFF8B: ; CODE XREF: sub_4CFED0+A9j
+ test edx, edx
+ jz loc_4D0012
+
+loc_4CFF93: ; CODE XREF: sub_4CFED0+140j
+ movzx edi, [esp+14h+arg_8]
+ mov ebp, [esp+14h+var_4]
+ sub edx, 1
+ mov cl, dl
+ shr edi, cl
+ mov ecx, [esi+10h]
+ mov eax, ecx
+ shr eax, 0Bh
+ imul eax, [ebp+ebx*4+0]
+ and edi, 1
+ test edi, edi
+ mov [esp+14h+arg_0], edx
+ jnz short loc_4CFFD4
+ mov [esi+10h], eax
+ mov eax, [ebp+ebx*4+0]
+ mov ecx, 800h
+ sub ecx, eax
+ shr ecx, 5
+ add ecx, eax
+ mov [ebp+ebx*4+0], ecx
+ jmp short loc_4CFFEF
+; ---------------------------------------------------------------------------
+
+loc_4CFFD4: ; CODE XREF: sub_4CFED0+E9j
+ add [esi+8], eax
+ adc dword ptr [esi+0Ch], 0
+ sub ecx, eax
+ mov [esi+10h], ecx
+ mov eax, [ebp+ebx*4+0]
+ mov ecx, eax
+ shr ecx, 5
+ sub eax, ecx
+ mov [ebp+ebx*4+0], eax
+
+loc_4CFFEF: ; CODE XREF: sub_4CFED0+102j
+ mov eax, [esi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D000A
+ shl eax, 8
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+ mov edx, [esp+14h+arg_0]
+
+loc_4D000A: ; CODE XREF: sub_4CFED0+127j
+ add ebx, ebx
+ or ebx, edi
+ test edx, edx
+ jnz short loc_4CFF93
+
+loc_4D0012: ; CODE XREF: sub_4CFED0+BDj
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ pop ecx
+ retn 0Ch
+sub_4CFED0 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4D0020 proc near ; CODE XREF: sub_4D0770+C6p
+ ; CEncoder_CodeOneBlock+56Dp ...
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+
+ push ebp
+ mov ebp, [esp+4+arg_4]
+ cmp ebp, 8
+ push esi
+ mov esi, [esp+8+arg_0]
+ push edi
+ mov edi, ecx
+ jnb short loc_4D007D
+ mov eax, [esi+10h]
+ shr eax, 0Bh
+ imul eax, [edi]
+ mov [esi+10h], eax
+ mov eax, [edi]
+ mov ecx, 800h
+ sub ecx, eax
+
+loc_4D0047: ; DATA XREF: .rdata:0050C3BCo
+ shr ecx, 5
+ add ecx, eax
+ mov [edi], ecx
+ mov eax, [esi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D0065
+ shl eax, 8
+
+loc_4D005B: ; DATA XREF: .rdata:005064B0o
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+
+loc_4D0065: ; CODE XREF: sub_4D0020+36j
+ mov edx, [esp+0Ch+arg_8]
+ push ebp
+ shl edx, 5
+ push esi
+ lea ecx, [edx+edi+8]
+ call sub_4CFB20
+ pop edi
+ pop esi
+ pop ebp
+ retn 0Ch
+; ---------------------------------------------------------------------------
+
+loc_4D007D: ; CODE XREF: sub_4D0020+10j
+ mov ecx, [esi+10h]
+ mov eax, ecx
+ shr eax, 0Bh
+ imul eax, [edi]
+ add [esi+8], eax
+ adc dword ptr [esi+0Ch], 0
+ sub ecx, eax
+ mov [esi+10h], ecx
+ mov eax, [edi]
+ mov ecx, eax
+ shr ecx, 5
+ sub eax, ecx
+ mov [edi], eax
+ mov eax, [esi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D00B6
+ shl eax, 8
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+
+loc_4D00B6: ; CODE XREF: sub_4D0020+87j
+ cmp ebp, 10h
+ jnb short loc_4D010F
+ mov edx, [esi+10h]
+ shr edx, 0Bh
+ imul edx, [edi+4]
+ mov [esi+10h], edx
+ mov eax, [edi+4]
+ mov ecx, 800h
+ sub ecx, eax
+ shr ecx, 5
+ add ecx, eax
+ mov [edi+4], ecx
+ mov eax, [esi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D00F1
+ shl eax, 8
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+
+loc_4D00F1: ; CODE XREF: sub_4D0020+C2j
+ mov edx, [esp+0Ch+arg_8]
+ add ebp, 0FFFFFFF8h
+ push ebp
+ shl edx, 5
+ push esi
+ lea ecx, [edx+edi+208h]
+ call sub_4CFB20
+ pop edi
+ pop esi
+ pop ebp
+ retn 0Ch
+; ---------------------------------------------------------------------------
+
+loc_4D010F: ; CODE XREF: sub_4D0020+99j
+ mov ecx, [esi+10h]
+ mov eax, ecx
+ shr eax, 0Bh
+ imul eax, [edi+4]
+ add [esi+8], eax
+ adc dword ptr [esi+0Ch], 0
+ sub ecx, eax
+ mov [esi+10h], ecx
+ mov eax, [edi+4]
+ mov ecx, eax
+ shr ecx, 5
+ sub eax, ecx
+ mov [edi+4], eax
+ mov eax, [esi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D014B
+ shl eax, 8
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+
+loc_4D014B: ; CODE XREF: sub_4D0020+11Cj
+ add ebp, 0FFFFFFF0h
+ push ebp
+ push esi
+ lea ecx, [edi+408h]
+ call sub_4CFBC0
+ pop edi
+ pop esi
+ pop ebp
+ retn 0Ch
+sub_4D0020 endp
+
+; =============== S U B R O U T I N E =======================================
+
+NCompress_NLZMA_CEncoder_CEncoder proc near ; CODE XREF: Compress_lzma_internal+149p
+ mov eax, ecx
+ mov dword ptr [eax+4], offset ICompressSetOutStream_vftable
+ mov dword ptr [eax+8], offset ICompressSetCoderProperties_vftable
+ mov dword ptr [eax+0Ch], offset ICompressWriteCoderProperties_vftable
+ xor ecx, ecx
+ mov [eax+24h], ecx
+ mov dword ptr [eax], offset NCompress_NLZMA_CEncoder_vftable
+ mov dword ptr [eax+4], offset NCompress_NLZMA_CEncoder_vftable_ICompressSetOutStream
+ mov dword ptr [eax+8], offset NCompress_NLZMA_CEncoder_vftable_ICompressSetCoderProperties
+ mov dword ptr [eax+0Ch], offset NCompress_NLZMA_CEncoder_vftable_ICompressWriteCoderProperties
+ mov [eax+40h], ecx
+ mov [eax+44h], ecx
+ mov [eax+54h], ecx
+ mov [eax+60h], ecx
+ mov [eax+32650h], ecx
+ mov dword ptr [eax+32EF8h], 20h
+ mov dword ptr [eax+33B58h], 2Ch
+ mov dword ptr [eax+33B5Ch], 2
+ mov [eax+33B64h], ecx
+ mov dword ptr [eax+33B6Ch], 00400000h
+ mov edx, 3
+ mov [eax+33B60h], edx
+ mov [eax+33B68h], edx
+ mov [eax+33B8Ch], ecx
+ mov [eax+33B90h], ecx
+ mov [eax+33B94h], cl
+ mov [eax+0B4h], ecx
+ mov [eax+0A4h], ecx
+ mov dword ptr [eax+0B0h], 20h
+ mov dword ptr [eax+0D4h], 1
+ mov dword ptr [eax+0CCh], 4
+ mov [eax+0D0h], ecx
+ mov [eax+0D8h], ecx
+ mov [eax+32EF4h], cl
+ retn
+NCompress_NLZMA_CEncoder_CEncoder endp
+
+; =============== S U B R O U T I N E =======================================
+
+; int __thiscall sub_4D0250(void *Memory, char)
+sub_4D0250 proc near ; DATA XREF: .rdata:00517B0Co
+
+arg_0 = byte ptr 4
+
+ push esi
+ mov esi, ecx
+ call sub_4CF810
+ test [esp+4+arg_0], 1
+ jz short loc_4D0268
+ push esi ; Memory
+ call j__free
+ add esp, 4
+
+loc_4D0268: ; CODE XREF: sub_4D0250+Dj
+ mov eax, esi
+ pop esi
+ retn 4
+sub_4D0250 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+sub_4D0270 proc near ; CODE XREF: CEncoder_SetStreams+14p
+ push esi
+ mov esi, ecx
+ mov eax, [esi+40h]
+ test eax, eax
+ push edi
+ mov edi, 100000h
+ jz short loc_4D0297
+ cmp [esi+50h], edi
+ jz short loc_4D02C5
+ test eax, eax
+ jz short loc_4D0297
+ push 8000h ; dwFreeType
+ push 0 ; dwSize
+ push eax ; lpAddress
+ call ds:VirtualFree
+
+loc_4D0297: ; CODE XREF: sub_4D0270+Ej
+ ; sub_4D0270+17j
+ push 4 ; flProtect
+ push 1000h ; flAllocationType
+ push edi ; dwSize
+ push 0 ; lpAddress
+ mov dword ptr [esi+40h], 0
+ mov [esi+50h], edi
+ call ds:VirtualAlloc
+ test eax, eax
+ mov [esi+40h], eax
+ setnz al
+ test al, al
+ jnz short loc_4D02C5
+ pop edi
+ mov eax, 8007000Eh
+ pop esi
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4D02C5: ; CODE XREF: sub_4D0270+13j
+ ; sub_4D0270+4Bj
+ mov eax, [esi+33B68h]
+ mov ecx, [esi+33B64h]
+ cmp dword ptr [esi+0D4h], 0
+ push ebx
+ push eax
+ push ecx
+ lea ecx, [esi+32650h]
+ setnz bl
+ call sub_4CD940
+ test al, al
+ jz short loc_4D034F
+ mov ecx, [esi+33B6Ch]
+ mov edx, 1000000h
+ cmp edx, ecx
+ sbb eax, eax
+ neg eax
+ push ebp
+ mov ebp, [esi+32EF8h]
+ mov [esi+0D8h], eax
+ mov eax, ebp
+ shr eax, 1
+ add eax, 10h
+ test bl, bl
+ jnz short loc_4D0318
+ shr eax, 1
+
+loc_4D0318: ; CODE XREF: sub_4D0270+A4j
+ mov edx, [esi+33B90h]
+ test edx, edx
+ jz short loc_4D0324
+ mov eax, edx
+
+loc_4D0324: ; CODE XREF: sub_4D0270+B0j
+ push offset off_546E20
+ push 111h
+ push ebp
+ push 1000h
+ push ecx
+ lea edi, [esi+84h]
+ push edi
+ mov [esi+0B0h], eax
+ call sub_4CBA60
+ add esp, 18h
+ test eax, eax
+ pop ebp
+ jnz short loc_4D0358
+
+loc_4D034F: ; CODE XREF: sub_4D0270+7Bj
+ pop ebx
+ pop edi
+ mov eax, 8007000Eh
+ pop esi
+ retn
+; ---------------------------------------------------------------------------
+
+loc_4D0358: ; CODE XREF: sub_4D0270+DDj
+ mov [esi+80h], edi
+ add esi, 68h
+ push esi
+ push edi
+ call sub_4CCAA0
+ add esp, 8
+ pop ebx
+ pop edi
+ xor eax, eax
+ pop esi
+ retn
+sub_4D0270 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+CEncoder_SetStreams proc near ; CODE XREF: CEncoder_CodeReal+4Ap
+
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+
+ mov eax, [esp+arg_0]
+ push esi
+ mov esi, ecx
+ mov [esi+33B84h], eax
+ mov byte ptr [esi+33B80h], 0
+ call sub_4D0270
+ test eax, eax
+ jnz loc_4D0441
+ mov edx, [esp+4+arg_4]
+ mov ecx, [esi+4]
+ lea eax, [esi+4]
+ push edx
+ push eax
+ mov eax, [ecx+0Ch]
+ call eax
+ test eax, eax
+ jnz loc_4D0441
+ mov ecx, esi
+ call sub_4CDEA0
+ test eax, eax
+ jnz short loc_4D0441
+ cmp [esi+32EF4h], al
+ jnz short loc_4D03DB
+ mov ecx, esi
+ call CEncoder_FillDistancesPrices
+ mov ecx, esi
+ call CEncoder_FillAlignPrices
+
+loc_4D03DB: ; CODE XREF: CEncoder_SetStreams+4Bj
+ mov ecx, [esi+32EF8h]
+ sub ecx, 1
+ mov [esi+2D9C0h], ecx
+ mov ecx, [esi+33B5Ch]
+ mov edx, 1
+ shl edx, cl
+ lea ecx, [esi+28DB8h]
+ push edx
+ call sub_4CF780
+ mov ecx, [esi+33B5Ch]
+ mov eax, [esi+32EF8h]
+ mov edx, 1
+ shl edx, cl
+ sub eax, 1
+ lea ecx, [esi+2DA04h]
+ mov [esi+3260Ch], eax
+ push edx
+ call sub_4CF780
+ mov dword ptr [esi+33B78h], 0
+ mov dword ptr [esi+33B7Ch], 0
+ xor eax, eax
+
+loc_4D0441: ; CODE XREF: CEncoder_SetStreams+1Bj
+ ; CEncoder_SetStreams+34j ...
+ pop esi
+ retn 10h
+CEncoder_SetStreams endp
+
+;Compress_lzma_internal proc near ; CODE XREF: Compress_lzma+34p
+_starcraft_compress_lzma proc near ; CODE XREF: Compress_lzma+34p
+; sub_4D0450
+
+var_58 = dword ptr -58h
+var_54 = dword ptr -54h
+var_50 = dword ptr -50h
+var_4C = dword ptr -4Ch
+var_48 = dword ptr -48h
+var_44 = dword ptr -44h
+var_40 = dword ptr -40h
+var_3C = word ptr -3Ch
+var_34 = dword ptr -34h
+var_2C = word ptr -2Ch
+var_24 = dword ptr -24h
+var_1C = dword ptr -1Ch
+var_14 = dword ptr -14h
+var_C = dword ptr -0Ch
+var_4 = dword ptr -4
+pbInBuffer = dword ptr 4
+cbInBuffer = dword ptr 8
+pcbInBuffer = dword ptr 0Ch
+pbOutBuffer = dword ptr 10h
+cbOutBuffer = dword ptr 14h
+dummy = dword ptr 18h
+pcbOutBuffer = dword ptr 1Ch
+pfnAllocateMemory= dword ptr 20h
+pfnFreeMemory = dword ptr 24h
+pfnGiveData = dword ptr 28h
+
+ push 0FFFFFFFFh
+ push offset loc_4DA0FB
+ mov eax, dword ptr fs:[0]
+ push eax
+ sub esp, 4Ch
+ push ebx
+ push ebp
+ push esi
+ push edi
+ mov eax, dword_544960
+ xor eax, esp
+ push eax
+ lea eax, [esp+6Ch+var_C]
+ mov dword ptr fs:[0], eax
+ mov eax, dword_553598
+ xor ebx, ebx
+ cmp eax, ebx
+ jnz short loc_4D04A1
+ push 0Ch ; Size
+ call _operator_new ; operator new(uint)
+ add esp, 4
+ cmp eax, ebx
+ jz short loc_4D049A
+ mov [eax], ebx
+ mov [eax+4], ebx
+ mov [eax+8], ebx
+ jmp short loc_4D049C
+; ---------------------------------------------------------------------------
+
+loc_4D049A: ; CODE XREF: Compress_lzma_internal+3Ej
+ xor eax, eax
+
+loc_4D049C: ; CODE XREF: Compress_lzma_internal+48j
+ mov dword ptr dword_553598, eax
+
+loc_4D04A1: ; CODE XREF: Compress_lzma_internal+30j
+ cmp [eax], ebx
+ jnz short loc_4D04B3
+ mov ecx, [esp+6Ch+pfnAllocateMemory]
+ mov [eax], ecx
+ mov eax, dword_553598
+
+loc_4D04B3: ; CODE XREF: Compress_lzma_internal+53j
+ cmp eax, ebx
+ jnz short loc_4D04D6
+ push 0Ch ; Size
+ call _operator_new ; operator new(uint)
+ add esp, 4
+ cmp eax, ebx
+ jz short loc_4D04CF
+ mov [eax], ebx
+ mov [eax+4], ebx
+ mov [eax+8], ebx
+ jmp short loc_4D04D1
+; ---------------------------------------------------------------------------
+
+loc_4D04CF: ; CODE XREF: Compress_lzma_internal+73j
+ xor eax, eax
+
+loc_4D04D1: ; CODE XREF: Compress_lzma_internal+7Dj
+ mov dword_553598, eax
+
+loc_4D04D6: ; CODE XREF: Compress_lzma_internal+65j
+ cmp [eax+4], ebx
+ jnz short loc_4D04EA
+ mov edx, [esp+6Ch+pfnFreeMemory]
+ mov [eax+4], edx
+ mov eax, dword_553598
+
+loc_4D04EA: ; CODE XREF: Compress_lzma_internal+89j
+ cmp [eax+8], ebx
+ jnz short loc_4D04F9
+ mov ecx, [esp+6Ch+pfnGiveData]
+ mov [eax+8], ecx
+
+loc_4D04F9: ; CODE XREF: Compress_lzma_internal+9Dj
+ mov edx, [esp+6Ch+pcbOutBuffer]
+ mov ebp, [esp+6Ch+pcbInBuffer]
+ cmp ebp, ebx
+ mov esi, [esp+6Ch+cbInBuffer]
+ mov [edx], ebx
+ mov edx, 1
+ mov eax, esi
+ mov ecx, ebp
+ ja short loc_4D0520
+ cmp esi, ebx
+ jbe short loc_4D053A
+ jmp short loc_4D0520
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4D0520: ; CODE XREF: Compress_lzma_internal+C5j
+ ; Compress_lzma_internal+CBj ...
+ shrd eax, ecx, 1
+ add edx, edx
+ shr ecx, 1
+ cmp edx, 2000000h
+ ja short loc_4D053A
+ cmp ecx, ebx
+ ja short loc_4D0520
+ jb short loc_4D053A
+ cmp eax, ebx
+ ja short loc_4D0520
+
+loc_4D053A: ; CODE XREF: Compress_lzma_internal+C9j
+ ; Compress_lzma_internal+DEj ...
+ mov eax, 13h
+ push 33B98h ; Size
+ mov [esp+70h+var_48], 470h
+ mov [esp+70h+var_44], 400h
+ mov [esp+70h+var_40], 450h
+ mov [esp+70h+var_3C], ax
+ mov [esp+70h+var_2C], ax
+ mov word ptr [esp+70h+var_1C], ax
+ mov [esp+70h+var_34], 2
+ mov [esp+70h+var_24], edx
+ mov [esp+70h+var_14], 40h
+ mov [esp+70h+var_58], ebx
+ call _operator_new ; operator new(uint)
+ add esp, 4
+ mov [esp+6Ch+var_4C], eax
+ cmp eax, ebx
+ mov [esp+6Ch+var_4], ebx
+ jz short loc_4D05A4
+ mov ecx, eax
+ call NCompress_NLZMA_CEncoder_CEncoder
+ mov [esp+6Ch+var_54], eax
+ jmp short loc_4D05AA
+; ---------------------------------------------------------------------------
+
+loc_4D05A4: ; CODE XREF: Compress_lzma_internal+145j
+ mov [esp+6Ch+var_54], ebx
+ mov eax, ebx
+
+loc_4D05AA: ; CODE XREF: Compress_lzma_internal+152j
+ or edi, 0FFFFFFFFh
+ cmp eax, ebx
+ mov [esp+6Ch+var_4], edi
+ jz short loc_4D05D1
+ mov ecx, [eax+8]
+ push 3
+ lea edx, [esp+70h+var_3C]
+ push edx
+ add eax, 8
+ lea edx, [esp+74h+var_48]
+ push edx
+ push eax
+ mov eax, [ecx+0Ch]
+ call eax ; ICompressSetCodeProperties::SetCoderProperties
+ test eax, eax
+ jz short loc_4D05D5
+
+loc_4D05D1: ; CODE XREF: Compress_lzma_internal+163j
+ mov [esp+6Ch+var_58], edi
+
+loc_4D05D5: ; CODE XREF: Compress_lzma_internal+17Fj
+ push 28h ; Size
+ call _operator_new ; operator new(uint)
+ add esp, 4
+ cmp eax, ebx
+ jz short loc_4D060E
+ mov ecx, [esp+6Ch+pbInBuffer]
+ mov [eax+4], ebx
+ add dword ptr [eax+4], 1
+ mov dword ptr [eax], offset off_517A90
+ mov [eax+8], ecx
+ mov [eax+10h], esi
+ mov [eax+14h], ebp
+ mov [eax+18h], ebx
+ mov [eax+1Ch], ebx
+ mov [eax+20h], bl
+ mov edi, eax ; EDI = pInStreamMemory
+ mov [esp+6Ch+var_50], eax
+ jmp short loc_4D0614
+; ---------------------------------------------------------------------------
+
+loc_4D060E: ; CODE XREF: Compress_lzma_internal+191j
+ xor edi, edi
+ mov [esp+6Ch+var_50], edi
+
+loc_4D0614: ; CODE XREF: Compress_lzma_internal+1BCj
+ push 28h ; Size
+ call _operator_new ; operator new(uint)
+ add esp, 4
+ cmp eax, ebx
+ jz short loc_4D0657
+ mov edx, [esp+6Ch+pbOutBuffer]
+ mov ecx, [esp+6Ch+cbOutBuffer]
+ mov [eax+4], ebx
+ add dword ptr [eax+4], 1
+ mov [eax+8], edx
+ mov edx, [esp+6Ch+dummy]
+ mov dword ptr [eax], offset off_517AA4
+ mov [eax+10h], ecx
+ mov [eax+14h], edx
+ mov [eax+18h], ebx
+ mov [eax+1Ch], ebx
+ mov [eax+20h], bl
+ mov esi, eax ; ESI = pOutStreamMemory
+ jmp short loc_4D0659
+; ---------------------------------------------------------------------------
+
+loc_4D0657: ; CODE XREF: Compress_lzma_internal+1D0j
+ xor esi, esi
+
+loc_4D0659: ; CODE XREF: Compress_lzma_internal+205j
+ cmp edi, ebx
+ jz short loc_4D0661
+ cmp esi, ebx
+ jnz short loc_4D0669
+
+loc_4D0661: ; CODE XREF: Compress_lzma_internal+20Bj
+ mov [esp+6Ch+var_58], 0FFFFFFFFh
+
+loc_4D0669: ; CODE XREF: Compress_lzma_internal+20Fj
+ mov eax, [esi] ; EAX = pOutStreamMemory->vftable
+ mov ecx, [eax+10h] ; ECX =
+ push ebx
+ mov edi, 1
+ push edi
+ push ebx
+ push esi
+ call ecx
+ test eax, eax
+ jz short loc_4D0681
+ mov [esp+6Ch+var_58], edi
+
+loc_4D0681: ; CODE XREF: Compress_lzma_internal+22Bj
+ mov eax, [esp+6Ch+var_54]
+ mov edx, [eax+0Ch]
+ add eax, 0Ch
+ push esi
+ push eax
+ mov eax, [edx+0Ch]
+ call eax
+ test eax, eax
+ jz short loc_4D069A
+ mov [esp+6Ch+var_58], edi
+
+loc_4D069A: ; CODE XREF: Compress_lzma_internal+244j
+ xor edi, edi
+ jmp short loc_4D06A4
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4D06A0: ; CODE XREF: Compress_lzma_internal+27Fj
+ mov ebp, [esp+6Ch+pcbInBuffer]
+
+loc_4D06A4: ; CODE XREF: Compress_lzma_internal+24Cj
+ mov eax, [esp+6Ch+cbInBuffer]
+ push ebx
+ push 1
+ mov edx, ebp
+ mov ecx, edi
+ call __allshr ; Microsoft VisualC 2-8/net runtime
+ push eax
+ mov eax, [esi]
+ mov ecx, [eax+10h]
+ push esi
+ call ecx
+ test eax, eax
+ jz short loc_4D06C9
+ mov [esp+6Ch+var_58], 1
+
+loc_4D06C9: ; CODE XREF: Compress_lzma_internal+26Fj
+ add edi, 8
+ cmp edi, 40h
+ jl short loc_4D06A0
+ mov ebp, [esp+6Ch+var_54]
+ xor edi, edi
+ cmp [esp+6Ch+var_58], ebx
+ jnz short loc_4D0723
+ mov eax, [esp+6Ch+var_50]
+ mov edx, [ebp+0]
+ mov ecx, [edx+0Ch]
+ push ebx
+ push ebx
+ push ebx
+ push esi
+ push eax
+ push ebp
+ call ecx
+ mov ecx, [esi+18h]
+ mov edi, eax
+ mov eax, [esi+1Ch]
+ cmp eax, ebx
+ ja short loc_4D0700
+ cmp ecx, 0FFFFFFFFh
+ jbe short loc_4D0709
+
+loc_4D0700: ; CODE XREF: Compress_lzma_internal+2A9j
+ or ecx, 0FFFFFFFFh
+ mov [esp+6Ch+pcbInBuffer], ebx
+ jmp short loc_4D070D
+; ---------------------------------------------------------------------------
+
+loc_4D0709: ; CODE XREF: Compress_lzma_internal+2AEj
+ mov [esp+6Ch+pcbInBuffer], eax
+
+loc_4D070D: ; CODE XREF: Compress_lzma_internal+2B7j
+ mov edx, [esp+6Ch+pcbOutBuffer]
+ mov [edx], ecx
+ cmp [esi+20h], bl
+ jz short loc_4D0723
+ mov [esp+6Ch+var_58], 1
+
+loc_4D0723: ; CODE XREF: Compress_lzma_internal+28Bj
+ ; Compress_lzma_internal+2C9j
+ mov eax, [esp+6Ch+var_50]
+ cmp eax, ebx
+ jz short loc_4D0733
+ mov ecx, [eax]
+ mov edx, [ecx+8]
+ push eax
+ call edx
+
+loc_4D0733: ; CODE XREF: Compress_lzma_internal+2D9j
+ mov eax, [esi]
+ mov ecx, [eax+8]
+ push esi
+ call ecx
+ mov edx, [ebp+0]
+ mov eax, [edx+10h]
+ push 1
+ mov ecx, ebp
+ call eax
+ mov eax, [esp+6Ch+var_58]
+ cmp eax, ebx
+ jnz short loc_4D0755
+ neg edi
+ sbb edi, edi
+ mov eax, edi
+
+loc_4D0755: ; CODE XREF: Compress_lzma_internal+2FDj
+ mov ecx, [esp+6Ch+var_C]
+ mov dword ptr fs:[0], ecx
+ pop ecx
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ add esp, 58h
+ retn
+_starcraft_compress_lzma endp
+;Compress_lzma_internal endp
+
+; =============== S U B R O U T I N E =======================================
+
+Compress_lzma proc near ; DATA XREF: .rdata:00509684o
+
+pbOutBuffer = dword ptr 4
+pcbOutBuffer = dword ptr 8
+pbInBuffer = dword ptr 0Ch
+cbInBuffer = dword ptr 10h
+
+ push esi
+ push edi
+; call sub_47F198
+ mov esi, [esp+8+pcbOutBuffer] ; ESI = pcbOutBuffer
+ mov edi, [esp+8+cbInBuffer] ; EDI = cbInBuffer
+; push offset GiveDataToCompress
+; push offset FreeMemory_47F3AB
+; push offset AllocateMemory_47F396
+ push esi ; pcbOutBuffer
+ push 0
+ mov [eax+493E0h], eax
+ push dword ptr [esi] ; cbOutBuffer
+ push [esp+20h+pbOutBuffer] ; pbOutBuffer
+ push 0
+ push edi ; cbInBuffer
+ push [esp+2Ch+pbInBuffer] ; pbInBuffer
+; call Compress_lzma_internal
+ add esp, 28h
+ sub eax, 0
+ jz short loc_47F401
+ mov [esi], edi
+ dec eax
+
+loc_47F401: ; CODE XREF: Compress_lzma+3Fj
+ pop edi
+ pop esi
+ retn
+Compress_lzma endp
+
+; =============== S U B R O U T I N E =======================================
+
+sub_4D0770 proc near ; CODE XREF: CEncoder_Flush+1Ap
+
+arg_0 = dword ptr 4
+
+ push edi
+ mov edi, ecx
+ cmp byte ptr [edi+33B94h], 0
+ jz loc_4D0881
+ movzx eax, byte ptr [edi+10h]
+ mov ecx, [edi+38h]
+ shl eax, 4
+ push ebx
+ mov ebx, [esp+8+arg_0]
+ add eax, ebx
+ lea edx, [edi+eax*4+280F0h]
+ push ebp
+ push esi
+ lea esi, [edi+28h]
+ mov eax, ecx
+ shr eax, 0Bh
+ imul eax, [edx]
+ add [esi+8], eax
+ adc dword ptr [esi+0Ch], 0
+ sub ecx, eax
+ mov [esi+10h], ecx
+ mov eax, [edx]
+ mov ecx, eax
+ shr ecx, 5
+ sub eax, ecx
+ mov [edx], eax
+ mov eax, [esi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D07D3
+ shl eax, 8
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+
+loc_4D07D3: ; CODE XREF: sub_4D0770+54j
+ movzx edx, byte ptr [edi+10h]
+ mov ecx, [esi+10h]
+ lea eax, [edi+edx*4+283F0h]
+ shr ecx, 0Bh
+ imul ecx, [eax]
+ mov [esi+10h], ecx
+ mov ecx, [eax]
+ mov edx, 800h
+ sub edx, ecx
+ shr edx, 5
+ add edx, ecx
+ mov [eax], edx
+ mov eax, [esi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D0811
+ shl eax, 8
+ mov ecx, esi
+ mov [esi+10h], eax
+ call loc_4CF640
+
+loc_4D0811: ; CODE XREF: sub_4D0770+92j
+ movzx eax, byte ptr [edi+10h]
+ mov cl, ds:kMatchNextStates[eax]
+ push ebx
+ mov [edi+10h], cl
+ cmp byte ptr [edi+32EF4h], 0
+ push 0
+ lea ebp, [edi+28DB8h]
+ push esi
+ mov ecx, ebp
+ setz byte ptr [esp+1Ch+arg_0]
+ call sub_4D0020
+ cmp byte ptr [esp+10h+arg_0], 0
+ jz short loc_4D0854
+ add dword ptr [ebp+ebx*4+4C0Ch], 0FFFFFFFFh
+ jnz short loc_4D0854
+ push ebx
+ mov ecx, ebp
+ call sub_4CF740
+
+loc_4D0854: ; CODE XREF: sub_4D0770+D0j
+ ; sub_4D0770+DAj
+ push 3Fh
+ push esi
+ lea ecx, [edi+287B0h]
+ call sub_4CFC60
+ push 1Ah
+ push 3FFFFFFh
+ mov ecx, esi
+ call sub_4CF6E0
+ push 0Fh
+ push esi
+ lea ecx, [edi+28D78h]
+ call sub_4CFD00
+ pop esi
+ pop ebp
+ pop ebx
+
+loc_4D0881: ; CODE XREF: sub_4D0770+Aj
+ pop edi
+ retn 4
+sub_4D0770 endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+CEncoder_Flush proc near ; CODE XREF: CEncoder_CodeOneBlock+BAp
+ ; CEncoder_CodeOneBlock+1D0p ...
+
+arg_0 = dword ptr 4
+
+ push esi
+ mov esi, ecx
+ mov eax, [esi+0ECh]
+ test eax, eax
+ jnz short loc_4D08E5
+ mov eax, [esi+33B60h]
+ and eax, [esp+4+arg_0]
+ push ebx
+ push edi
+ push eax
+ call sub_4D0770
+ lea ebx, [esi+28h]
+ mov edi, 5
+
+loc_4D08B7: ; CODE XREF: CEncoder_Flush+31j
+ mov ecx, ebx
+ call loc_4CF640
+ sub edi, 1
+ jnz short loc_4D08B7
+ mov ecx, [esi+4Ch]
+ add esi, 40h
+ cmp ecx, [esi+4]
+ pop edi
+ pop ebx
+ jz short loc_4D08E3
+
+loc_4D08D0: ; CODE XREF: CEncoder_Flush+51j
+ mov ecx, esi
+ call sub_4CF450
+ test eax, eax
+ jnz short loc_4D08E5
+ mov edx, [esi+0Ch]
+ cmp edx, [esi+4]
+ jnz short loc_4D08D0
+
+loc_4D08E3: ; CODE XREF: CEncoder_Flush+3Ej
+ xor eax, eax
+
+loc_4D08E5: ; CODE XREF: CEncoder_Flush+Bj
+ ; CEncoder_Flush+49j
+ pop esi
+ retn 4
+CEncoder_Flush endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+; =============== S U B R O U T I N E =======================================
+
+CEncoder_CodeOneBlock proc near ; CODE XREF: CEncoder_CodeReal+B1p
+ ; CEncoder_CodeReal+F5p
+
+var_20 = byte ptr -20h
+var_1C = dword ptr -1Ch
+var_18 = dword ptr -18h
+var_14 = dword ptr -14h
+var_10 = dword ptr -10h
+var_C = dword ptr -0Ch
+var_8 = dword ptr -8
+var_4 = dword ptr -4
+arg_0 = dword ptr 4
+arg_4 = dword ptr 8
+arg_8 = dword ptr 0Ch
+
+ sub esp, 20h
+ push ebp
+ push esi
+ mov esi, ecx
+ push edi
+ mov edi, [esi+33B84h]
+ xor ebp, ebp
+ cmp edi, ebp
+ jz short loc_4D0952
+ mov eax, [edi]
+ mov ecx, [eax+4]
+ push edi
+ call ecx
+ mov eax, [esi+33B8Ch]
+ cmp eax, ebp
+ jz short loc_4D091E
+ mov edx, [eax]
+ push eax
+ mov eax, [edx+8]
+ call eax
+
+loc_4D091E: ; CODE XREF: CEncoder_CodeOneBlock+24j
+ mov [esi+33B8Ch], edi
+ mov ecx, [esi+80h]
+ mov edx, [esi+68h]
+ lea eax, [esi+33B88h]
+ push ecx
+ mov dword ptr [eax], offset loc_4CF210
+ mov [esi+0B8h], eax
+ call edx
+ add esp, 4
+ mov byte ptr [esi+33B95h], 1
+ mov [esi+33B84h], ebp
+
+loc_4D0952: ; CODE XREF: CEncoder_CodeOneBlock+12j
+ mov eax, [esp+2Ch+arg_8]
+ mov dword ptr [eax], 1
+ cmp byte ptr [esi+33B80h], 0
+ jz short loc_4D0974
+ mov eax, [esi+0ECh]
+ pop edi
+ pop esi
+ pop ebp
+ add esp, 20h
+ retn 0Ch
+; ---------------------------------------------------------------------------
+
+loc_4D0974: ; CODE XREF: CEncoder_CodeOneBlock+73j
+ mov ecx, [esi+33B78h]
+ or ecx, [esi+33B7Ch]
+ push ebx
+ mov byte ptr [esi+33B80h], 1
+ jnz loc_4D0A9C
+ mov edx, [esi+80h]
+ mov eax, [esi+70h]
+ push edx
+ call eax
+ add esp, 4
+ test eax, eax
+ jnz short loc_4D09B9
+ mov ecx, [esi+33B78h]
+ push ecx
+ mov ecx, esi
+ call CEncoder_Flush
+ pop ebx
+ pop edi
+ pop esi
+ pop ebp
+ add esp, 20h
+ retn 0Ch
+; ---------------------------------------------------------------------------
+
+loc_4D09B9: ; CODE XREF: CEncoder_CodeOneBlock+AFj
+ lea edx, [esp+30h+var_4]
+ push edx
+ mov ecx, esi
+ call sub_4CB3B0
+ movzx ecx, byte ptr [esi+10h]
+ mov eax, [esi+33B60h]
+ and eax, [esi+33B78h]
+ mov edx, [esi+38h]
+ lea edi, [esi+28h]
+ shl ecx, 4
+ add eax, ecx
+ shr edx, 0Bh
+ imul edx, [esi+eax*4+280F0h]
+ lea eax, [esi+eax*4+280F0h]
+ mov [edi+10h], edx
+ mov ecx, [eax]
+ mov edx, 800h
+ sub edx, ecx
+ shr edx, 5
+ add edx, ecx
+ mov [eax], edx
+ mov eax, [edi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D0A1C
+ shl eax, 8
+ mov ecx, edi
+ mov [edi+10h], eax
+ call loc_4CF640
+
+loc_4D0A1C: ; CODE XREF: CEncoder_CodeOneBlock+11Dj
+ movzx eax, byte ptr [esi+10h]
+ mov cl, ds:kLiteralNextStates[eax]
+ mov [esi+10h], cl
+ mov edx, [esi+32F04h]
+ mov eax, [esi+80h]
+ mov ecx, [esi+6Ch]
+ neg edx
+ push edx
+ push eax
+ call ecx
+ mov bl, al
+ mov eax, [esi+32654h]
+ add esp, 8
+ mov byte ptr [esp+30h+var_10], bl
+ mov edx, [esp+30h+var_10]
+ push edx
+ movzx edx, byte ptr [esi+11h]
+ push edi
+ mov edi, [esi+3265Ch]
+ and edi, [esi+33B78h]
+ mov ecx, 8
+ sub cl, al
+ shr edx, cl
+ mov ecx, eax
+ shl edi, cl
+ add edx, edi
+ imul edx, 0C00h
+ add edx, [esi+32650h]
+ mov ecx, edx
+ call sub_4CFE30
+ add dword ptr [esi+32F04h], 0FFFFFFFFh
+ add dword ptr [esi+33B78h], 1
+ mov [esi+11h], bl
+ adc [esi+33B7Ch], ebp
+
+loc_4D0A9C: ; CODE XREF: CEncoder_CodeOneBlock+98j
+ mov edi, [esi+33B78h]
+ mov eax, [esi+80h]
+ mov ecx, [esi+70h]
+ push eax
+ mov [esp+34h+var_14], edi
+ mov [esp+34h+var_4], edi
+ call ecx
+ add esp, 4
+ test eax, eax
+ jnz short loc_4D0AD4
+ push edi
+ mov ecx, esi
+ call CEncoder_Flush
+ pop ebx
+ pop edi
+ pop esi
+ pop ebp
+ add esp, 20h
+ retn 0Ch
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_4D0AD0: ; CODE XREF: CEncoder_CodeOneBlock+735j
+ ; CEncoder_CodeOneBlock+78Bj
+ mov edi, [esp+30h+var_14]
+
+loc_4D0AD4: ; CODE XREF: CEncoder_CodeOneBlock+1CBj
+ cmp byte ptr [esi+32EF4h], 0
+ mov ecx, esi
+ jz short loc_4D0AEB
+ lea edx, [esp+30h+var_1C]
+ push edx
+ call CEncoder_GetOptimumFast
+ jmp short loc_4D0AF6
+; ---------------------------------------------------------------------------
+
+loc_4D0AEB: ; CODE XREF: CEncoder_CodeOneBlock+1EDj
+ lea eax, [esp+30h+var_1C]
+ push eax
+ push edi
+ call CEncoder_GetOptimum
+
+loc_4D0AF6: ; CODE XREF: CEncoder_CodeOneBlock+1F9j
+ mov ebx, [esi+33B60h]
+ and ebx, edi
+ cmp eax, 1
+ mov [esp+30h+var_18], eax
+ jnz loc_4D0C0E
+ cmp [esp+30h+var_1C], 0FFFFFFFFh
+ jnz loc_4D0C0E
+ movzx ecx, byte ptr [esi+10h]
+ mov edx, [esi+38h]
+ lea ebp, [esi+28h]
+ shl ecx, 4
+ shr edx, 0Bh
+ add ecx, ebx
+ imul edx, [esi+ecx*4+280F0h]
+ lea eax, [esi+ecx*4+280F0h]
+ mov [ebp+10h], edx
+ mov ecx, [eax]
+ mov edx, 800h
+ sub edx, ecx
+ shr edx, 5
+ add edx, ecx
+ mov [eax], edx
+ mov eax, [ebp+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D0B61
+ shl eax, 8
+ mov ecx, ebp
+ mov [ebp+10h], eax
+ call loc_4CF640
+
+loc_4D0B61: ; CODE XREF: CEncoder_CodeOneBlock+262j
+ mov eax, [esi+32F04h]
+ mov ecx, [esi+80h]
+ mov edx, [esi+6Ch]
+ neg eax
+ push eax
+ push ecx
+ call edx
+ movzx edi, byte ptr [esi+11h]
+ mov edx, [esi+3265Ch]
+ and edx, [esp+38h+var_14]
+ mov bl, al
+ mov eax, [esi+32654h]
+ mov ecx, 8
+ sub cl, al
+ shr edi, cl
+ mov ecx, eax
+ shl edx, cl
+ add esp, 8
+ mov byte ptr [esp+30h+var_10], bl
+ add edi, edx
+ imul edi, 0C00h
+ add edi, [esi+32650h]
+ cmp byte ptr [esi+10h], 7
+ jnb short loc_4D0BC3
+ mov eax, [esp+30h+var_10]
+ push eax
+ push ebp
+ mov ecx, edi
+ call sub_4CFE30
+ jmp short loc_4D0BF5
+; ---------------------------------------------------------------------------
+
+loc_4D0BC3: ; CODE XREF: CEncoder_CodeOneBlock+2C2j
+ mov edx, [esi+80h]
+ mov eax, [esi+6Ch]
+ or ecx, 0FFFFFFFFh
+ sub ecx, [esi+14h]
+ sub ecx, [esi+32F04h]
+ push ecx
+ push edx
+ call eax
+ mov ecx, [esp+38h+var_10]
+ add esp, 8
+ mov byte ptr [esp+30h+var_C], al
+ mov edx, [esp+30h+var_C]
+ push ecx
+ push edx
+ push ebp
+ mov ecx, edi
+ call sub_4CFED0
+
+loc_4D0BF5: ; CODE XREF: CEncoder_CodeOneBlock+2D1j
+ movzx eax, byte ptr [esi+10h]
+ mov cl, ds:kLiteralNextStates[eax]
+ mov ebp, [esp+30h+var_18]
+ mov [esi+10h], cl
+ mov [esi+11h], bl
+ jmp loc_4D1013
+; ---------------------------------------------------------------------------
+
+loc_4D0C0E: ; CODE XREF: CEncoder_CodeOneBlock+215j
+ ; CEncoder_CodeOneBlock+220j
+ movzx edx, byte ptr [esi+10h]
+ mov ecx, [esi+38h]
+ lea edi, [esi+28h]
+ shl edx, 4
+ mov eax, ecx
+ shr eax, 0Bh
+ add edx, ebx
+ imul eax, [esi+edx*4+280F0h]
+ add [edi+8], eax
+ lea edx, [esi+edx*4+280F0h]
+ mov ebp, 0
+ adc [edi+0Ch], ebp
+ sub ecx, eax
+ mov [edi+10h], ecx
+ mov eax, [edx]
+ mov ecx, eax
+ shr ecx, 5
+ sub eax, ecx
+ mov [edx], eax
+ mov eax, [edi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D0C63
+ shl eax, 8
+ mov ecx, edi
+ mov [edi+10h], eax
+ call loc_4CF640
+
+loc_4D0C63: ; CODE XREF: CEncoder_CodeOneBlock+364j
+ cmp [esp+30h+var_1C], 4
+ movzx edx, byte ptr [esi+10h]
+ mov ecx, [edi+10h]
+ jnb loc_4D0E91
+ mov eax, ecx
+ shr eax, 0Bh
+ imul eax, [esi+edx*4+283F0h]
+ add [edi+8], eax
+ lea edx, [esi+edx*4+283F0h]
+ adc [edi+0Ch], ebp
+ sub ecx, eax
+ mov [edi+10h], ecx
+ mov eax, [edx]
+ mov ecx, eax
+ shr ecx, 5
+ sub eax, ecx
+ mov [edx], eax
+ mov eax, [edi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D0CB6
+ shl eax, 8
+ mov ecx, edi
+ mov [edi+10h], eax
+ call loc_4CF640
+
+loc_4D0CB6: ; CODE XREF: CEncoder_CodeOneBlock+3B7j
+ mov eax, [esp+30h+var_1C]
+ cmp eax, ebp
+ mov ecx, [edi+10h]
+ jnz short loc_4D0D24
+ movzx edx, byte ptr [esi+10h]
+ lea eax, [esi+edx*4+28420h]
+ shr ecx, 0Bh
+ imul ecx, [eax]
+ mov [edi+10h], ecx
+ mov ecx, [eax]
+ mov edx, 800h
+ sub edx, ecx
+ shr edx, 5
+ add edx, ecx
+ mov [eax], edx
+ mov eax, [edi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D0CFC
+ shl eax, 8
+ mov ecx, edi
+ mov [edi+10h], eax
+ call loc_4CF640
+
+loc_4D0CFC: ; CODE XREF: CEncoder_CodeOneBlock+3FDj
+ mov ebp, [esp+30h+var_18]
+ movzx ecx, byte ptr [esi+10h]
+ xor eax, eax
+ cmp ebp, 1
+ setnz al
+ shl ecx, 4
+ add ecx, ebx
+ lea ecx, [esi+ecx*4+284B0h]
+ push eax
+ push edi
+ call sub_4CFAC0
+ jmp loc_4D0E2E
+; ---------------------------------------------------------------------------
+
+loc_4D0D24: ; CODE XREF: CEncoder_CodeOneBlock+3CFj
+ mov edx, [esi+eax*4+14h]
+ movzx eax, byte ptr [esi+10h]
+ mov [esp+30h+var_8], edx
+ lea edx, [esi+eax*4+28420h]
+ mov eax, ecx
+ shr eax, 0Bh
+ imul eax, [edx]
+ add [edi+8], eax
+ adc [edi+0Ch], ebp
+ sub ecx, eax
+ mov [edi+10h], ecx
+ mov eax, [edx]
+ mov ecx, eax
+ shr ecx, 5
+ sub eax, ecx
+ mov [edx], eax
+ mov eax, [edi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D0D6C
+ shl eax, 8
+ mov ecx, edi
+ mov [edi+10h], eax
+ call loc_4CF640
+
+loc_4D0D6C: ; CODE XREF: CEncoder_CodeOneBlock+46Dj
+ cmp [esp+30h+var_1C], 1
+ mov ecx, [edi+10h]
+ jnz short loc_4D0DB3
+ movzx edx, byte ptr [esi+10h]
+ lea eax, [esi+edx*4+28450h]
+ shr ecx, 0Bh
+ imul ecx, [eax]
+ mov [edi+10h], ecx
+ mov ecx, [eax]
+ mov edx, 800h
+ sub edx, ecx
+ shr edx, 5
+ add edx, ecx
+ mov [eax], edx
+ mov eax, [edi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D0E1D
+ shl eax, 8
+ mov ecx, edi
+ mov [edi+10h], eax
+ call loc_4CF640
+ jmp short loc_4D0E1D
+; ---------------------------------------------------------------------------
+
+loc_4D0DB3: ; CODE XREF: CEncoder_CodeOneBlock+484j
+ movzx eax, byte ptr [esi+10h]
+ lea edx, [esi+eax*4+28450h]
+ mov eax, ecx
+ shr eax, 0Bh
+ imul eax, [edx]
+ add [edi+8], eax
+ adc [edi+0Ch], ebp
+ sub ecx, eax
+ mov [edi+10h], ecx
+ mov eax, [edx]
+ mov ecx, eax
+ shr ecx, 5
+ sub eax, ecx
+ mov [edx], eax
+ mov eax, [edi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D0DF3
+ shl eax, 8
+ mov ecx, edi
+ mov [edi+10h], eax
+ call loc_4CF640
+
+loc_4D0DF3: ; CODE XREF: CEncoder_CodeOneBlock+4F4j
+ mov ebp, [esp+30h+var_1C]
+ movzx eax, byte ptr [esi+10h]
+ lea edx, [ebp-2]
+ push edx
+ push edi
+ lea ecx, [esi+eax*4+28480h]
+ call sub_4CFAC0
+ cmp ebp, 3
+ jnz short loc_4D0E17
+ mov ecx, [esi+1Ch]
+ mov [esi+20h], ecx
+
+loc_4D0E17: ; CODE XREF: CEncoder_CodeOneBlock+51Fj
+ mov edx, [esi+18h]
+ mov [esi+1Ch], edx
+
+loc_4D0E1D: ; CODE XREF: CEncoder_CodeOneBlock+4B2j
+ ; CEncoder_CodeOneBlock+4C1j
+ mov eax, [esi+14h]
+ mov ecx, [esp+30h+var_8]
+ mov ebp, [esp+30h+var_18]
+ mov [esi+18h], eax
+ mov [esi+14h], ecx
+
+loc_4D0E2E: ; CODE XREF: CEncoder_CodeOneBlock+42Fj
+ cmp ebp, 1
+ jnz short loc_4D0E45
+ movzx edx, byte ptr [esi+10h]
+ mov al, ds:kShortRepNextStates[edx]
+ mov [esi+10h], al
+ jmp loc_4D0FF5
+; ---------------------------------------------------------------------------
+
+loc_4D0E45: ; CODE XREF: CEncoder_CodeOneBlock+541j
+ cmp byte ptr [esi+32EF4h], 0
+ push ebx
+ lea edx, [ebp-2]
+ push edx
+ lea ecx, [esi+2DA04h]
+ push edi
+ setz [esp+3Ch+var_20]
+ call sub_4D0020
+ cmp [esp+30h+var_20], 0
+ jz short loc_4D0E7F
+ add dword ptr [esi+ebx*4+32610h], 0FFFFFFFFh
+ lea ecx, [esi+2DA04h]
+ jnz short loc_4D0E7F
+ push ebx
+ call sub_4CF740
+
+loc_4D0E7F: ; CODE XREF: CEncoder_CodeOneBlock+577j
+ ; CEncoder_CodeOneBlock+587j
+ movzx eax, byte ptr [esi+10h]
+ mov cl, ds:kRepNextStates[eax]
+ mov [esi+10h], cl
+ jmp loc_4D0FF5
+; ---------------------------------------------------------------------------
+
+loc_4D0E91: ; CODE XREF: CEncoder_CodeOneBlock+37Fj
+ lea eax, [esi+edx*4+283F0h]
+ shr ecx, 0Bh
+ imul ecx, [eax]
+ mov [edi+10h], ecx
+ mov ecx, [eax]
+ mov edx, 800h
+ sub edx, ecx
+ shr edx, 5
+ add edx, ecx
+ mov [eax], edx
+ mov eax, [edi+10h]
+ cmp eax, 1000000h
+ jnb short loc_4D0EC8
+ shl eax, 8
+ mov ecx, edi
+ mov [edi+10h], eax
+ call loc_4CF640
+
+loc_4D0EC8: ; CODE XREF: CEncoder_CodeOneBlock+5C9j
+ movzx eax, byte ptr [esi+10h]
+ mov cl, ds:kMatchNextStates[eax]
+ mov eax, [esp+30h+var_18]
+ mov [esi+10h], cl
+ cmp byte ptr [esi+32EF4h], 0
+ push ebx
+ setz [esp+34h+var_20]
+ add eax, 0FFFFFFFEh
+ push eax
+ lea ebp, [esi+28DB8h]
+ push edi
+ mov ecx, ebp
+ call sub_4D0020
+ cmp [esp+30h+var_20], 0
+ jz short loc_4D0F11
+ add dword ptr [ebp+ebx*4+4C0Ch], 0FFFFFFFFh
+ jnz short loc_4D0F11
+ push ebx
+ mov ecx, ebp
+ call sub_4CF740
+
+loc_4D0F11: ; CODE XREF: CEncoder_CodeOneBlock+60Dj
+ ; CEncoder_CodeOneBlock+617j
+ mov eax, [esp+30h+var_1C]
+ sub eax, 4
+ cmp eax, 2000h
+ mov [esp+30h+var_1C], eax
+ jnb short loc_4D0F2C
+ movzx ebp, byte ptr dword_551198[eax]
+ jmp short loc_4D0F4F
+; ---------------------------------------------------------------------------
+
+loc_4D0F2C: ; CODE XREF: CEncoder_CodeOneBlock+631j
+ cmp eax, 2000000h
+ jnb short loc_4D0F42
+ shr eax, 0Ch
+ movzx ebp, byte ptr dword_551198[eax]
+ add ebp, 18h
+ jmp short loc_4D0F4F
+; ---------------------------------------------------------------------------
+
+loc_4D0F42: ; CODE XREF: CEncoder_CodeOneBlock+641j
+ shr eax, 18h
+ movzx ebp, byte ptr dword_551198[eax]
+ add ebp, 30h
+
+loc_4D0F4F: ; CODE XREF: CEncoder_CodeOneBlock+63Aj
+ ; CEncoder_CodeOneBlock+650j
+ mov eax, [esp+30h+var_18]
+ add eax, 0FFFFFFFEh
+ cmp eax, 4
+ jb short loc_4D0F60
+ mov eax, 3
+
+loc_4D0F60: ; CODE XREF: CEncoder_CodeOneBlock+669j
+ push ebp
+ shl eax, 8
+ push edi
+ lea ecx, [eax+esi+287B0h]
+ call sub_4CFC60
+ cmp ebp, 4
+ jb short loc_4D0FD1
+ mov ebx, [esp+30h+var_1C]
+ mov ecx, ebp
+ mov eax, ebp
+ and eax, 1
+ shr ecx, 1
+ sub ecx, 1
+ or eax, 2
+ shl eax, cl
+ sub ebx, eax
+ cmp ebp, 0Eh
+ jnb short loc_4D0FA9
+ push ebx
+ push ecx
+ sub eax, ebp
+ lea edx, [esi+eax*4+28BACh]
+ push edi
+ push edx
+ call sub_4CFD90
+ add esp, 10h
+ jmp short loc_4D0FD1
+; ---------------------------------------------------------------------------
+
+loc_4D0FA9: ; CODE XREF: CEncoder_CodeOneBlock+6A0j
+ add ecx, 0FFFFFFFCh
+ push ecx
+ mov eax, ebx
+ shr eax, 4
+ push eax
+ mov ecx, edi
+ call sub_4CF6E0
+ and ebx, 0Fh
+ push ebx
+ push edi
+ lea ecx, [esi+28D78h]
+ call sub_4CFD00
+ add dword ptr [esi+33B54h], 1
+
+loc_4D0FD1: ; CODE XREF: CEncoder_CodeOneBlock+684j
+ ; CEncoder_CodeOneBlock+6B7j
+ mov ecx, [esi+1Ch]
+ mov edx, [esi+18h]
+ mov eax, [esi+14h]
+ add dword ptr [esi+33B70h], 1
+ mov ebp, [esp+30h+var_18]
+ mov [esi+20h], ecx
+ mov ecx, [esp+30h+var_1C]
+ mov [esi+1Ch], edx
+ mov [esi+18h], eax
+ mov [esi+14h], ecx
+
+loc_4D0FF5: ; CODE XREF: CEncoder_CodeOneBlock+550j
+ ; CEncoder_CodeOneBlock+59Cj
+ mov eax, [esi+80h]
+ mov ecx, [esi+6Ch]
+ mov edx, ebp
+ sub edx, [esi+32F04h]
+ sub edx, 1
+ push edx
+ push eax
+ call ecx
+ add esp, 8
+ mov [esi+11h], al
+
+loc_4D1013: ; CODE XREF: CEncoder_CodeOneBlock+319j
+ sub [esi+32F04h], ebp
+ mov eax, [esi+32F04h]
+ add [esp+30h+var_14], ebp
+ test eax, eax
+ jnz loc_4D0AD0
+ cmp [esi+32EF4h], al
+ jnz short loc_4D1056
+ cmp dword ptr [esi+33B70h], 80h
+ jb short loc_4D1046
+ mov ecx, esi
+ call CEncoder_FillDistancesPrices
+
+loc_4D1046: ; CODE XREF: CEncoder_CodeOneBlock+74Dj
+ cmp dword ptr [esi+33B54h], 10h
+ jb short loc_4D1056
+ mov ecx, esi
+ call CEncoder_FillAlignPrices
+
+loc_4D1056: ; CODE XREF: CEncoder_CodeOneBlock+741j
+ ; CEncoder_CodeOneBlock+75Dj
+ mov edx, [esi+80h]
+ mov eax, [esi+70h]
+ push edx
+ call eax
+ add esp, 4
+ test eax, eax
+ mov eax, [esp+30h+var_14]
+ jz short loc_4D10D7
+ mov ecx, [esp+30h+var_4]
+ mov edx, eax
+ sub edx, ecx
+ cmp edx, 4000h
+ jb loc_4D0AD0
+ sub eax, ecx
+ add [esi+33B78h], eax
+ mov ecx, [esi+33B78h]
+ mov eax, [esp+30h+arg_0]
+ adc dword ptr [esi+33B7Ch], 0
+ mov [eax], ecx
+ mov edx, [esi+33B7Ch]
+ lea ecx, [esi+28h]
+ mov [eax+4], edx
+ call sub_4CD8B0
+ mov ecx, [esp+30h+arg_4]
+ mov [ecx], eax
+ mov eax, [esp+30h+arg_8]
+ mov [ecx+4], edx
+ pop ebx
+ mov byte ptr [esi+33B80h], 0
+ pop edi
+ mov dword ptr [eax], 0
+ mov eax, [esi+0ECh]
+ pop esi
+ pop ebp
+ add esp, 20h
+ retn 0Ch
+; ---------------------------------------------------------------------------
+
+loc_4D10D7: ; CODE XREF: CEncoder_CodeOneBlock+77Bj
+ push eax
+ mov ecx, esi
+ call CEncoder_Flush
+ pop ebx
+ pop edi
+ pop esi
+ pop ebp
+ add esp, 20h
+ retn 0Ch
+CEncoder_CodeOneBlock endp
+
+; ---------------------------------------------------------------------------
+ align 10h
+CEncoder_CodeReal proc near ; CODE XREF: CEncoder_Code+49p
+
+var_20 = dword ptr -20h
+processedOutSize= byte ptr -1Ch
+processedInSize = byte ptr -14h
+var_C = dword ptr -0Ch
+var_4 = dword ptr -4
+inStream = dword ptr 4
+outStream = dword ptr 8
+inSize = dword ptr 0Ch
+outSize = dword ptr 10h
+progress = dword ptr 14h
+
+ push 0FFFFFFFFh
+ push offset loc_4DA128
+ mov eax, dword ptr fs:[0]
+ push eax
+ sub esp, 14h
+ push ebp
+ push esi
+ push edi
+ mov eax, dword_544960
+ xor eax, esp
+ push eax
+ lea eax, [esp+30h+var_C]
+ mov dword ptr fs:[0], eax
+ mov esi, ecx
+ mov [esp+30h+var_20], esi
+ mov eax, [esp+30h+outSize]
+ mov ecx, [esp+30h+inSize]
+ mov edx, [esp+30h+outStream]
+ push eax
+ mov eax, [esp+34h+inStream]
+ push ecx
+ push edx
+ push eax
+ mov ecx, esi
+ mov [esp+40h+var_4], 0
+ call CEncoder_SetStreams
+ mov edi, eax
+ test edi, edi
+ jz short loc_4D1190
+ cmp dword ptr [esi+80h], 0
+ mov [esp+30h+var_4], 0FFFFFFFFh
+ jz short loc_4D1166
+ cmp byte ptr [esi+33B95h], 0
+ jz short loc_4D1166
+ mov byte ptr [esi+33B95h], 0
+
+loc_4D1166: ; CODE XREF: CEncoder_CodeReal+64j
+ ; CEncoder_CodeReal+6Dj
+ mov eax, [esi+33B8Ch]
+ test eax, eax
+ jz short loc_4D1182
+ mov ecx, [eax]
+ mov edx, [ecx+8]
+ push eax
+ call edx
+ mov dword ptr [esi+33B8Ch], 0
+
+loc_4D1182: ; CODE XREF: CEncoder_CodeReal+7Ej
+ mov ecx, [esi+4]
+ mov edx, [ecx+10h]
+ lea eax, [esi+4]
+ push eax
+ call edx
+ jmp short loc_4D1201
+; ---------------------------------------------------------------------------
+
+loc_4D1190: ; CODE XREF: CEncoder_CodeReal+53j
+ lea eax, [esp+30h+outSize]
+ push eax
+ lea ecx, [esp+34h+processedOutSize]
+ push ecx
+ lea edx, [esp+38h+processedInSize]
+ push edx
+ mov ecx, esi
+ call CEncoder_CodeOneBlock
+ mov edi, eax
+ test edi, edi
+ jnz short loc_4D11F0
+ mov ebp, [esp+30h+progress]
+
+loc_4D11B0: ; CODE XREF: CEncoder_CodeReal+FEj
+ cmp [esp+30h+outSize], 0
+ jnz short loc_4D1218
+ test ebp, ebp
+ jz short loc_4D11D4
+ mov eax, [ebp+0]
+ mov eax, [eax+0Ch]
+ lea ecx, [esp+30h+processedOutSize]
+ push ecx
+ lea edx, [esp+34h+processedInSize]
+ push edx
+ push ebp
+ call eax ; SetRatioInfo
+ mov edi, eax
+ test edi, edi
+ jnz short loc_4D11F0
+
+loc_4D11D4: ; CODE XREF: CEncoder_CodeReal+C9j
+ lea ecx, [esp+30h+outSize]
+ push ecx
+ lea edx, [esp+34h+processedOutSize]
+ push edx
+ lea eax, [esp+38h+processedInSize]
+ push eax
+ mov ecx, esi
+ call CEncoder_CodeOneBlock
+ mov edi, eax
+ test edi, edi
+ jz short loc_4D11B0
+
+loc_4D11F0: ; CODE XREF: CEncoder_CodeReal+BAj
+ ; CEncoder_CodeReal+E2j
+ lea ecx, [esp+30h+var_20]
+ mov [esp+30h+var_4], 0FFFFFFFFh
+ call sub_4CDA70
+
+loc_4D1201: ; CODE XREF: CEncoder_CodeReal+9Ej
+ mov eax, edi
+ mov ecx, [esp+30h+var_C]
+ mov dword ptr fs:[0], ecx
+ pop ecx
+ pop edi
+ pop esi
+ pop ebp
+ add esp, 20h
+ retn 14h
+; ---------------------------------------------------------------------------
+
+loc_4D1218: ; CODE XREF: CEncoder_CodeReal+C5j
+ lea ecx, [esp+30h+var_20]
+ mov [esp+30h+var_4], 0FFFFFFFFh
+ call sub_4CDA70
+ xor eax, eax
+ mov ecx, [esp+30h+var_C]
+ mov dword ptr fs:[0], ecx
+ pop ecx
+ pop edi
+ pop esi
+ pop ebp
+ add esp, 20h
+ retn 14h
+CEncoder_CodeReal endp
+
+; =============== S U B R O U T I N E =======================================
+; Attributes: bp-based frame
+
+CEncoder_Code proc near ; DATA XREF: .rdata:00517B08o
+; sub_4D1240
+
+var_10 = dword ptr -10h
+var_C = dword ptr -0Ch
+var_4 = dword ptr -4
+pThis = dword ptr 8
+pInStream = dword ptr 0Ch
+pOutStream = dword ptr 10h
+pInSize = dword ptr 14h
+pOutSize = dword ptr 18h
+progress = dword ptr 1Ch
+
+ push ebp
+ mov ebp, esp
+ push 0FFFFFFFFh
+ push offset loc_4DA150
+ mov eax, dword ptr fs:[0]
+ push eax
+ sub esp, 8
+ push ebx
+ push esi
+ push edi
+ mov eax, dword_544960
+ xor eax, ebp
+ push eax
+ lea eax, [ebp+var_C]
+ mov dword ptr fs:[0], eax
+ mov [ebp+var_10], esp
+ mov eax, [ebp+progress]
+ mov ecx, [ebp+pOutSize]
+ mov edx, [ebp+pInSize]
+ push eax
+ mov eax, [ebp+pOutStream]
+ push ecx
+ mov ecx, [ebp+pInStream]
+ push edx
+ push eax
+ push ecx
+ mov ecx, [ebp+pThis]
+ mov [ebp+var_4], 0
+ call CEncoder_CodeReal
+ mov ecx, [ebp+var_C]
+ mov dword ptr fs:[0], ecx
+ pop ecx
+ pop edi
+ pop esi
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 18h
+CEncoder_Code endp
+
+; ---------------------------------------------------------------------------
+
+loc_4DA0FB: ; DATA XREF: Compress_lzma_internal+2o
+ mov edx, [esp+8]
+ lea eax, [edx-5Ch]
+ mov ecx, [edx-60h]
+ xor ecx, eax
+ call sub_4A0686
+ mov eax, 0 ; offset dword_526E44
+ int 3;
+; jmp ___CxxFrameHandler3
+
+loc_4DA0C9: ; DATA XREF: sub_4CF810+2o
+ mov edx, [esp+8]
+ lea eax, [edx-0Ch]
+ mov ecx, [edx-10h]
+ xor ecx, eax
+ call sub_4A0686
+ mov eax, 0 ; offset dword_526E18
+ int 3;
+; jmp ___CxxFrameHandler3
+
+loc_4DA128: ; DATA XREF: CEncoder_CodeReal+2o
+ mov edx, [esp+8]
+ lea eax, [edx-20h]
+ mov ecx, [edx-24h]
+ xor ecx, eax
+ call sub_4A0686
+ mov eax, 0 ; offset unk_526E70
+ int 3;
+; jmp ___CxxFrameHandler3
+
+loc_4DA150: ; DATA XREF: CEncoder_Code+5o
+ mov edx, [esp+8]
+ lea eax, [edx+0Ch]
+ mov ecx, [edx-18h]
+ xor ecx, eax
+ call sub_4A0686
+ mov eax, 0 ; offset unk_526ED8
+ int 3;
+; jmp ___CxxFrameHandler3
+
+END
diff --git a/dep/libmpq/AUTHORS b/dep/libmpq/AUTHORS
deleted file mode 100644
index 3d7da7bec9a..00000000000
--- a/dep/libmpq/AUTHORS
+++ /dev/null
@@ -1,10 +0,0 @@
-Project Initiator:
-
- * Maik Broemme <mbroemme@plusserver.de>
-
-Developers:
-
- * Maik Broemme <mbroemme@plusserver.de>
- * Tilman Sauerbeck <tilman@code-monkey.de>
- * Forrest Voight <voights@gmail.com>
- * Georg Lukas <georg@op-co.de>
diff --git a/dep/libmpq/CMakeLists.txt b/dep/libmpq/CMakeLists.txt
deleted file mode 100644
index cd14098c698..00000000000
--- a/dep/libmpq/CMakeLists.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
-#
-# This file is free software; as a special exception the author gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-file(GLOB sources_mpq libmpq/*.c libmpq/*.h)
-
-set(mpq_STAT_SRCS
- ${sources_mpq}
-)
-
-if( UNIX )
- include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_SOURCE_DIR}/dep/zlib
- ${CMAKE_SOURCE_DIR}/dep/bzip2
- )
-elseif( WIN32 )
- include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_SOURCE_DIR}/win
- ${CMAKE_SOURCE_DIR}/dep/zlib
- ${CMAKE_SOURCE_DIR}/dep/bzip2
- )
-endif()
-
-add_library(mpq STATIC ${mpq_STAT_SRCS})
-
-set_target_properties(mpq PROPERTIES LINKER_LANGUAGE CXX)
diff --git a/dep/libmpq/COPYING b/dep/libmpq/COPYING
deleted file mode 100644
index 4189933be9f..00000000000
--- a/dep/libmpq/COPYING
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- Appendix: How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) 19yy <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) 19yy name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/dep/libmpq/FAQ b/dep/libmpq/FAQ
deleted file mode 100644
index 52ca9f3c705..00000000000
--- a/dep/libmpq/FAQ
+++ /dev/null
@@ -1,68 +0,0 @@
-FAQ - Frequently Asked Questions
-================================
-
-Q: What is libmpq?
-A: libmpq is a library for manipulating MoPaQ mpq archives mostly used
- used by Blizzard in their games.
-
-Q: What can i do with libmpq?
-A: With libmpq you can write applications which can extract, create
- and manipulate mpq archives.
-
-Q: Is it legal?
-A: Yes, i think so. I have no idea why it should not, all informations
- about the fileformat are available.
-
-Q: Is there a description of the functions?
-A: Since version 0.4.0 libmpq comes with a API documentation for
- developers. The documentation is written as manual pages.
-
-Q: Can i help?
-A: Yes, help is needed, not only with developing, also with testing.
- A good point to start is using a recent SVN version of libmpq and
- trying to use it with every mpq archive you could get :)
-
-Q: Can you give a small example to demonstrate the usage?
-A: Of course :) The example below takes first parameter as mpq archive
- and extracts the first file to a buffer.
-
- /*
- * Compile with:
- *
- * x86_32:
- *
- * gcc \
- * -D_FILE_OFFSET_BITS=64 \
- * -D_LARGE_FILES=1 \
- * -D_LARGEFILE_SOURCE=1 \
- * mpq-example.c -o mpq-example -lmpq -lz -lbz2 -I/usr/local/include/libmpq
- *
- * x86_64:
- *
- * gcc \
- * -D_LARGE_FILES=1 \
- * mpq-example.c -o mpq-example -lmpq -lz -lbz2 -I/usr/local/include/libmpq
- */
-
- #include <mpq.h>
- #include <stdlib.h>
- #include <limits.h>
-
- int main(int argc, char **argv) {
- mpq_archive_s *mpq_archive;
- off_t out_size;
- char *out_buf;
-
- /* open the mpq archive given as first parameter. */
- libmpq__archive_open(&mpq_archive, argv[1], -1);
-
- /* get size of first file (0) and malloc output buffer. */
- libmpq__file_unpacked_size(mpq_archive, 0, &out_size);
- out_buf = malloc(out_size);
-
- /* read, decrypt and unpack file to output buffer. */
- libmpq__file_read(mpq_archive, 0, out_buf, out_size, NULL);
-
- /* close the mpq archive. */
- libmpq__archive_close(mpq_archive);
- }
diff --git a/dep/libmpq/INSTALL b/dep/libmpq/INSTALL
deleted file mode 100644
index b42a17ac464..00000000000
--- a/dep/libmpq/INSTALL
+++ /dev/null
@@ -1,182 +0,0 @@
-Basic Installation
-==================
-
- These are generic installation instructions.
-
- The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation. It uses
-those values to create a `Makefile' in each directory of the package.
-It may also create one or more `.h' files containing system-dependent
-definitions. Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, a file
-`config.cache' that saves the results of its tests to speed up
-reconfiguring, and a file `config.log' containing compiler output
-(useful mainly for debugging `configure').
-
- If you need to do unusual things to compile the package, please try
-to figure out how `configure' could check whether to do them, and mail
-diffs or instructions to the address given in the `README' so they can
-be considered for the next release. If at some point `config.cache'
-contains results you don't want to keep, you may remove or edit it.
-
- The file `configure.in' is used to create `configure' by a program
-called `autoconf'. You only need `configure.in' if you want to change
-it or regenerate `configure' using a newer version of `autoconf'.
-
-The simplest way to compile this package is:
-
- 1. `cd' to the directory containing the package's source code and type
- `./configure' to configure the package for your system. If you're
- using `csh' on an old version of System V, you might need to type
- `sh ./configure' instead to prevent `csh' from trying to execute
- `configure' itself.
-
- Running `configure' takes awhile. While running, it prints some
- messages telling which features it is checking for.
-
- 2. Type `make' to compile the package.
-
- 3. Optionally, type `make check' to run any self-tests that come with
- the package.
-
- 4. Type `make install' to install the programs and any data files and
- documentation.
-
- 5. You can remove the program binaries and object files from the
- source code directory by typing `make clean'. To also remove the
- files that `configure' created (so you can compile the package for
- a different kind of computer), type `make distclean'. There is
- also a `make maintainer-clean' target, but that is intended mainly
- for the package's developers. If you use it, you may have to get
- all sorts of other programs in order to regenerate files that came
- with the distribution.
-
-Compilers and Options
-=====================
-
- Some systems require unusual options for compilation or linking that
-the `configure' script does not know about. You can give `configure'
-initial values for variables by setting them in the environment. Using
-a Bourne-compatible shell, you can do that on the command line like
-this:
- CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
-
-Or on systems that have the `env' program, you can do it like this:
- env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
-
-Compiling For Multiple Architectures
-====================================
-
- You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory. To do this, you must use a version of `make' that
-supports the `VPATH' variable, such as GNU `make'. `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script. `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'.
-
- If you have to use a `make' that does not supports the `VPATH'
-variable, you have to compile the package for one architecture at a time
-in the source code directory. After you have installed the package for
-one architecture, use `make distclean' before reconfiguring for another
-architecture.
-
-Installation Names
-==================
-
- By default, `make install' will install the package's files in
-`/usr/local/bin', `/usr/local/man', etc. You can specify an
-installation prefix other than `/usr/local' by giving `configure' the
-option `--prefix=PATH'.
-
- You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files. If you
-give `configure' the option `--exec-prefix=PATH', the package will use
-PATH as the prefix for installing programs and libraries.
-Documentation and other data files will still use the regular prefix.
-
- In addition, if you use an unusual directory layout you can give
-options like `--bindir=PATH' to specify different values for particular
-kinds of files. Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them.
-
- If the package supports it, you can cause programs to be installed
-with an extra prefix or suffix on their names by giving `configure' the
-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
-
-Optional Features
-=================
-
- Some packages pay attention to `--enable-FEATURE' options to
-`configure', where FEATURE indicates an optional part of the package.
-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
-is something like `gnu-as' or `x' (for the X Window System). The
-`README' should mention any `--enable-' and `--with-' options that the
-package recognizes.
-
- For packages that use the X Window System, `configure' can usually
-find the X include and library files automatically, but if it doesn't,
-you can use the `configure' options `--x-includes=DIR' and
-`--x-libraries=DIR' to specify their locations.
-
-Specifying the System Type
-==========================
-
- There may be some features `configure' can not figure out
-automatically, but needs to determine by the type of host the package
-will run on. Usually `configure' can figure that out, but if it prints
-a message saying it can not guess the host type, give it the
-`--host=TYPE' option. TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name with three fields:
- CPU-COMPANY-SYSTEM
-
-See the file `config.sub' for the possible values of each field. If
-`config.sub' isn't included in this package, then this package doesn't
-need to know the host type.
-
- If you are building compiler tools for cross-compiling, you can also
-use the `--target=TYPE' option to select the type of system they will
-produce code for and the `--build=TYPE' option to select the type of
-system on which you are compiling the package.
-
-Sharing Defaults
-================
-
- If you want to set default values for `configure' scripts to share,
-you can create a site shell script called `config.site' that gives
-default values for variables like `CC', `cache_file', and `prefix'.
-`configure' looks for `PREFIX/share/config.site' if it exists, then
-`PREFIX/etc/config.site' if it exists. Or, you can set the
-`CONFIG_SITE' environment variable to the location of the site script.
-A warning: not all `configure' scripts look for a site script.
-
-Operation Controls
-==================
-
- `configure' recognizes the following options to control how it
-operates.
-
-`--cache-file=FILE'
- Use and save the results of the tests in FILE instead of
- `./config.cache'. Set FILE to `/dev/null' to disable caching, for
- debugging `configure'.
-
-`--help'
- Print a summary of the options to `configure', and exit.
-
-`--quiet'
-`--silent'
-`-q'
- Do not print messages saying which checks are being made. To
- suppress all normal output, redirect it to `/dev/null' (any error
- messages will still be shown).
-
-`--srcdir=DIR'
- Look for the package's source code in directory DIR. Usually
- `configure' can determine that directory automatically.
-
-`--version'
- Print the version of Autoconf used to generate the `configure'
- script, and exit.
-
-`configure' also accepts some other, not widely useful, options.
diff --git a/dep/libmpq/Makefile.am b/dep/libmpq/Makefile.am
deleted file mode 100644
index 0a9b54c2526..00000000000
--- a/dep/libmpq/Makefile.am
+++ /dev/null
@@ -1,26 +0,0 @@
-# minimum required automake 1.6
-AUTOMAKE_OPTIONS = 1.6
-
-# any directories which should be built and installed.
-SUBDIRS = libmpq bindings doc
-
-# the directories which are part of the distribution.
-DIST_SUBDIRS = $(SUBDIRS)
-
-# libmpq runtime configuration script.
-bin_SCRIPTS = libmpq-config
-
-# pkg-config installation directory.
-pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libmpq.pc
-
-# extra stuff.
-EXTRA_DIST = \
- AUTHORS \
- COPYING \
- FAQ \
- INSTALL \
- NEWS \
- README \
- THANKS \
- TODO
diff --git a/dep/libmpq/NEWS b/dep/libmpq/NEWS
deleted file mode 100644
index 74850a8a5bb..00000000000
--- a/dep/libmpq/NEWS
+++ /dev/null
@@ -1,76 +0,0 @@
-Changes version 0.4.2 (2008-05-16)
-==================================
-
- * added full extraction support for protected maps used in
- warcraft 3.
-
- * added full extraction support for all blizzard titles until
- world of warcraft - the burning crusade.
-
- * added support for archives version 2 with extended header and
- extended block table.
-
- * added support for the bzip2 compression algorithm.
-
- * added support for archives and files inside archive > 2gb.
-
- * added generic read functions, which will do decryption,
- decompression or exploding.
-
- * the info functions are no longer exported by the library and
- were replaced by separate api functions.
-
- * the file number and block number are count from 0 instead
- of 1.
-
- * added python bindings.
-
- * linking against libmpq requires from now on the usual largefile
- macros -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES=1 -D_LARGEFILE_SOURCE=1
-
-Changes version 0.4.1 (2008-04-02)
-==================================
-
- * memory, speed and stability improvements.
-
- * split sourcecode into library and utility package.
-
-Changes version 0.4.0 (2008-03-31)
-==================================
-
- * added robust error handling to make the library and extracting
- utility more stable.
-
- * added c++ bindings to public include and moved internal defines
- and functions to private include.
-
- * added support for 64-bit architectures and removed any stupid
- pointer to int arithmetics.
-
- * added much better member names to the structures to make
- developers able to understand the code on reading.
-
- * added full api documentation using manual pages.
-
- * added full extraction support for all blizzard titles until
- warcraft 3 - the frozen throne.
-
- * added support for single sector and stored files (neither
- compressed nor imploded).
-
- * added support for files which have compressed size greater than
- uncompressed size.
-
- * removed the external listfile database support from 0.3.0 it
- was a weird implementation.
-
-Changes version 0.3.0 (2004-02-12)
-==================================
-
- * added listfile database support from external files.
-
-Initial version 0.2.1 (2004-01-17)
-==================================
-
- * first version which was able to extract some of the older mopaq
- archives.
diff --git a/dep/libmpq/README b/dep/libmpq/README
deleted file mode 100644
index 3f1bd3a1e9f..00000000000
--- a/dep/libmpq/README
+++ /dev/null
@@ -1,34 +0,0 @@
-Introduction
-============
-
-'libmpq' is a library which can be easily used in own applications
-to extract, create or manipulate MoPaQ mpq archives.
-
-MPQ, or MoPaQ, is a proprietary archive format created by
-Mike O'Brien, the man hailed as Blizzard's multiplayer engine
-genius, back in 1996 as a general purpose archive for use with
-Diablo, and named narcissistically for its creator
-"Mike O'brien PaCK". The copyrights to it, however, are held by
-Havas Interactive, Blizzard's parent company. The archive format
-is used by many Blizzard titles like Diablo, Diablo 2, Starcraft,
-Warcraft 2: BNE, a newer version in Warcraft 3 and World of
-Warcraft (WoW).
-
-Manual
-======
-
-Since version 0.4.0 the 'libmpq' package comes with a manpage for
-every library function. If you use 'libmpq' first time it is a good
-idea to read the `FAQ' file.
-
-Reporting Bugs
-==============
-
-Bug reports for 'libmpq' can be send to me directly.
-
- * Maik Broemme <mbroemme@plusserver.de>
-
-Enjoy!
-
-Maik Broemme <mbroemme@plusserver.de>
-http://www.babelize.org/
diff --git a/dep/libmpq/THANKS b/dep/libmpq/THANKS
deleted file mode 100644
index 42da1235476..00000000000
--- a/dep/libmpq/THANKS
+++ /dev/null
@@ -1,21 +0,0 @@
-'libmpq' was originaly created by Maik Broemme <mbroemme@plusserver.de>
-and i want to thank some people which helped by supplying knowledge, code or
-something else.
-
- * Romy Trompke <rtnet@web.de>
- - my lovely girlfriend for her patience
-
- * Ladislav Zezula <ladik@zezula.net>
- - stormlib creator
-
- * Marko Friedemann <marko.friedemann@bmx-chemnitz.de>
- - initial port of stormlib to linux
-
- * Tom Amigo <tomamigo@apexmail.com>
- - first people who decrypts the MoPaQ archive format
-
- * ShadowFlare <BlakFlare@hiotmail.com>
- - creator of the ShadowFlare MPQ API
-
- * Justin Olbrantz (Quantam) <omega@dragonfire.net>
- - creator of the client using ShadowFlare MPQ API
diff --git a/dep/libmpq/TODO b/dep/libmpq/TODO
deleted file mode 100644
index 0c1951f0b46..00000000000
--- a/dep/libmpq/TODO
+++ /dev/null
@@ -1,10 +0,0 @@
-Features and functionality which should be added in the future.
-
- * Porting for big endian systems.
- * Porting for Windows? :)
- * Creating mpq archives.
- * Brute all unknown filenames, Blizzard uses in their
- archives.
-
-Look at the AUTHORS file if you want help me with 'libmpq', or
-if you have other interesting features which should be added.
diff --git a/dep/libmpq/autogen.sh b/dep/libmpq/autogen.sh
deleted file mode 100644
index 16871edd70d..00000000000
--- a/dep/libmpq/autogen.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-#
-echo "Generating build information using aclocal, autoheader, automake and autoconf"
-echo "This may take a while ..."
-
-# Touch the timestamps on all the files since CVS messes them up
-directory=`dirname $0`
-touch $directory/configure.ac
-
-# Regenerate configuration files
-libtoolize --copy
-aclocal
-autoheader
-automake --foreign --add-missing --copy
-autoconf
-
-# Run configure for this platform
-#./configure $*
-echo "Now you are ready to run ./configure"
diff --git a/dep/libmpq/bindings/Makefile.am b/dep/libmpq/bindings/Makefile.am
deleted file mode 100644
index b9fefe306ef..00000000000
--- a/dep/libmpq/bindings/Makefile.am
+++ /dev/null
@@ -1,6 +0,0 @@
-# any directories which should be built and installed.
-SUBDIRS = d
-
-if HAVE_PYTHON
-SUBDIRS += python
-endif
diff --git a/dep/libmpq/bindings/d/Makefile.am b/dep/libmpq/bindings/d/Makefile.am
deleted file mode 100644
index 4de7285ae51..00000000000
--- a/dep/libmpq/bindings/d/Makefile.am
+++ /dev/null
@@ -1,6 +0,0 @@
-# minimum required automake 1.6
-AUTOMAKE_OPTIONS = 1.6
-
-# install D binding to /usr/include/d by default
-libmpq_includedir = $(includedir)/d
-libmpq_include_HEADERS = mpq.d
diff --git a/dep/libmpq/bindings/d/dsss.conf b/dep/libmpq/bindings/d/dsss.conf
deleted file mode 100644
index 252482c4933..00000000000
--- a/dep/libmpq/bindings/d/dsss.conf
+++ /dev/null
@@ -1,2 +0,0 @@
-[mpq.d]
-type=sourcelibrary
diff --git a/dep/libmpq/bindings/d/mpq.d b/dep/libmpq/bindings/d/mpq.d
deleted file mode 100644
index d72c2d2a986..00000000000
--- a/dep/libmpq/bindings/d/mpq.d
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * mpq.d -- D programming language module for libmpq
- *
- * Copyright (c) 2008 Georg Lukas <georg@op-co.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * This module is written to support Phobos. Patches to allow binding to
- * Tango are welcome.
- */
-
-module mpq;
-
-/* the following pragma does not work on DMD/Linux, generates a warning on
- * GDC/Linux and has not been tested on Windows. Commented out for now. */
-// pragma(lib, "libmpq");
-
-import std.string; // for format() and toStringz()
-import std.traits; // for ParameterTypeTuple!()
-
-/* XXX: this assumes that libmpq is compiled with Large File Support on */
-alias long off_t;
-
-/* libmpq error return values */
-const LIBMPQ_ERROR_OPEN = -1; /* open error on file. */
-const LIBMPQ_ERROR_CLOSE = -2; /* close error on file. */
-const LIBMPQ_ERROR_SEEK = -3; /* lseek error on file. */
-const LIBMPQ_ERROR_READ = -4; /* read error on file. */
-const LIBMPQ_ERROR_WRITE = -5; /* write error on file. */
-const LIBMPQ_ERROR_MALLOC = -6; /* memory allocation error. */
-const LIBMPQ_ERROR_FORMAT = -7; /* format errror. */
-const LIBMPQ_ERROR_NOT_INITIALIZED = -8; /* init() wasn't called. */
-const LIBMPQ_ERROR_SIZE = -9; /* buffer size is to small. */
-const LIBMPQ_ERROR_EXIST = -10; /* file or block does not exist in archive. */
-const LIBMPQ_ERROR_DECRYPT = -11; /* we don't know the decryption seed. */
-const LIBMPQ_ERROR_UNPACK = -12; /* error on unpacking file. */
-
-/** libmpq internal meta-data for an archive */
-extern struct mpq_archive_s;
-
-extern(C) {
-
-/* libmpq__generic information about library. */
-char *libmpq__version();
-
-/* libmpq__generic mpq archive information. */
-int libmpq__archive_open(mpq_archive_s **mpq_archive, char *mpq_filename, off_t archive_offset);
-int libmpq__archive_close(mpq_archive_s *mpq_archive);
-int libmpq__archive_packed_size(mpq_archive_s *mpq_archive, off_t *packed_size);
-int libmpq__archive_unpacked_size(mpq_archive_s *mpq_archive, off_t *unpacked_size);
-int libmpq__archive_offset(mpq_archive_s *mpq_archive, off_t *offset);
-int libmpq__archive_version(mpq_archive_s *mpq_archive, uint *version_);
-int libmpq__archive_files(mpq_archive_s *mpq_archive, uint *files);
-
-/* libmpq__generic file processing functions. */
-int libmpq__file_packed_size(mpq_archive_s *mpq_archive, uint file_number, off_t *packed_size);
-int libmpq__file_unpacked_size(mpq_archive_s *mpq_archive, uint file_number, off_t *unpacked_size);
-int libmpq__file_offset(mpq_archive_s *mpq_archive, uint file_number, off_t *offset);
-int libmpq__file_blocks(mpq_archive_s *mpq_archive, uint file_number, uint *blocks);
-int libmpq__file_encrypted(mpq_archive_s *mpq_archive, uint file_number, uint *encrypted);
-int libmpq__file_compressed(mpq_archive_s *mpq_archive, uint file_number, uint *compressed);
-int libmpq__file_imploded(mpq_archive_s *mpq_archive, uint file_number, uint *imploded);
-int libmpq__file_number(mpq_archive_s *mpq_archive, char *filename, uint *number);
-int libmpq__file_read(mpq_archive_s *mpq_archive, uint file_number, ubyte *out_buf, off_t out_size, off_t *transferred);
-
-/* libmpq__generic block processing functions. */
-int libmpq__block_open_offset(mpq_archive_s *mpq_archive, uint file_number);
-int libmpq__block_close_offset(mpq_archive_s *mpq_archive, uint file_number);
-int libmpq__block_unpacked_size(mpq_archive_s *mpq_archive, uint file_number, uint block_number, off_t *unpacked_size);
-int libmpq__block_read(mpq_archive_s *mpq_archive, uint file_number, uint block_number, ubyte *out_buf, off_t out_size, off_t *transferred);
-
-}
-
-
-/** exception class for failed libmpq calls */
-class MPQException : Exception {
- const string[] Errors = [
- "unknown error",
- "open error on file",
- "close error on file",
- "lseek error on file",
- "read error on file",
- "write error on file",
- "memory allocation error",
- "format errror",
- "init() wasn't called",
- "buffer size is to small",
- "file or block does not exist in archive",
- "we don't know the decryption seed",
- "error on unpacking file"];
-
- public int errno;
- this(char[] fnname = "unknown_function", int errno = 0) {
-
- this.errno = errno;
- if (-errno >= Errors.length)
- errno = 0;
- super(std.string.format("Error in %s(): %s (%d)",
- fnname, Errors[-errno], errno));
- }
-}
-
-
-/** template to wrap function calls and throw exceptions in case of error
- *
- * thanks for the idea to while(nan) blog,
- * http://while-nan.blogspot.com/2007/06/wrapping-functions-for-fun-and-profit.html
- *
- * use: MPQ_CHECKERR(libmpq__archive_open)(&m, "foo.mpq", -1);
- * returns the retval of archive_open on success;
- * throws an MPQException on failure.
- *
- * @param Fn libmpq__function reference
- * @param args libmpq__function parameters
- * @return return value of libmpq__function on success
- * @throw MPQException on error
- */
-int MPQ_CHECKERR(alias Fn)(ParameterTypeTuple!(Fn) args)
-{
- int result = Fn(args);
- if (result < 0) {
- /* XXX: relying on non-specified stringof() behaviour */
- throw new MPQException((&Fn).stringof[2..$], result);
- }
- return result;
-}
-
-
-/** mixin alias to wrap library functions into MPQ_CHECKERR.
- *
- * alias mpq.func_name(...) to MPQ_CHECKERR(libmpq__func_name)(...)
- * @param func_name name of the function to be wrapped
- */
-template MPQ_FUNC(char[] func_name) {
- const char[] MPQ_FUNC = "alias MPQ_CHECKERR!(libmpq__" ~ func_name ~ ") " ~ func_name ~ ";";
-}
-
-alias libmpq__version libversion; /* must be direct alias because it returns char*, not error int */
-mixin(MPQ_FUNC!("archive_open"));
-mixin(MPQ_FUNC!("archive_close"));
-mixin(MPQ_FUNC!("archive_packed_size"));
-mixin(MPQ_FUNC!("archive_unpacked_size"));
-mixin(MPQ_FUNC!("archive_offset"));
-mixin(MPQ_FUNC!("archive_version"));
-mixin(MPQ_FUNC!("archive_files"));
-mixin(MPQ_FUNC!("file_packed_size"));
-mixin(MPQ_FUNC!("file_unpacked_size"));
-mixin(MPQ_FUNC!("file_offset"));
-mixin(MPQ_FUNC!("file_blocks"));
-mixin(MPQ_FUNC!("file_encrypted"));
-mixin(MPQ_FUNC!("file_compressed"));
-mixin(MPQ_FUNC!("file_imploded"));
-mixin(MPQ_FUNC!("file_number"));
-mixin(MPQ_FUNC!("file_read"));
-mixin(MPQ_FUNC!("block_open_offset"));
-mixin(MPQ_FUNC!("block_close_offset"));
-mixin(MPQ_FUNC!("block_unpacked_size"));
-mixin(MPQ_FUNC!("block_read"));
-
-/** getter function named name for returning archive_* single values:
- *
- * <type> Archive.<name>() { return libmpq__archive_<name>() }
- *
- * @param type return type for the original function reference
- * @param name name of the original function
- * @param name2 name for the prototype (defaults to name, used for "version")
- * @return getter function mixin
- */
-template MPQ_A_GET(char[] type, char[] name, char[] name2 = name) {
- const char[] MPQ_A_GET = type ~ " " ~ name2 ~ "() { " ~
- type ~ " ret; " ~
- "archive_" ~ name ~ "(m, &ret); return ret;" ~
- "}";
-}
-
-/** wrapper class for an MPQ Archive
- *
- * syntax: auto a = new mpq.Archive("somefile.mpq");
- */
-class Archive {
- mpq_archive_s *m;
- File listfile;
- char[][] listfiledata;
-
- this(char[] archivename, off_t offset = -1) {
- archive_open(&m, toStringz(archivename), offset);
- }
-
- mixin(MPQ_A_GET!("off_t", "packed_size"));
- mixin(MPQ_A_GET!("off_t", "unpacked_size"));
- mixin(MPQ_A_GET!("off_t", "offset"));
- mixin(MPQ_A_GET!("uint", "version", "version_"));
- mixin(MPQ_A_GET!("uint", "files"));
-
- ~this() {
- archive_close(m);
- }
-
- mpq_archive_s* archive() {
- return m;
- }
-
- File opIndex(char[] fname) {
- return new File(this, fname);
- }
- File opIndex(int fno) {
- return new File(this, fno);
- }
-
- char[][] filelist() {
- try {
- if (!listfile) {
- listfile = this["(listfile)"];
- listfiledata = (cast(char[])listfile.read()).splitlines();
- }
- return listfiledata;
- } catch (MPQException e) {
- return [];
- }
- }
-
- /+uint filenumber(char[] filename) {
- try {
- if (!listfile) {
- listfile = this["(listfile)"];
- listfiledata = (cast(char[])listfile.read()).splitlines();
- }
- return listfiledata;
- } catch (MPQException e) {
- return [];
- }
- }+/
-
-}
-
-
-/** getter function named name for returning file_* single values:
- *
- * <type> File.<name>() { return libmpq__file_<name>() }
- *
- * @param type return type for the original function reference
- * @param name name of the original function
- * @param name2 name for the prototype (defaults to name, used for "version")
- * @return getter function mixin
- */
-template MPQ_F_GET(char[] type, char[] name, char[] name2 = name) {
- const char[] MPQ_F_GET = type ~ " " ~ name2 ~ "() { " ~
- type ~ " ret; " ~
- "file_" ~ name ~ "(am, fileno, &ret); " ~
- "return ret;" ~
- "}";
-}
-
-/** wrapper class for a single file in an MPQ Archive
- *
- * syntax:
- * auto a = new mpq.Archive("somefile.mpq");
- * auto f = a["(listfile)"];
- * auto f2 = a[0];
- * auto f3 = new File(a, "(listfile)");
- */
-class File {
- Archive a;
- mpq_archive_s* am;
- char[] filename;
- uint fileno;
-
- this(Archive a, int fileno) {
- this.a = a;
- this.am = a.archive();
- if (fileno >= a.files) {
- throw new MPQException(format("File(%d)", fileno),
- LIBMPQ_ERROR_EXIST);
- }
- this.filename = format("file%04d.xxx", fileno);
- this.fileno = fileno;
- }
-
- this(Archive a, char[] filename) {
- this.a = a;
- this.am = a.archive();
- this.filename = filename;
- /* this line will throw an exception when the file is not there */
- mpq.file_number(am, toStringz(filename), &this.fileno);
- }
-
- mixin(MPQ_F_GET!("off_t", "packed_size"));
- mixin(MPQ_F_GET!("off_t", "unpacked_size"));
- mixin(MPQ_F_GET!("off_t", "offset"));
- mixin(MPQ_F_GET!("uint", "blocks"));
- mixin(MPQ_F_GET!("uint", "encrypted"));
- mixin(MPQ_F_GET!("uint", "compressed"));
- mixin(MPQ_F_GET!("uint", "imploded"));
-
- uint no() { return fileno; }
- char[] name() { return filename; }
-
- ubyte[] read() {
- ubyte[] content;
- content.length = this.unpacked_size();
- off_t trans;
- mpq.file_read(am, fileno, content.ptr, content.length, &trans);
- content.length = trans;
- return content;
- }
-}
diff --git a/dep/libmpq/bindings/python/Makefile.am b/dep/libmpq/bindings/python/Makefile.am
deleted file mode 100644
index 6971a9b2f6d..00000000000
--- a/dep/libmpq/bindings/python/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-# minimum required automake 1.6
-AUTOMAKE_OPTIONS = 1.6
-
-# library information and headers which should not be installed.
-python_PYTHON = mpq.py
diff --git a/dep/libmpq/bindings/python/mpq-info b/dep/libmpq/bindings/python/mpq-info
deleted file mode 100644
index 2c67aa1d0cc..00000000000
--- a/dep/libmpq/bindings/python/mpq-info
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import division
-
-import sys
-
-import mpq
-
-archive = mpq.Archive(sys.argv[1])
-
-print "Name: %s" % sys.argv[1]
-print "Version: %s" % archive.filename
-print "Offset: %s" % archive.offset
-print "Packed size: %s" % archive.packed_size
-print "Unpacked size: %s" % archive.unpacked_size
-print "Compression ratio: %s" % (archive.packed_size/archive.unpacked_size)
diff --git a/dep/libmpq/bindings/python/mpq.py b/dep/libmpq/bindings/python/mpq.py
deleted file mode 100644
index cf6ecaae800..00000000000
--- a/dep/libmpq/bindings/python/mpq.py
+++ /dev/null
@@ -1,322 +0,0 @@
-"""wrapper for libmpq"""
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-import ctypes
-import ctypes.util
-import os
-
-libmpq = ctypes.CDLL(ctypes.util.find_library("mpq"))
-
-class Error(Exception):
- pass
-
-errors = {
- -1: (IOError, "open"),
- -2: (IOError, "close"),
- -3: (IOError, "seek"),
- -4: (IOError, "read"),
- -5: (IOError, "write"),
- -6: (MemoryError,),
- -7: (Error, "file is not an mpq or is corrupted"),
- -8: (AssertionError, "not initialized"),
- -9: (AssertionError, "buffer size too small"),
- -10: (IndexError, "file not in archive"),
- -11: (AssertionError, "decrypt"),
- -12: (AssertionError, "unpack"),
-}
-
-def check_error(result, func, arguments, errors=errors):
- try:
- error = errors[result]
- except KeyError:
- return result
- else:
- raise error[0](*error[1:])
-
-libmpq.libmpq__version.restype = ctypes.c_char_p
-
-libmpq.libmpq__archive_open.errcheck = check_error
-libmpq.libmpq__archive_close.errcheck = check_error
-libmpq.libmpq__archive_packed_size.errcheck = check_error
-libmpq.libmpq__archive_unpacked_size.errcheck = check_error
-libmpq.libmpq__archive_offset.errcheck = check_error
-libmpq.libmpq__archive_version.errcheck = check_error
-libmpq.libmpq__archive_files.errcheck = check_error
-
-libmpq.libmpq__file_packed_size.errcheck = check_error
-libmpq.libmpq__file_unpacked_size.errcheck = check_error
-libmpq.libmpq__file_offset.errcheck = check_error
-libmpq.libmpq__file_blocks.errcheck = check_error
-libmpq.libmpq__file_encrypted.errcheck = check_error
-libmpq.libmpq__file_compressed.errcheck = check_error
-libmpq.libmpq__file_imploded.errcheck = check_error
-libmpq.libmpq__file_number.errcheck = check_error
-libmpq.libmpq__file_read.errcheck = check_error
-
-libmpq.libmpq__block_open_offset.errcheck = check_error
-libmpq.libmpq__block_close_offset.errcheck = check_error
-libmpq.libmpq__block_unpacked_size.errcheck = check_error
-libmpq.libmpq__block_read.errcheck = check_error
-
-__version__ = libmpq.libmpq__version()
-
-
-class Reader(object):
- def __init__(self, file, libmpq=libmpq):
- self._file = file
- self._pos = 0
- self._buf = []
- self._cur_block = 0
- libmpq.libmpq__block_open_offset(self._file._archive._mpq,
- self._file.number)
-
- def __iter__(self):
- return self
-
- def __repr__(self):
- return "iter(%r)" % self._file
-
- def seek(self, offset, whence=os.SEEK_SET, os=os):
- if whence == os.SEEK_SET:
- pass
- elif whence == os.SEEK_CUR:
- offset += self._pos
- elif whence == os.SEEK_END:
- offset += self._file.unpacked_size
- else:
- raise ValueError, "invalid whence"
-
- if offset >= self._pos:
- self.read(offset - self._pos)
- else:
- self._pos = 0
- self._buf = []
- self._cur_block = 0
- self.read(offset)
-
- def tell(self):
- return self._pos
-
- def _read_block(self, ctypes=ctypes, libmpq=libmpq):
- block_size = ctypes.c_uint64()
- libmpq.libmpq__block_unpacked_size(self._file._archive._mpq,
- self._file.number, self._cur_block, ctypes.byref(block_size))
- block_data = ctypes.create_string_buffer(block_size.value)
- libmpq.libmpq__block_read(self._file._archive._mpq,
- self._file.number, self._cur_block,
- block_data, ctypes.c_uint64(len(block_data)), None)
- self._buf.append(block_data.raw)
- self._cur_block += 1
-
- def read(self, size=-1):
- while size < 0 or sum(map(len, self._buf)) < size:
- if self._cur_block == self._file.blocks:
- break
- self._read_block()
- buf = "".join(self._buf)
- if size < 0:
- ret = buf
- self._buf = []
- else:
- ret = buf[:size]
- self._buf = [buf[size:]]
- self._pos += len(ret)
- return ret
-
- def readline(self, os=os):
- line = []
- while True:
- char = self.read(1)
- if char == "":
- break
- if char not in '\r\n' and line and line[-1] in '\r\n':
- self.seek(-1, os.SEEK_CUR)
- break
- line.append(char)
- return ''.join(line)
-
- def next(self):
- line = self.readline()
- if not line:
- raise StopIteration
- return line
-
- def readlines(self, sizehint=-1):
- res = []
- while sizehint < 0 or sum(map(len, res)) < sizehint:
- line = self.readline()
- if not line:
- break
- res.append(line)
- return res
-
- xreadlines = __iter__
-
- def __del__(self, libmpq=libmpq):
- libmpq.libmpq__block_close_offset(self._file._archive._mpq,
- self._file.number)
-
-
-class File(object):
- def __init__(self, archive, number, ctypes=ctypes, libmpq=libmpq):
- self._archive = archive
- self.number = number
-
- for name, atype in [
- ("packed_size", ctypes.c_uint64),
- ("unpacked_size", ctypes.c_uint64),
- ("offset", ctypes.c_uint64),
- ("blocks", ctypes.c_uint32),
- ("encrypted", ctypes.c_uint32),
- ("compressed", ctypes.c_uint32),
- ("imploded", ctypes.c_uint32),
- ]:
- data = atype()
- func = getattr(libmpq, "libmpq__file_"+name)
- func(self._archive._mpq, self.number, ctypes.byref(data))
- setattr(self, name, data.value)
-
- def __str__(self, ctypes=ctypes, libmpq=libmpq):
- data = ctypes.create_string_buffer(self.unpacked_size)
- libmpq.libmpq__file_read(self._archive._mpq, self.number,
- data, ctypes.c_uint64(len(data)), None)
- return data.raw
-
- def __repr__(self):
- return "%r[%i]" % (self._archive, self.number)
-
- def __iter__(self, Reader=Reader):
- return Reader(self)
-
-
-class Archive(object):
- def __init__(self, source, ctypes=ctypes, File=File, libmpq=libmpq):
- self._source = source
- if isinstance(source, File):
- assert not source.encrypted
- assert not source.compressed
- assert not source.imploded
- self.filename = source._archive.filename
- offset = source._archive.offset + source.offset
- else:
- self.filename = source
- offset = -1
-
- self._mpq = ctypes.c_void_p()
- libmpq.libmpq__archive_open(ctypes.byref(self._mpq), self.filename,
- ctypes.c_uint64(offset))
- self._opened = True
-
- for field_name, field_type in [
- ("packed_size", ctypes.c_uint64),
- ("unpacked_size", ctypes.c_uint64),
- ("offset", ctypes.c_uint64),
- ("version", ctypes.c_uint32),
- ("files", ctypes.c_uint32),
- ]:
- func = getattr(libmpq, "libmpq__archive_" + field_name)
- data = field_type()
- func(self._mpq, ctypes.byref(data))
- setattr(self, field_name, data.value)
-
- def __del__(self, libmpq=libmpq):
- if getattr(self, "_opened", False):
- libmpq.libmpq__archive_close(self._mpq)
-
- def __len__(self):
- return self.files
-
- def __contains__(self, item, ctypes=ctypes, libmpq=libmpq):
- if isinstance(item, str):
- data = ctypes.c_uint32()
- try:
- libmpq.libmpq__file_number(self._mpq, ctypes.c_char_p(item),
- ctypes.byref(data))
- except IndexError:
- return False
- return True
- return 0 <= item < self.files
-
- def __getitem__(self, item, ctypes=ctypes, File=File, libmpq=libmpq):
- if isinstance(item, str):
- data = ctypes.c_int()
- libmpq.libmpq__file_number(self._mpq, ctypes.c_char_p(item),
- ctypes.byref(data))
- item = data.value
- else:
- if not 0 <= item < self.files:
- raise IndexError, "file not in archive"
- return File(self, item)
-
- def __repr__(self):
- return "mpq.Archive(%r)" % self._source
-
-# Remove clutter - everything except Error and Archive.
-del os, check_error, ctypes, errors, File, libmpq, Reader
-
-if __name__ == "__main__":
- import sys, random
- archive = Archive(sys.argv[1])
- print repr(archive)
- for k, v in archive.__dict__.iteritems():
- #if k[0] == '_': continue
- print " " * (4 - 1), k, v
- assert '(listfile)' in archive
- assert 0 in archive
- assert len(archive) == archive.files
- files = [x.strip() for x in archive['(listfile)']]
- files.extend(xrange(archive.files))
- for key in files: #sys.argv[2:] if sys.argv[2:] else xrange(archive.files):
- file = archive[key]
- print
- print " " * (4 - 1), repr(file)
- for k, v in file.__dict__.iteritems():
- #if k[0] == '_': continue
- print " " * (8 - 1), k, v
-
- a = str(file)
-
- b = iter(file).read()
-
- reader = iter(file)
- c = []
- while True:
- l = random.randrange(1, 10)
- d = reader.read(l)
- if not d: break
- assert len(d) <= l
- c.append(d)
- c = "".join(c)
-
- d = []
- reader.seek(0)
- for line in reader:
- d.append(line)
- d = "".join(d)
-
- assert a == b == c == d, map(hash, [a,b,c,d])
- assert len(a) == file.unpacked_size
-
- repr(iter(file))
-
-
- reader.seek(0)
- a = reader.readlines()
-
- reader.seek(0)
- b = list(reader)
-
- assert a == b
diff --git a/dep/libmpq/config.h b/dep/libmpq/config.h
deleted file mode 100644
index c69fb13211b..00000000000
--- a/dep/libmpq/config.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* config.h. Generated from config.h.in by configure. */
-/* config.h.in. Generated from configure.ac by autoheader. */
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#define HAVE_DLFCN_H 1
-
-/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
-#define HAVE_FSEEKO 1
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the `bz2' library (-lbz2). */
-#define HAVE_LIBBZ2 1
-
-/* Define to 1 if you have the `z' library (-lz). */
-#define HAVE_LIBZ 1
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#define HAVE_STDINT_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 1
-
-/* Name of package */
-#define PACKAGE "libmpq"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT "mbroemme@plusserver.de"
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "libmpq"
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "libmpq 0.4.2"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "libmpq"
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "0.4.2"
-
-/* Define to 1 if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Version number of package */
-#define VERSION "0.4.2"
-
-/* Number of bits in a file offset, on hosts where this is settable. */
-#define _FILE_OFFSET_BITS 64
-
-/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
-/* #undef _LARGEFILE_SOURCE */
-
-/* Define for large files, on AIX-style hosts. */
-/* #undef _LARGE_FILES */
diff --git a/dep/libmpq/configure.ac b/dep/libmpq/configure.ac
deleted file mode 100644
index d274eab07c6..00000000000
--- a/dep/libmpq/configure.ac
+++ /dev/null
@@ -1,84 +0,0 @@
-# the autoconf initilization.
-AC_INIT(libmpq, 0.4.2, [mbroemme@plusserver.de], [libmpq])
-
-# detect the canonical host and target build environment.
-AC_CANONICAL_SYSTEM
-
-# initialize autoconf and automake system.
-AM_INIT_AUTOMAKE([no-dependencies])
-AC_CONFIG_HEADERS([config.h:config.h.in])
-
-# notices.
-AC_PREREQ(2.53)
-AC_REVISION($Revision: 1.6 $)
-
-# checking for programs.
-AC_PROG_LIBTOOL
-AC_PROG_MAKE_SET
-AC_PROG_CC
-AC_SYS_LARGEFILE
-AC_FUNC_FSEEKO
-
-# check if we need to export some largefile flags.
-if test "$enable_largefile" != no; then
- if test "$ac_cv_sys_file_offset_bits" != 'no'; then
- if test -z "$LFS_CFLAGS" ; then
- LFS_CFLAGS="-D_FILE_OFFSET_BITS=$ac_cv_sys_file_offset_bits"
- else
- LFS_CFLAGS="$LFS_CFLAGS -D_FILE_OFFSET_BITS=$ac_cv_sys_file_offset_bits"
- fi
- fi
- if test "$ac_cv_sys_large_files" != 'no'; then
- if test -z "$LFS_CFLAGS" ; then
- LFS_CFLAGS="-D_LARGE_FILES=1"
- else
- LFS_CFLAGS="$LFS_CFLAGS -D_LARGE_FILES=1"
- fi
- fi
- if test "$ac_cv_sys_largefile_source" != 'no'; then
- if test -z "$LFS_CFLAGS" ; then
- LFS_CFLAGS="-D_LARGEFILE_SOURCE=1"
- else
- LFS_CFLAGS="$LFS_CFLAGS -D_LARGEFILE_SOURCE=1"
- fi
- fi
-fi
-
-# export largefile flags.
-AC_SUBST(LFS_CFLAGS)
-
-# check for zlib library.
-AC_CHECK_HEADER([zlib.h], [], [AC_MSG_ERROR([*** zlib.h is required, install zlib header files])])
-AC_CHECK_LIB([z], [inflateEnd], [], [AC_MSG_ERROR([*** inflateEnd is required, install zlib library files])])
-
-# check for bzlib2 library.
-AC_CHECK_HEADER([bzlib.h], [], [AC_MSG_ERROR([*** bzlib.h is required, install bzip2 header files])])
-AC_CHECK_LIB([bz2], [BZ2_bzDecompressInit], [], [AC_MSG_ERROR([*** BZ2_bzDecompressInit is required, install bzip2 library files])])
-
-# When we're running gcc 4 or greater, compile with -fvisibility=hidden.
-AC_TRY_COMPILE([
-#if !defined(__GNUC__) || (__GNUC__ < 4)
-#error not gcc4
-#endif
-], [], [CFLAGS="$CFLAGS -fvisibility=hidden"])
-
-# find python for binding
-AM_PATH_PYTHON([2.4],,[:])
-AM_CONDITIONAL([HAVE_PYTHON], [test "$PYTHON" != :])
-
-# configuration files.
-AC_CONFIG_FILES([libmpq.pc])
-AC_CONFIG_FILES([libmpq-config],[chmod +x libmpq-config])
-
-# creating files.
-AC_OUTPUT([
-Makefile
-libmpq/Makefile
-bindings/Makefile
-bindings/d/Makefile
-bindings/python/Makefile
-doc/Makefile
-doc/man1/Makefile
-doc/man3/Makefile
-tools/Makefile
-])
diff --git a/dep/libmpq/debian/changelog b/dep/libmpq/debian/changelog
deleted file mode 100644
index 55d2d918755..00000000000
--- a/dep/libmpq/debian/changelog
+++ /dev/null
@@ -1,35 +0,0 @@
-libmpq (0.4.2-svn288-1) unstable; urgency=low
-
- [ babyface ]
- * Due to the nature of MPQ archives which can have valid block entries
- * removed function libmpq__init() and libmpq__shutdown(), because they
- are no longer required and libmpq__file_name(), because it is up to
- the application to provide listfile support
- * updated documentation to latest API changes
- * removed API documentation for removed function prototypes
- * removed no longer required files from target
-
- [ forrestv ]
- * mpq.py fix
- * spelling - huffmann to huffman
- * changed pkware/pkzip to pkzip and used constants instead of numbers
- in extract.c
- * sanified huffman decoder a bit
- * cleanup + update of mpq.py
- * Added support for library finding on platforms besides Linux.
- * python bindings - sequence methods on Archive, example code
-
- [ georg ]
- * libmpq: file number search now continued over hashtable end
- * debian debug package
-
- -- Georg Lukas <georg@op-co.de> Fri, 22 May 2009 22:38:26 +0200
-
-libmpq (0.4.2-svn270-1) unstable; urgency=low
-
- * First debian package
- * compatible to new libmpq API (post 0.4.2)
- * contains preliminary python-mpq package
-
- -- Georg Lukas <georg@op-co.de> Tue, 07 Oct 2008 14:38:58 +0200
-
diff --git a/dep/libmpq/debian/compat b/dep/libmpq/debian/compat
deleted file mode 100644
index 7f8f011eb73..00000000000
--- a/dep/libmpq/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-7
diff --git a/dep/libmpq/debian/control b/dep/libmpq/debian/control
deleted file mode 100644
index f35bb060015..00000000000
--- a/dep/libmpq/debian/control
+++ /dev/null
@@ -1,50 +0,0 @@
-Source: libmpq
-Priority: extra
-Maintainer: Georg Lukas <georg@op-co.de>
-Build-Depends: debhelper (>= 7), autotools-dev, libbz2-dev
-Standards-Version: 3.7.3
-Section: libs
-Homepage: https://libmpq.org/
-
-Package: libmpq-dev
-Section: libdevel
-Architecture: any
-Depends: libmpq0 (= ${binary:Version})
-Description: Headers for libmpq, a library for MoPaQ mpq archives
- libmpq is a library for extracting and manipulating MoPaQ mpq archives.
- This package provides header files and bindings for applications using
- the libmpq library for the following languages:
- * C
- * Python
- * D
-
-Package: libmpq0
-Section: libs
-Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}
-Description: A library for extracting and manipulating MoPaQ mpq archives
- MPQ, or MoPaQ, is a proprietary archive format created by
- Mike O'Brien, the man hailed as Blizzard's multiplayer engine
- genius, back in 1996 as a general purpose archive for use with
- Diablo, and named narcissistically for its creator
- "Mike O'brien PaCK". The copyrights to it, however, are held by
- Havas Interactive, Blizzard's parent company. The archive format
- is used by many Blizzard titles like Diablo, Diablo 2, Starcraft,
- Warcraft 2: BNE, a newer version in Warcraft 3 and World of
- Warcraft (WoW).
-
-Package: libmpq0-dbg
-Section: libdevel
-Architecture: any
-Depends: libmpq0 (= ${binary:Version})
-Description: Debug symbols for libmpq0 library package
-
-Package: python-mpq
-Architecture: all
-Depends: ${python:Depends}
-XB-Python-Version: ${python:Versions}
-XS-Python-Version: current
-Description: Python bindings for libmpq, a library for MoPaQ mpq archives
- libmpq is a library for extracting and manipulating MoPaQ mpq archives.
- This package provides the python bindings for libmpq.
-
diff --git a/dep/libmpq/debian/copyright b/dep/libmpq/debian/copyright
deleted file mode 100644
index f014cf14de7..00000000000
--- a/dep/libmpq/debian/copyright
+++ /dev/null
@@ -1,23 +0,0 @@
-This package was debianized by Georg Lukas <georg@op-co.de> on
-Fri, 04 Jul 2008 18:17:08 +0200.
-
-It was downloaded from <https://libmpq.org/>
-
-Upstream Author:
-
- Maik Broemme <mbroemme@plusserver.de>
-
-Copyright:
-
- Copyright (C) 2008 Maik Broemme
-
-License:
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
-
-The Debian packaging is (C) 2008, Georg Lukas <georg@op-co.de> and
-is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
diff --git a/dep/libmpq/debian/libmpq-dev.dirs b/dep/libmpq/debian/libmpq-dev.dirs
deleted file mode 100644
index 7b6c7ee6ec1..00000000000
--- a/dep/libmpq/debian/libmpq-dev.dirs
+++ /dev/null
@@ -1,6 +0,0 @@
-usr/bin
-usr/lib
-usr/lib/pkgconfig
-usr/include
-usr/share/man/man1
-usr/share/man/man3
diff --git a/dep/libmpq/debian/libmpq-dev.install b/dep/libmpq/debian/libmpq-dev.install
deleted file mode 100644
index 4e6ab3278e3..00000000000
--- a/dep/libmpq/debian/libmpq-dev.install
+++ /dev/null
@@ -1,6 +0,0 @@
-usr/bin/*
-usr/include/*
-usr/lib/lib*.a
-usr/lib/pkgconfig/*
-usr/lib/*.la
-usr/share/man/man?/*
diff --git a/dep/libmpq/debian/libmpq0.dirs b/dep/libmpq/debian/libmpq0.dirs
deleted file mode 100644
index 68457717bd8..00000000000
--- a/dep/libmpq/debian/libmpq0.dirs
+++ /dev/null
@@ -1 +0,0 @@
-usr/lib
diff --git a/dep/libmpq/debian/libmpq0.docs b/dep/libmpq/debian/libmpq0.docs
deleted file mode 100644
index 5ac7060850c..00000000000
--- a/dep/libmpq/debian/libmpq0.docs
+++ /dev/null
@@ -1,6 +0,0 @@
-FAQ
-NEWS
-README
-TODO
-THANKS
-AUTHORS
diff --git a/dep/libmpq/debian/libmpq0.install b/dep/libmpq/debian/libmpq0.install
deleted file mode 100644
index 8aa4466a68e..00000000000
--- a/dep/libmpq/debian/libmpq0.install
+++ /dev/null
@@ -1 +0,0 @@
-usr/lib/lib*.so*
diff --git a/dep/libmpq/debian/python-mpq.install b/dep/libmpq/debian/python-mpq.install
deleted file mode 100644
index a7aba2013b0..00000000000
--- a/dep/libmpq/debian/python-mpq.install
+++ /dev/null
@@ -1 +0,0 @@
-usr/lib/python?.?
diff --git a/dep/libmpq/debian/rules b/dep/libmpq/debian/rules
deleted file mode 100644
index 1e101be5faf..00000000000
--- a/dep/libmpq/debian/rules
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/usr/bin/make -f
-# -*- makefile -*-
-# Sample debian/rules that uses debhelper.
-# This file was originally written by Joey Hess and Craig Small.
-# As a special exception, when this file is copied by dh-make into a
-# dh-make output file, you may use that output file without restriction.
-# This special exception was added by Craig Small in version 0.37 of dh-make.
-
-# Uncomment this to turn on verbose mode.
-export DH_VERBOSE=1
-
-
-# These are used for cross-compiling and for saving the configure script
-# from having to guess our platform (since we know it already)
-DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
-DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
-ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE))
-CROSS= --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE)
-else
-CROSS= --build $(DEB_BUILD_GNU_TYPE)
-endif
-
-
-
-
-# shared library versions, option 1
-version=2.0.5
-major=2
-# option 2, assuming the library is created as src/.libs/libfoo.so.2.0.5 or so
-#version=`ls src/.libs/lib*.so.* | \
-# awk '{if (match($$0,/[0-9]+\.[0-9]+\.[0-9]+$$/)) print substr($$0,RSTART)}'`
-#major=`ls src/.libs/lib*.so.* | \
-# awk '{if (match($$0,/\.so\.[0-9]+$$/)) print substr($$0,RSTART+4)}'`
-
-config.status: configure
- dh_testdir
- # Add here commands to configure the package.
-ifneq "$(wildcard /usr/share/misc/config.sub)" ""
- cp -f /usr/share/misc/config.sub config.sub
-endif
-ifneq "$(wildcard /usr/share/misc/config.guess)" ""
- cp -f /usr/share/misc/config.guess config.guess
-endif
- ./configure $(CROSS) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info CFLAGS="$(CFLAGS) -ggdb" LDFLAGS="-Wl,-z,defs"
-
-
-build: build-stamp
-build-stamp: config.status
- dh_testdir
-
- # Add here commands to compile the package.
- $(MAKE)
-
- touch $@
-
-clean:
- dh_testdir
- dh_testroot
- rm -f build-stamp
-
- # Add here commands to clean up after the build process.
- [ ! -f Makefile ] || $(MAKE) distclean
- rm -f config.sub config.guess
-
- dh_clean
-
-install: build
- dh_testdir
- dh_testroot
- dh_clean -k
- dh_installdirs
-
- # Add here commands to install the package into debian/tmp
- $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install
-
-
-# Build architecture-independent files here.
-binary-indep: build install
- dh_pysupport usr/lib/python?.?/site-packages
-
-# Build architecture-dependent files here.
-binary-arch: build install
- dh_testdir
- dh_testroot
- dh_installchangelogs
- dh_installdocs
- dh_installexamples
- dh_install
-# dh_installmenu
-# dh_installdebconf
-# dh_installlogrotate
-# dh_installemacsen
-# dh_installpam
-# dh_installmime
-# dh_installinit
-# dh_installcron
-# dh_installinfo
- dh_installman
- dh_link
- dh_strip --dbg-package=libmpq0-dbg
- dh_compress
- dh_fixperms
-# dh_perl
- dh_makeshlibs
- dh_installdeb
- dh_shlibdeps
- dh_gencontrol
- dh_md5sums
- dh_builddeb
-
-binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary install
diff --git a/dep/libmpq/doc/Makefile.am b/dep/libmpq/doc/Makefile.am
deleted file mode 100644
index e7ccd5f4518..00000000000
--- a/dep/libmpq/doc/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-# minimum required automake 1.6
-AUTOMAKE_OPTIONS = 1.6
-
-# any directories which should be built and installed.
-SUBDIRS = man1 man3
diff --git a/dep/libmpq/doc/man1/Makefile.am b/dep/libmpq/doc/man1/Makefile.am
deleted file mode 100644
index 055f1aab533..00000000000
--- a/dep/libmpq/doc/man1/Makefile.am
+++ /dev/null
@@ -1,9 +0,0 @@
-# minimum required automake 1.6
-AUTOMAKE_OPTIONS = 1.6
-
-# manual page directory.
-EXTRA_DIST = $(man_MANS)
-
-# manual pages for the installed binaries.
-man_MANS = \
- libmpq-config.1
diff --git a/dep/libmpq/doc/man1/libmpq-config.1 b/dep/libmpq/doc/man1/libmpq-config.1
deleted file mode 100644
index c025f5ce4f4..00000000000
--- a/dep/libmpq/doc/man1/libmpq-config.1
+++ /dev/null
@@ -1,69 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 1 2008-02-10 "The MoPaQ archive library"
-.SH NAME
-libmpq-config \- script to get information about the installed version of libmpq.
-.SH SYNOPSIS
-.B libmpq-config
-[\-\-prefix\fI[=DIR]\fP] [\-\-exec\-prefix\fI[=DIR]\fP] [\-\-version]
-.br
-[\-\-cflags] [\-\-libs] [\-\-static\-libs]
-.SH DESCRIPTION
-.PP
-\fIlibmpq-config\fP is a tool that is used to determine the compiler and linker flags that should be used to compile and link programs that use \fIlibmpq\fP. Finally, it's also used internally by the .m4 macros for GNU autoconf that are included with \fIlibmpq\fP.
-.SH OPTIONS
-\fIlibmpq-config\fP accepts the following options:
-.TP 8
-.B \-\-version
-.ti 15
-Print the currently installed version of \fIlibmpq\fP on the standard output.
-.TP 8
-.B \-\-libs
-.ti 15
-Print the linker flags that are necessary to link \fIlibmpq\fP to a program.
-.TP 8
-.B \-\-static\-libs
-.ti 15
-Print the linker flags that are necessary to statically link \fIlibmpq\fP to a program.
-.TP 8
-.B \-\-cflags
-.ti 15
-Print the compiler flags that are necessary to compile a program that use \fIlibmpq\fP.
-.TP 8
-.B \-\-prefix=PREFIX
-.ti 15
-If specified, use PREFIX instead of the installation prefix that \fIlibmpq\fP was built with when computing the output for the \-\-cflags and \-\-libs options. This option is also used for the exec prefix if \-\-exec\-prefix was not specified. This option must be specified before any \-\-libs or \-\-cflags options.
-.TP 8
-.B \-\-exec\-prefix=PREFIX
-.ti 15
-If specified, use PREFIX instead of the installation exec prefix that \fIlibmpq\fP was built with when computing the output for the \-\-cflags and \-\-libs options. This option must be specified before any \-\-libs or \-\-cflags options.
-.SH NOTE
-Instead of using this configuration script you should better use the pkg-config version because this would be more platform independent and makes the usage within GNU autoconf much easier.
-.SH SEE ALSO
-\fBlibmpq\fR(3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/Makefile.am b/dep/libmpq/doc/man3/Makefile.am
deleted file mode 100644
index cad3d865dc1..00000000000
--- a/dep/libmpq/doc/man3/Makefile.am
+++ /dev/null
@@ -1,31 +0,0 @@
-# minimum required automake 1.6
-AUTOMAKE_OPTIONS = 1.6
-
-# manual page directory.
-EXTRA_DIST = $(man_MANS)
-
-# manual pages for the installed binaries.
-man_MANS = \
- libmpq.3 \
- libmpq__archive_close.3 \
- libmpq__archive_files.3 \
- libmpq__archive_offset.3 \
- libmpq__archive_open.3 \
- libmpq__archive_packed_size.3 \
- libmpq__archive_unpacked_size.3 \
- libmpq__archive_version.3 \
- libmpq__block_close_offset.3 \
- libmpq__block_open_offset.3 \
- libmpq__block_read.3 \
- libmpq__block_unpacked_size.3 \
- libmpq__file_blocks.3 \
- libmpq__file_compressed.3 \
- libmpq__file_encrypted.3 \
- libmpq__file_imploded.3 \
- libmpq__file_number.3 \
- libmpq__file_offset.3 \
- libmpq__file_packed_size.3 \
- libmpq__file_read.3 \
- libmpq__file_unpacked_size.3 \
- libmpq__strerror.3 \
- libmpq__version.3
diff --git a/dep/libmpq/doc/man3/libmpq.3 b/dep/libmpq/doc/man3/libmpq.3
deleted file mode 100644
index 768dab0a712..00000000000
--- a/dep/libmpq/doc/man3/libmpq.3
+++ /dev/null
@@ -1,207 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-04-29 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "const char *libmpq__version();"
-.sp
-.BI "const char *libmpq__strerror(int32_t returncode);"
-.sp
-.BI "int32_t libmpq__archive_open("
-.BI " mpq_archive_s **" "mpq_archive",
-.BI " const char *" "mpq_filename",
-.BI " off_t " "archive_offset"
-.BI ");"
-.sp
-.BI "int32_t libmpq__archive_close("
-.BI " mpq_archive_s *" "mpq_archive"
-.BI ");"
-.sp
-.BI "int32_t libmpq__archive_packed_size("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " off_t *" "packed_size"
-.BI ");"
-.sp
-.BI "int32_t libmpq__archive_unpacked_size("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " off_t *" "unpacked_size"
-.BI ");"
-.sp
-.BI "int32_t libmpq__archive_offset("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " off_t *" "offset"
-.BI ");"
-.sp
-.BI "int32_t libmpq__archive_version("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t *" "version"
-.BI ");"
-.sp
-.BI "int32_t libmpq__archive_files("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t *" "files"
-.BI ");"
-.sp
-.BI "int32_t libmpq__file_packed_size("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " off_t *" "packed_size"
-.BI ");"
-.sp
-.BI "int32_t libmpq__file_unpacked_size("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " off_t *" "unpacked_size"
-.BI ");"
-.sp
-.BI "int32_t libmpq__file_offset("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " off_t *" "offset"
-.BI ");"
-.sp
-.BI "int32_t libmpq__file_blocks("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " off_t *" "blocks"
-.BI ");"
-.sp
-.BI "int32_t libmpq__file_encrypted("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " off_t *" "encrypted"
-.BI ");"
-.sp
-.BI "int32_t libmpq__file_compressed("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " off_t *" "compressed"
-.BI ");"
-.sp
-.BI "int32_t libmpq__file_imploded("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " off_t *" "imploded"
-.BI ");"
-.sp
-.BI "int32_t libmpq__file_number("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " const char *" "filename",
-.BI " uint32_t *" "number"
-.BI ");"
-.sp
-.BI "int32_t libmpq__file_read("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " uint8_t *" "out_buf",
-.BI " off_t " "out_size",
-.BI " off_t *" "transferred"
-.BI ");"
-.sp
-.BI "int32_t libmpq__block_open_offset("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number"
-.BI ");"
-.sp
-.BI "int32_t libmpq__block_close_offset("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number"
-.BI ");"
-.sp
-.BI "int32_t libmpq__block_packed_size("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " uint32_t " "block_number",
-.BI " off_t *" "packed_size"
-.BI ");"
-.sp
-.BI "int32_t libmpq__block_unpacked_size("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " uint32_t " "block_number",
-.BI " off_t *" "unpacked_size"
-.BI ");"
-.sp
-.BI "int32_t libmpq__block_offset("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " uint32_t " "block_number",
-.BI " off_t *" "offset"
-.BI ");"
-.sp
-.BI "int32_t libmpq__block_seed("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " uint32_t " "block_number",
-.BI " uint32_t *" "seed"
-.BI ");"
-.sp
-.BI "int32_t libmpq__block_read("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " uint32_t " "block_number",
-.BI " uint8_t *" "out_buf",
-.BI " off_t " "out_size",
-.BI " off_t *" "transferred"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-The \fIlibmpq\fP library supports decrypting, decompressing, exploding and various manipulations of the MoPaQ archive files. It uses \fIzlib(3)\fP and \fIbzip2(1)\fP compression library. At this moment \fIlibmpq\fP is not able to create MoPaQ archives, this limitation will be removed in a future version.
-.SH SEE ALSO
-.BR libmpq__version (3),
-.BR libmpq__strerror (3),
-.BR libmpq__archive_open (3),
-.BR libmpq__archive_close (3),
-.BR libmpq__archive_packed_size (3),
-.BR libmpq__archive_unpacked_size (3),
-.BR libmpq__archive_offset (3),
-.BR libmpq__archive_version (3),
-.BR libmpq__archive_files (3),
-.BR libmpq__file_packed_size (3),
-.BR libmpq__file_unpacked_size (3),
-.BR libmpq__file_offset (3),
-.BR libmpq__file_blocks (3),
-.BR libmpq__file_encrypted (3),
-.BR libmpq__file_compressed (3),
-.BR libmpq__file_imploded (3),
-.BR libmpq__file_number (3),
-.BR libmpq__file_read (3),
-.BR libmpq__block_open_offset (3),
-.BR libmpq__block_close_offset (3),
-.BR libmpq__block_packed_size (3),
-.BR libmpq__block_unpacked_size (3),
-.BR libmpq__block_offset (3),
-.BR libmpq__block_seed (3),
-.BR libmpq__block_read (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__archive_close.3 b/dep/libmpq/doc/man3/libmpq__archive_close.3
deleted file mode 100644
index dfc652a6721..00000000000
--- a/dep/libmpq/doc/man3/libmpq__archive_close.3
+++ /dev/null
@@ -1,57 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-04-29 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__archive_close("
-.BI " mpq_archive_s *" "mpq_archive"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__archive_close\fP() to close a mpq archive which was opened by \fBlibmpq__archive_open\fP(). The function frees the archive structure itself and the contents of it.
-.LP
-The \fBlibmpq__archive_close\fP() function one takes one argument of the archive structure \fImpq_archive\fP which has to be set by \fBlibmpq__archive_open\fP.
-.SH RETURN VALUE
-On success, a zero is returned and on error one of the following constants.
-.TP
-.B LIBMPQ_ERROR_CLOSE
-The given file could not be closed.
-.SH SEE ALSO
-.BR libmpq__archive_open (3),
-.BR libmpq__archive_packed_size (3),
-.BR libmpq__archive_unpacked_size (3),
-.BR libmpq__archive_offset (3),
-.BR libmpq__archive_version (3),
-.BR libmpq__archive_files (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__archive_files.3 b/dep/libmpq/doc/man3/libmpq__archive_files.3
deleted file mode 100644
index 6663b99161a..00000000000
--- a/dep/libmpq/doc/man3/libmpq__archive_files.3
+++ /dev/null
@@ -1,50 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-14 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__archive_files("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t *" "files"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__archive_files\fP() to get the number of files inside the archive. It will count only valid files and skip files which have deleted or freed hash entries.
-.LP
-The \fBlibmpq__archive_files\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument is a reference to the number of \fIfiles\fP in the archive.
-.SH RETURN VALUE
-On success, a zero is returned.
-.SH SEE ALSO
-.BR libmpq__file_blocks (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__archive_offset.3 b/dep/libmpq/doc/man3/libmpq__archive_offset.3
deleted file mode 100644
index 696ac5e809f..00000000000
--- a/dep/libmpq/doc/man3/libmpq__archive_offset.3
+++ /dev/null
@@ -1,51 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-14 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__archive_offset("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " off_t *" "offset"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__archive_offset\fP() to get the offset of the archive, which is the absolute position in the file. It also supports archives within archives.
-.LP
-The \fBlibmpq__archive_offset\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument is a reference to the archive starting position \fIoffset\fP in file.
-.SH RETURN VALUE
-On success, a zero is returned.
-.SH SEE ALSO
-.BR libmpq__file_offset (3),
-.BR libmpq__block_offset (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__archive_open.3 b/dep/libmpq/doc/man3/libmpq__archive_open.3
deleted file mode 100644
index 02c021f8948..00000000000
--- a/dep/libmpq/doc/man3/libmpq__archive_open.3
+++ /dev/null
@@ -1,71 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-04-29 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__archive_open("
-.BI " mpq_archive_s **" "mpq_archive",
-.BI " const char *" "mpq_filename",
-.BI " off_t " "archive_offset"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__archive_open\fP() to open a given mpq archive for later use to extract or manipulate files inside the archive. It will create all required file structures and you have to call \fBlibmpq__archive_close\fP() on success to clean the opened structures. On failure there is no need to call \fBlibmpq__archive_close\fP() because everything will be cleaned up.
-.LP
-The \fBlibmpq__archive_open\fP() function takes as first argument a reference to the archive structure \fImpq_archive\fP and will open the file \fImpq_filename\fP to the structure pointed to by \fImpq_archive\fP. The last argument, \fIarchive_offset\fP is normally -1, but can be specified when the archive offset is known, or not 512-byte aligned.
-.SH RETURN VALUE
-On success, *\fImpq_archive\fP is set to a new \fBmpq_archive_s\fP* and zero is returned, and on error one of the following constants is returned.
-.TP
-.B LIBMPQ_ERROR_OPEN
-The given file could not be opened.
-.TP
-.B LIBMPQ_ERROR_MALLOC
-Not enough memory for creating required structures.
-.TP
-.B LIBMPQ_ERROR_SEEK
-Seeking in file failed.
-.TP
-.B LIBMPQ_ERROR_FORMAT
-The given file is no valid mpq archive.
-.TP
-.B LIBMPQ_ERROR_READ
-Reading in archive failed.
-.SH SEE ALSO
-.BR libmpq__archive_close (3),
-.BR libmpq__archive_packed_size (3),
-.BR libmpq__archive_unpacked_size (3),
-.BR libmpq__archive_offset (3),
-.BR libmpq__archive_version (3),
-.BR libmpq__archive_files (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__archive_packed_size.3 b/dep/libmpq/doc/man3/libmpq__archive_packed_size.3
deleted file mode 100644
index 6c3061f2031..00000000000
--- a/dep/libmpq/doc/man3/libmpq__archive_packed_size.3
+++ /dev/null
@@ -1,51 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-04-29 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__archive_packed_size("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " off_t *" "packed_size"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__archive_packed_size\fP() to get the packed size of all files in the archive. It will count compressed and imploded files as well as stored only.
-.LP
-The \fBlibmpq__archive_packed_size\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument is a reference to the compressed, imploded or stored size \fIpacked_size\fP of file.
-.SH RETURN VALUE
-On success, a zero is returned.
-.SH SEE ALSO
-.BR libmpq__file_packed_size (3),
-.BR libmpq__block_packed_size (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__archive_unpacked_size.3 b/dep/libmpq/doc/man3/libmpq__archive_unpacked_size.3
deleted file mode 100644
index d2ba923c8f0..00000000000
--- a/dep/libmpq/doc/man3/libmpq__archive_unpacked_size.3
+++ /dev/null
@@ -1,51 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-04-29 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__archive_unpacked_size("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " off_t *" "unpacked_size"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__archive_unpacked_size\fP() to get the unpacked size of all files in the archive. It will count uncompressed and exploded files as well as stored only.
-.LP
-The \fBlibmpq__archive_unpacked_size\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument is a reference to the uncompressed, exploded or stored size \fIunpacked_size\fP of file.
-.SH RETURN VALUE
-On success, a zero is returned.
-.SH SEE ALSO
-.BR libmpq__file_unpacked_size (3),
-.BR libmpq__block_unpacked_size (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__archive_version.3 b/dep/libmpq/doc/man3/libmpq__archive_version.3
deleted file mode 100644
index 1764046895a..00000000000
--- a/dep/libmpq/doc/man3/libmpq__archive_version.3
+++ /dev/null
@@ -1,48 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-14 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__archive_version("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t *" "version"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__archive_version\fP() to get the archive version. Currently there exist two known versions, version 1 which supports archives until 2GB total size and version 2 which supports archives above 2GB total size and both are supported.
-.LP
-The \fBlibmpq__archive_version\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument is a reference to the \fIversion\fP of archive.
-.SH RETURN VALUE
-On success, a zero is returned.
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__block_close_offset.3 b/dep/libmpq/doc/man3/libmpq__block_close_offset.3
deleted file mode 100644
index 1ec0c06f70d..00000000000
--- a/dep/libmpq/doc/man3/libmpq__block_close_offset.3
+++ /dev/null
@@ -1,53 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-16 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__block_close_offset("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__block_close_offset\fP() to close the block offset table for the given file. It will close the block offset table regardless of compression (compressed, imploded or stored) type of file.
-.LP
-The \fBlibmpq__block_close_offset\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument \fIfile_number\fP is the number of file to close.
-.SH RETURN VALUE
-On success, a zero is returned and on error one of the following constants.
-.TP
-.B LIBMPQ_ERROR_EXIST
-File or block does not exist in archive.
-.SH SEE ALSO
-.BR libmpq__block_open_offset (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__block_open_offset.3 b/dep/libmpq/doc/man3/libmpq__block_open_offset.3
deleted file mode 100644
index a60b133f406..00000000000
--- a/dep/libmpq/doc/man3/libmpq__block_open_offset.3
+++ /dev/null
@@ -1,65 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-16 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__block_open_offset("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__block_open_offset\fP() to open the block offset table for the given file. It will open the block offset table regardless of compression (compressed, imploded or stored) type of file.
-.LP
-The \fBlibmpq__block_open_offset\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument \fIfile_number\fP is the number of file to open.
-.SH RETURN VALUE
-On success, a zero is returned and on error one of the following constants.
-.TP
-.B LIBMPQ_ERROR_EXIST
-File or block does not exist in archive.
-.TP
-.B LIBMPQ_ERROR_SEEK
-Seeking in file failed.
-.TP
-.B LIBMPQ_ERROR_MALLOC
-Not enough memory for creating required structures.
-.TP
-.B LIBMPQ_ERROR_READ
-Reading in archive failed.
-.TP
-.B LIBMPQ_ERROR_DECRYPT
-Decrypting block failed.
-.SH SEE ALSO
-.BR libmpq__block_close_offset (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__block_read.3 b/dep/libmpq/doc/man3/libmpq__block_read.3
deleted file mode 100644
index 3272c64c7ed..00000000000
--- a/dep/libmpq/doc/man3/libmpq__block_read.3
+++ /dev/null
@@ -1,78 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-16 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__block_read("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " uint32_t " "block_number,
-.BI " uint8_t *" "out_buf",
-.BI " off_t " "out_size",
-.BI " off_t " "transferred"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__block_read\fP() to read a given block into memory. If the block is encrypted it will be first decrypted and then if it is packed (compressed or imploded) it will be unpacked.
-.LP
-The \fBlibmpq__block_read\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument \fIfile_number\fP is the number of file, the third argument \fIblock_number\fP is the number of block. The fourth argument \fIout_buf\fP is the output data buffer which contains the extracted data and the fifth argument \fIout_size\fP is the size of \fIout_buf\fP. The sixth argument is a reference to the \fItransferred\fP bytes of the file.
-.SH RETURN VALUE
-On success, a zero is returned and on error one of the following constants.
-.TP
-.B LIBMPQ_ERROR_EXIST
-Block does not exist in archive.
-.TP
-.B LIBMPQ_ERROR_OPEN
-Block offset table was not opened by calling \fBlibmpq__block_open_offset\fP(), or it was closed by an \fBlibmpq__block_close_offset\fP() call.
-.TP
-.B LIBMPQ_ERROR_SIZE
-The output buffer is to small.
-.TP
-.B LIBMPQ_ERROR_SEEK
-Seeking in file failed.
-.TP
-.B LIBMPQ_ERROR_MALLOC
-Not enough memory for creating required structures.
-.TP
-.B LIBMPQ_ERROR_READ
-Reading in archive failed.
-.TP
-.B LIBMPQ_ERROR_DECRYPT
-Decrypting block failed.
-.TP
-.B LIBMPQ_ERROR_UNPACK
-Unpacking block failed.
-.SH SEE ALSO
-.BR libmpq__file_read (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__block_unpacked_size.3 b/dep/libmpq/doc/man3/libmpq__block_unpacked_size.3
deleted file mode 100644
index a21ca48159a..00000000000
--- a/dep/libmpq/doc/man3/libmpq__block_unpacked_size.3
+++ /dev/null
@@ -1,59 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-16 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__block_unpacked_size("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " uint32_t " "block_number",
-.BI " off_t *" "unpacked_size"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__block_unpacked_size\fP() to get the unpacked size of a given block in the file. It will return a valid size for compressed and imploded blocks as well as stored only.
-.LP
-The \fBlibmpq__block_unpacked_size\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument \fIfile_number\fP is the number of file, the third argument \fIblock_number\fP is the number of block and the fourth argument is a reference to the uncompressed, exploded or stored size \fIunpacked_size\fP of block.
-.SH RETURN VALUE
-On success, a zero is returned and on error one of the following constants.
-.TP
-.B LIBMPQ_ERROR_EXIST
-File or block does not exist in archive.
-.TP
-.B LIBMPQ_ERROR_OPEN
-Block offset table was not opened by calling \fBlibmpq__block_open_offset\fP(), or it was closed by an \fBlibmpq__block_close_offset\fP() call.
-.SH SEE ALSO
-.BR libmpq__archive_unpacked_size (3),
-.BR libmpq__file_unpacked_size (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__file_blocks.3 b/dep/libmpq/doc/man3/libmpq__file_blocks.3
deleted file mode 100644
index 85baeffc603..00000000000
--- a/dep/libmpq/doc/man3/libmpq__file_blocks.3
+++ /dev/null
@@ -1,54 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-16 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__file_blocks("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " uint32_t *" "blocks"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__file_blocks\fP() to get the number of blocks for a given file. It will count all blocks for files stored in multiple sectors or count one for files stored in single sector.
-.LP
-The \fBlibmpq__file_blocks\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument \fIfile_number\fP is the number of file and the third argument is a reference to the number of \fIblocks\fP of the file.
-.SH RETURN VALUE
-On success, a zero is returned and on error one of the following constants.
-.TP
-.B LIBMPQ_ERROR_EXIST
-File does not exist in archive.
-.SH SEE ALSO
-.BR libmpq__archive_files (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__file_compressed.3 b/dep/libmpq/doc/man3/libmpq__file_compressed.3
deleted file mode 100644
index 24b44f0b666..00000000000
--- a/dep/libmpq/doc/man3/libmpq__file_compressed.3
+++ /dev/null
@@ -1,54 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-16 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__file_compressed("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " uint32_t *" "compressed"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__file_compressed\fP() to get the compression status of the given file. It will return true for compressed files and false otherwise.
-.LP
-The \fBlibmpq__file_compressed\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument \fIfile_number\fP is the number of file and the third argument is a reference to the compression status \fIcompressed\fP of the file.
-.SH RETURN VALUE
-On success, a zero is returned and on error one of the following constants.
-.TP
-.B LIBMPQ_ERROR_EXIST
-File does not exist in archive.
-.SH SEE ALSO
-.BR libmpq__archive_files (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__file_encrypted.3 b/dep/libmpq/doc/man3/libmpq__file_encrypted.3
deleted file mode 100644
index 798f4019c7a..00000000000
--- a/dep/libmpq/doc/man3/libmpq__file_encrypted.3
+++ /dev/null
@@ -1,54 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-16 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__file_encrypted("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " uint32_t *" "encrypted"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__file_encrypted\fP() to get the encryption status of the given file. It will return true for encrypted files and false otherwise.
-.LP
-The \fBlibmpq__file_encrypted\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument \fIfile_number\fP is the number of file and the third argument is a reference to the encryption status \fIencrypted\fP of the file.
-.SH RETURN VALUE
-On success, a zero is returned and on error one of the following constants.
-.TP
-.B LIBMPQ_ERROR_EXIST
-File does not exist in archive.
-.SH SEE ALSO
-.BR libmpq__archive_files (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__file_imploded.3 b/dep/libmpq/doc/man3/libmpq__file_imploded.3
deleted file mode 100644
index 9adce38cb5f..00000000000
--- a/dep/libmpq/doc/man3/libmpq__file_imploded.3
+++ /dev/null
@@ -1,54 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-16 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__file_imploded("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " uint32_t *" "imploded"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__file_imploded\fP() to get the implosion status of the given file. It will return true for imploded files and false otherwise.
-.LP
-The \fBlibmpq__file_imploded\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument \fIfile_number\fP is the number of file and the third argument is a reference to the implosion status \fIimploded\fP of the file.
-.SH RETURN VALUE
-On success, a zero is returned and on error one of the following constants.
-.TP
-.B LIBMPQ_ERROR_EXIST
-File does not exist in archive.
-.SH SEE ALSO
-.BR libmpq__archive_files (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__file_number.3 b/dep/libmpq/doc/man3/libmpq__file_number.3
deleted file mode 100644
index 8d7a47769ee..00000000000
--- a/dep/libmpq/doc/man3/libmpq__file_number.3
+++ /dev/null
@@ -1,52 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-16 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__file_number("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " const char *" "filename",
-.BI " uint32_t *" "number"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__file_number\fP() to get the number of a given file in the archive. This function will return a file number regardless of a known or opened listfile.
-.LP
-The \fBlibmpq__file_number\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument \fIfilename\fP is the name of the file and the third argument is a reference to the \fInumber\fP of the file.
-.SH RETURN VALUE
-On success, the number of the file is returned and on error one of the following constants.
-.TP
-.B LIBMPQ_ERROR_EXIST
-File does not exist in archive.
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__file_offset.3 b/dep/libmpq/doc/man3/libmpq__file_offset.3
deleted file mode 100644
index 392a66d0b04..00000000000
--- a/dep/libmpq/doc/man3/libmpq__file_offset.3
+++ /dev/null
@@ -1,55 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-15 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__file_offset("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " off_t *" "offset"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__file_offset\fP() to get the offset of the file, which is the absolute position in the archive. It also supports archives within archives.
-.LP
-The \fBlibmpq__file_offset\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument \fIfile_number\fP is the number of file and the third argument is a reference to the file starting position \fIoffset\fP in archive.
-.SH RETURN VALUE
-On success, a zero is returned and on error one of the following constants.
-.TP
-.B LIBMPQ_ERROR_EXIST
-File does not exist in archive.
-.SH SEE ALSO
-.BR libmpq__archive_offset (3),
-.BR libmpq__block_offset (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__file_packed_size.3 b/dep/libmpq/doc/man3/libmpq__file_packed_size.3
deleted file mode 100644
index b584ddf77dd..00000000000
--- a/dep/libmpq/doc/man3/libmpq__file_packed_size.3
+++ /dev/null
@@ -1,55 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-15 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__file_packed_size("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " off_t *" "packed_size"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__file_packed_size\fP() to get the packed size of a given file in the archive. It will return a valid size for compressed and imploded files as well as stored only.
-.LP
-The \fBlibmpq__file_packed_size\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument \fIfile_number\fP is the number of file and the third argument is a reference to the compressed, imploded or stored size \fIpacked_size\fP of file.
-.SH RETURN VALUE
-On success, a zero is returned and on error one of the following constants.
-.TP
-.B LIBMPQ_ERROR_EXIST
-File does not exist in archive.
-.SH SEE ALSO
-.BR libmpq__archive_packed_size (3),
-.BR libmpq__block_packed_size (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__file_read.3 b/dep/libmpq/doc/man3/libmpq__file_read.3
deleted file mode 100644
index cbfafbd0f4f..00000000000
--- a/dep/libmpq/doc/man3/libmpq__file_read.3
+++ /dev/null
@@ -1,77 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-16 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__file_read("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " uint8_t *" "out_buf",
-.BI " off_t " "out_size",
-.BI " off_t *" "transferred"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__file_read\fP() to read a given file into memory. If the file is encrypted it will be first decrypted and then if it is packed (compressed or imploded) it will be unpacked.
-.LP
-The \fBlibmpq__file_read\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument \fIfile_number\fP is the file to extract, the third argument \fIout_buf\fP is the output data buffer which contains the extracted data. The fourth argument \fIout_size\fP is the size of \fIout_buf\fP and the fifth argument is a reference to the \fItransferred\fP bytes of the file.
-.SH RETURN VALUE
-On success, a zero is returned and on error one of the following constants.
-.TP
-.B LIBMPQ_ERROR_EXIST
-File does not exist in archive.
-.TP
-.B LIBMPQ_ERROR_OPEN
-Block offset table was not opened by calling \fBlibmpq__block_open_offset\fP(), or it was closed by an \fBlibmpq__block_close_offset\fP() call.
-.TP
-.B LIBMPQ_ERROR_SIZE
-The output buffer is to small.
-.TP
-.B LIBMPQ_ERROR_SEEK
-Seeking in file failed.
-.TP
-.B LIBMPQ_ERROR_MALLOC
-Not enough memory for creating required structures.
-.TP
-.B LIBMPQ_ERROR_READ
-Reading in archive failed.
-.TP
-.B LIBMPQ_ERROR_DECRYPT
-Decrypting file failed.
-.TP
-.B LIBMPQ_ERROR_UNPACK
-Unpacking file failed.
-.SH SEE ALSO
-.BR libmpq__block_read (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__file_unpacked_size.3 b/dep/libmpq/doc/man3/libmpq__file_unpacked_size.3
deleted file mode 100644
index a81cf7a4e76..00000000000
--- a/dep/libmpq/doc/man3/libmpq__file_unpacked_size.3
+++ /dev/null
@@ -1,55 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-05-15 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "int32_t libmpq__file_unpacked_size("
-.BI " mpq_archive_s *" "mpq_archive",
-.BI " uint32_t " "file_number",
-.BI " off_t *" "unpacked_size"
-.BI ");"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__file_unpacked_size\fP() to get the unpacked size of a given file in the archive. It will return a valid size for compressed and imploded files as well as stored only.
-.LP
-The \fBlibmpq__file_unpacked_size\fP() function takes as first argument the archive structure \fImpq_archive\fP which have to be allocated first and opened by \fBlibmpq__archive_open\fP(). The second argument \fIfile_number\fP is the number of file and the third argument is a reference to the uncompressed, exploded or stored size \fIunpacked_size\fP of file.
-.SH RETURN VALUE
-On success, a zero is returned and on error one of the following constants.
-.TP
-.B LIBMPQ_ERROR_EXIST
-File does not exist in archive.
-.SH SEE ALSO
-.BR libmpq__archive_unpacked_size (3),
-.BR libmpq__block_unpacked_size (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__strerror.3 b/dep/libmpq/doc/man3/libmpq__strerror.3
deleted file mode 100644
index 246f422eed0..00000000000
--- a/dep/libmpq/doc/man3/libmpq__strerror.3
+++ /dev/null
@@ -1,45 +0,0 @@
-.\" Copyright (c) 2010 Georg Lukas <georg@op-co.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2010-07-18 "The MoPaQ archive library"
-.SH NAME
-libmpq__strerror \- return string describing libmpq error number
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "const char *libmpq__strerror(int32_t returncode);"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__strerror\fP() to get a string message for the return code of one of the other libmpq functions.
-.SH RETURN VALUE
-The function returns a string pointer to non-writable memory or NULL if \fBreturncode\fP is not a return code of a libmpq function.
-.SH SEE ALSO
-.BR libmpq (3), strerror (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/doc/man3/libmpq__version.3 b/dep/libmpq/doc/man3/libmpq__version.3
deleted file mode 100644
index 5500d7314f5..00000000000
--- a/dep/libmpq/doc/man3/libmpq__version.3
+++ /dev/null
@@ -1,45 +0,0 @@
-.\" Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
-.\"
-.\" This is free documentation; you can redistribute it and/or
-.\" modify it under the terms of the GNU General Public License as
-.\" published by the Free Software Foundation; either version 2 of
-.\" the License, or (at your option) any later version.
-.\"
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\"
-.\" This manual is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public
-.\" License along with this manual; if not, write to the Free
-.\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111,
-.\" USA.
-.TH libmpq 3 2008-03-31 "The MoPaQ archive library"
-.SH NAME
-libmpq \- cross-platform C library for manipulating mpq archives.
-.SH SYNOPSIS
-.nf
-.B
-#include <mpq.h>
-.sp
-.BI "const char *libmpq__version();"
-.fi
-.SH DESCRIPTION
-.PP
-Call \fBlibmpq__version\fP() to get information about the version of the library, it is useful to create minimum required version verifications.
-.SH RETURN VALUE
-The function returns the library version.
-.SH SEE ALSO
-.BR libmpq (3)
-.SH AUTHOR
-Check documentation.
-.TP
-libmpq is (c) 2003-2008
-.B Maik Broemme <mbroemme@plusserver.de>
-.PP
-The above e-mail address can be used to send bug reports, feedbacks or library enhancements.
diff --git a/dep/libmpq/libmpq-config.in b/dep/libmpq/libmpq-config.in
deleted file mode 100644
index d345efdbe09..00000000000
--- a/dep/libmpq/libmpq-config.in
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/bin/sh
-
-prefix="@prefix@"
-exec_prefix="@exec_prefix@"
-exec_prefix_set=no
-
-usage="\
-Usage: libmpq-config [--prefix[=DIR]] [--exec-prefix[=DIR]] [--version] [--libs] [--cflags]"
-
-if test "$#" -eq "0"; then
- echo "${usage}" 1>&2
- exit 1
-fi
-
-while test "$#" -gt "0"; do
- case "$1" in
- -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
- *) optarg= ;;
- esac
-
- case "$1" in
- --prefix=*)
- prefix="$optarg"
- if test "$exec_prefix_set" = "no" ; then
- exec_prefix="$optarg"
- fi
- ;;
- --prefix)
- echo "$prefix"
- ;;
- --exec-prefix=*)
- exec_prefix="$optarg"
- exec_prefix_set=yes
- ;;
- --exec-prefix)
- echo "$exec_prefix"
- ;;
- --version)
- echo "@VERSION@"
- ;;
- --cflags)
- largefile="@LFS_CFLAGS@"
- includes=-I@includedir@/libmpq
- echo "$includes $largefile"
- ;;
- --libs)
- libdirs="-L@libdir@"
- echo "$libdirs -lmpq"
- ;;
- *)
- echo "${usage}" 1>&2
- exit 1
- ;;
- esac
- shift
-done
-
diff --git a/dep/libmpq/libmpq.pc.in b/dep/libmpq/libmpq.pc.in
deleted file mode 100644
index 8c53bea35a0..00000000000
--- a/dep/libmpq/libmpq.pc.in
+++ /dev/null
@@ -1,10 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: libmpq
-Description: GPL version of the libmpq library
-Version: @VERSION@
-Libs: -L${libdir} -lmpq
-Cflags: -I${includedir}/libmpq @LFS_CFLAGS@
diff --git a/dep/libmpq/libmpq/Makefile.am b/dep/libmpq/libmpq/Makefile.am
deleted file mode 100644
index 409e3dfe02f..00000000000
--- a/dep/libmpq/libmpq/Makefile.am
+++ /dev/null
@@ -1,23 +0,0 @@
-# minimum required automake 1.6
-AUTOMAKE_OPTIONS = 1.6
-
-# library information and headers which should not be installed.
-lib_LTLIBRARIES = libmpq.la
-noinst_HEADERS = common.h explode.h extract.h huffman.h mpq-internal.h wave.h
-
-# directory where the include files will be installed.
-libmpq_includedir = $(includedir)/libmpq
-
-# header files to install.
-libmpq_include_HEADERS = mpq.h
-
-libmpq_la_SOURCES = $(GENERAL_SRCS)
-libmpq_la_LDFLAGS = -release $(PACKAGE_VERSION)
-
-GENERAL_SRCS = \
- common.c \
- huffman.c \
- extract.c \
- explode.c \
- mpq.c \
- wave.c
diff --git a/dep/libmpq/libmpq/common.c b/dep/libmpq/libmpq/common.c
deleted file mode 100644
index 879bd902b58..00000000000
--- a/dep/libmpq/libmpq/common.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * common.c -- shared functions used by mpq-tools.
- *
- * Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/* generic includes. */
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-/* libmpq main includes. */
-#include "mpq.h"
-#include "mpq-internal.h"
-
-/* libmpq generic includes. */
-#include "extract.h"
-
-#include "common.h"
-
-/* the global shared decryption buffer. it's a static array compiled into the
- * library, and can be re-created by compiling and running crypt_buf_gen.c
- */
-#include "crypt_buf.h"
-
-/* function to return the hash to a given string. */
-uint32_t libmpq__hash_string(const char *key, uint32_t offset) {
-
- /* some common variables. */
- uint32_t seed1 = 0x7FED7FED;
- uint32_t seed2 = 0xEEEEEEEE;
-
- /* one key character. */
- uint32_t ch;
-
- /* prepare seeds. */
- while (*key != 0) {
- ch = toupper(*key++);
- seed1 = crypt_buf[offset + ch] ^ (seed1 + seed2);
- seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
- }
-
- return seed1;
-}
-
-/* function to encrypt a block. */
-int32_t libmpq__encrypt_block(uint32_t *in_buf, uint32_t in_size, uint32_t seed) {
-
- /* some common variables. */
- uint32_t seed2 = 0xEEEEEEEE;
- uint32_t ch;
-
- /* we're processing the data 4 bytes at a time. */
- for (; in_size >= 4; in_size -= 4) {
- seed2 += crypt_buf[0x400 + (seed & 0xFF)];
- ch = *in_buf ^ (seed + seed2);
- seed = ((~seed << 0x15) + 0x11111111) | (seed >> 0x0B);
- seed2 = *in_buf + seed2 + (seed2 << 5) + 3;
- *in_buf++ = ch;
- }
-
- /* if no error was found, return decrypted bytes. */
- return LIBMPQ_SUCCESS;
-}
-
-
-/* function to decrypt a block. */
-int32_t libmpq__decrypt_block(uint32_t *in_buf, uint32_t in_size, uint32_t seed) {
-
- /* some common variables. */
- uint32_t seed2 = 0xEEEEEEEE;
- uint32_t ch;
-
- /* we're processing the data 4 bytes at a time. */
- for (; in_size >= 4; in_size -= 4) {
- seed2 += crypt_buf[0x400 + (seed & 0xFF)];
- ch = *in_buf ^ (seed + seed2);
- seed = ((~seed << 0x15) + 0x11111111) | (seed >> 0x0B);
- seed2 = ch + seed2 + (seed2 << 5) + 3;
- *in_buf++ = ch;
- }
-
- /* if no error was found, return decrypted bytes. */
- return LIBMPQ_SUCCESS;
-}
-
-/* function to detect decryption key. */
-int32_t libmpq__decrypt_key(uint8_t *in_buf, uint32_t in_size, uint32_t block_size, uint32_t *key) {
-
- /* some common variables. */
- uint32_t saveseed1;
-
- /* temp = seed1 + seed2 */
- uint32_t temp;
- uint32_t i = 0;
-
- /* temp = seed1 + buffer[0x400 + (seed1 & 0xFF)] */
- temp = (*(uint32_t *)in_buf ^ in_size) - 0xEEEEEEEE;
-
- /* try all 255 possibilities. */
- for (i = 0; i < 0x100; i++) {
-
- /* some common variables. */
- uint32_t seed1;
- uint32_t seed2 = 0xEEEEEEEE;
- uint32_t ch;
- uint32_t ch2;
-
- /* try the first uint32_t's (we exactly know the value). */
- seed1 = temp - crypt_buf[0x400 + i];
- seed2 += crypt_buf[0x400 + (seed1 & 0xFF)];
- ch = ((uint32_t *)in_buf)[0] ^ (seed1 + seed2);
-
- if (ch != in_size) {
- continue;
- }
-
- /* add one because we are decrypting block positions. */
- saveseed1 = seed1 + 1;
- ch2 = ch;
-
- /*
- * if ok, continue and test the second value. we don't know exactly the value,
- * but we know that the second one has lower 16 bits set to zero (no compressed
- * block is larger than 0xFFFF bytes)
- */
- seed1 = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
- seed2 = ch + seed2 + (seed2 << 5) + 3;
- seed2 += crypt_buf[0x400 + (seed1 & 0xFF)];
- ch = ((uint32_t *)in_buf)[1] ^ (seed1 + seed2);
-
- /* check if we found the file seed. */
- if ((ch - ch2) <= block_size) {
-
- /* file seed found, so return it. */
- *key = saveseed1;
- return LIBMPQ_SUCCESS;
- }
- }
-
- /* if no file seed was found return with error. */
- return LIBMPQ_ERROR_DECRYPT;
-}
-
-/* function to decompress or explode a block from mpq archive. */
-int32_t libmpq__decompress_block(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size, uint32_t compression_type) {
-
- /* some common variables. */
- int32_t tb = 0;
-
- /* check if buffer is not compressed. */
- if (compression_type == LIBMPQ_FLAG_COMPRESS_NONE) {
-
- /* no compressed data, so copy input buffer to output buffer. */
- memcpy(out_buf, in_buf, out_size);
-
- /* store number of bytes copied. */
- tb = out_size;
- }
-
- /* check if one compression mode is used. */
- else if (compression_type == LIBMPQ_FLAG_COMPRESS_PKZIP ||
- compression_type == LIBMPQ_FLAG_COMPRESS_MULTI) {
-
- /* check if block is really compressed, some blocks have set the compression flag, but are not compressed. */
- if (in_size < out_size) {
-
- /* check if we are using pkzip compression algorithm. */
- if (compression_type == LIBMPQ_FLAG_COMPRESS_PKZIP) {
-
- /* decompress using pkzip. */
- if ((tb = libmpq__decompress_pkzip(in_buf, in_size, out_buf, out_size)) < 0) {
-
- /* something on decompression failed. */
- return tb;
- }
- }
-
- /* check if we are using multiple compression algorithm. */
- else if (compression_type == LIBMPQ_FLAG_COMPRESS_MULTI) {
-
- /*
- * check if it is a file compressed by blizzard's multiple compression, note that storm.dll
- * version 1.0.9 distributed with warcraft 3 passes the full path name of the opened archive
- * as the new last parameter.
- */
- if ((tb = libmpq__decompress_multi(in_buf, in_size, out_buf, out_size)) < 0) {
-
- /* something on decompression failed. */
- return tb;
- }
- }
- } else {
-
- /* block has set compression flag, but is not compressed, so copy data to output buffer. */
- memcpy(out_buf, in_buf, out_size);
-
- /* save the number of transferred bytes. */
- tb = in_size;
- }
- }
-
- /* if no error was found, return transferred bytes. */
- return tb;
-}
diff --git a/dep/libmpq/libmpq/common.h b/dep/libmpq/libmpq/common.h
deleted file mode 100644
index b9e03126434..00000000000
--- a/dep/libmpq/libmpq/common.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * common.h -- header functions used by mpq-tools.
- *
- * Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _COMMON_H
-#define _COMMON_H
-
-/* function to return the hash to a given string. */
-uint32_t libmpq__hash_string(
- const char *key,
- uint32_t offset
-);
-
-/* function to encrypt a block. */
-int32_t libmpq__encrypt_block(
- uint32_t *in_buf,
- uint32_t in_size,
- uint32_t seed
-);
-
-/* function to decrypt a block. */
-int32_t libmpq__decrypt_block(
- uint32_t *in_buf,
- uint32_t in_size,
- uint32_t seed
-);
-
-/* function to detect decryption key. */
-int32_t libmpq__decrypt_key(
- uint8_t *in_buf,
- uint32_t in_size,
- uint32_t block_size,
- uint32_t *key
-);
-
-/* function to decompress or explode block from archive. */
-int32_t libmpq__decompress_block(
- uint8_t *in_buf,
- uint32_t in_size,
- uint8_t *out_buf,
- uint32_t out_size,
- uint32_t compression_type
-);
-
-#endif /* _COMMON_H */
diff --git a/dep/libmpq/libmpq/crypt_buf.h b/dep/libmpq/libmpq/crypt_buf.h
deleted file mode 100644
index 34184b017fe..00000000000
--- a/dep/libmpq/libmpq/crypt_buf.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/* DO NOT CHANGE! this file is auto-generated by crypt_buf_gen.c */
-static const uint32_t crypt_buf[0x500] = {
- 0x55c636e2, 0x02be0170, 0x584b71d4, 0x2984f00e, 0xb682c809, 0x91cf876b,
- 0x775a9c24, 0x597d5ca5, 0x5a1afeb2, 0xd3e9ce0d, 0x32cdcdf8, 0xb18201cd,
- 0x3cce05ce, 0xa55d13be, 0xbb0afe71, 0x9376ab33, 0x848f645e, 0x87e45a45,
- 0x45b86017, 0x5e656ca8, 0x1b851a95, 0x2542dbd7, 0xab4df9e4, 0x5976ae9b,
- 0x6c317e7d, 0xcddd2f94, 0x3c3c13e5, 0x335b1371, 0x31a592ca, 0x51e4fc4c,
- 0xf7db5b2f, 0x8abdbe41, 0x8beaa674, 0x20d6b319, 0xde6c9a9d, 0xc5ac84e5,
- 0x445a5feb, 0x94958cb0, 0x1e7d3847, 0xf35d29b0, 0xca5cceda, 0xb732c8b5,
- 0xfdcc41dd, 0x0edcec16, 0x9d01feae, 0x1165d38e, 0x9ee193c8, 0xbf33b13c,
- 0x61bc0dfc, 0xef3e7be9, 0xf8d4d4c5, 0xc79b7694, 0x5a255943, 0x0b3dd20a,
- 0x9d1ab5a3, 0xcfa8ba57, 0x5e6d7069, 0xcb89b731, 0x3dc0d15b, 0x0d4d7e7e,
- 0x97e37f2b, 0xfefc2bb1, 0xf95b16b5, 0x27a55b93, 0x45f22729, 0x4c986630,
- 0x7c666862, 0x5fa40847, 0xa3f16205, 0x791b7764, 0x386b36d6, 0x6e6c3fef,
- 0xc75855db, 0x4abc7dc7, 0x4a328f9b, 0xcef20c0f, 0x60b88f07, 0xf7bb4b8f,
- 0x830b5192, 0x94f711ec, 0x20250752, 0x399d21a3, 0xe5c0840d, 0xe76cffa5,
- 0x624fab29, 0x5df133e6, 0x83e0b9b8, 0xc5796bfb, 0x4a7ab2d0, 0xba59a821,
- 0x03a81e4c, 0xcd3adfdb, 0x32b26b8c, 0x8e35c533, 0x9e6300e9, 0x8cf92ac5,
- 0x880d18eb, 0x131a53b3, 0x2ed2dc64, 0xb23257c1, 0xa06450c1, 0x1b92cb8e,
- 0x72ed730e, 0x19a685f0, 0x82836483, 0x42d94e8a, 0xee9bd6f6, 0x556d0b6a,
- 0xba65589a, 0xde24cce4, 0x53329f6c, 0xc754fe8b, 0x503d2dc7, 0x10027ba4,
- 0xd3b60a8b, 0x68e68d83, 0x0a9128a9, 0x595fa35f, 0x0b03b5be, 0x150a45c4,
- 0xb1629cce, 0xe5f7497b, 0x8a7098a4, 0xb8233e69, 0x8ea0f978, 0x5b579970,
- 0xeab14318, 0x4b28b263, 0xb6766cef, 0x06782877, 0x155c6dd0, 0xc711333c,
- 0xf819cedf, 0x00eb1d68, 0xd6fffa6e, 0x439e5962, 0xd765d6db, 0xcb0bcee9,
- 0x6d3c5647, 0x965466f3, 0x0ca983c9, 0x74ecc1ce, 0xfc0563b6, 0x42b08fee,
- 0xc5b38853, 0xfe502ceb, 0x7b432faf, 0xc309e610, 0x2c3997d8, 0x43774654,
- 0x15bd9d2c, 0xed6a420d, 0xc7ff520c, 0xb8a97fd1, 0x5e4d60cc, 0xb9738d11,
- 0xda2181ff, 0x73ac2597, 0x3a8eec8d, 0xac85e779, 0xf3f975d6, 0xb9fe7b91,
- 0x0f155d1e, 0x2860b6dd, 0x835977cb, 0xb0607436, 0x9cab7f6b, 0x8ab91186,
- 0xc12b51e9, 0x20084e8b, 0x44ba8ead, 0xa542b130, 0x82bcd5c4, 0xcc747f4e,
- 0x0f1909d8, 0xda242e1c, 0x6f7d1aa0, 0xd2626486, 0x88d0781e, 0xab695ccd,
- 0xfa569145, 0xb4feb55c, 0xbe47e896, 0xe70a7a88, 0xd56185a2, 0xacf4c871,
- 0x09282332, 0x1ddeeaa8, 0x590c7adb, 0xf4a97667, 0xbfd85705, 0x0ea77ccc,
- 0xa9f85364, 0x83195869, 0x8bfb041a, 0xdb842f5c, 0xd6f0f315, 0xa7756ea7,
- 0x0a51b439, 0xa9edf8a3, 0xd9084e2f, 0x827407f8, 0xd4ac8284, 0x09739d0d,
- 0xb3bb6cfc, 0xd539c77d, 0x6bbc9ac0, 0x35c641aa, 0x934c96b0, 0xd17af317,
- 0x29c6baef, 0xb275cdac, 0xd72662de, 0x9f5c2544, 0xc1a98f75, 0xd98e8f9a,
- 0x47bd5c86, 0x70c610a6, 0xb5482ed4, 0x23b9c68c, 0x3c1bae66, 0x69556e7f,
- 0xd902f5e0, 0x653d195b, 0xde6541fb, 0x07bcc6ac, 0xc6ee7788, 0x801534d4,
- 0x2c1f35c0, 0xd9de614d, 0xbdccac85, 0xb4d4a0da, 0x242d549b, 0x9d964796,
- 0xb9ceb982, 0x59fa99a9, 0xd8986cc1, 0x9e90c1a1, 0x01bbd82f, 0xd7f1c5fd,
- 0xdd847eba, 0x883d305d, 0x25f13152, 0x4a92694d, 0x77f1e601, 0x8024e6e7,
- 0x02a5f53d, 0x9c3ef4d9, 0xaf403ccc, 0xe2ad03c0, 0x46edf6ec, 0x6f9bd3e6,
- 0xcc24ad7a, 0x47afab12, 0x82298df7, 0x708c9eec, 0x76f8c1b1, 0xb39459d2,
- 0x3f1e26d9, 0xe1811be7, 0x56ed1c4d, 0xc9d18af8, 0xe828060e, 0x91cada2e,
- 0x5ccbf9b7, 0xf1a552d4, 0x3c9d4343, 0xe1008785, 0x2adfeebf, 0xf90240a0,
- 0x3d08cce7, 0x426e6fb0, 0x573c984f, 0x13a843ae, 0x406b7439, 0x636085d9,
- 0x5000ba9a, 0xad4a47ab, 0xaf001d8d, 0x419907ae, 0x185c8f96, 0xe5e9ed4d,
- 0x61764133, 0xd3703d97, 0xac98f0c6, 0xdbc3a37c, 0x85f010c4, 0x90491e32,
- 0xf12e18bf, 0xc88c96e1, 0xd3fbd6d9, 0xe3c28b08, 0xd5bf08cc, 0xb1e78859,
- 0x2546ddcf, 0xb030b200, 0xaafd2811, 0x55b22d21, 0xd38bf567, 0x469c7a2b,
- 0x5ad05792, 0xa1a5981e, 0x7dfb8384, 0x34d1ca0a, 0x7eb0dbe0, 0xd61ce0f6,
- 0x398068b7, 0xe6406d1f, 0x95ae6b47, 0xe4281230, 0xb0843061, 0xa70a3a68,
- 0xe340f625, 0x72dcbffd, 0x8eb8afcd, 0x18b6661f, 0x17ef5a5c, 0x000c5b22,
- 0x6ba13836, 0x6165e383, 0x74481c5b, 0xe56f0711, 0xa26f5024, 0x5ff22e60,
- 0x31a5e829, 0xa1094bf0, 0xc680ec6c, 0x8cf327d7, 0xebf1348a, 0x6a227d2f,
- 0x74065184, 0x8df65112, 0x2bbd05ee, 0xe4d00ed6, 0x2980ee1a, 0x6ae1da73,
- 0xe84614da, 0x6c9906ab, 0xcf8e02db, 0xd3723e97, 0x92f66caf, 0xac8491c7,
- 0xaec65696, 0xb98997cf, 0xfa16c762, 0x6d73c65f, 0x205d22a6, 0x4dd3aaa5,
- 0x2deb6bc0, 0x9f37686c, 0x71a5282b, 0x376bb9e0, 0x7fff2a1b, 0xde67982f,
- 0x9cbf33ce, 0x2e6dab37, 0x6e3424b9, 0x0ee143bc, 0x832a60d9, 0xbb6329e1,
- 0x13f6befd, 0x5965fb84, 0xf60b233c, 0x3d695183, 0x433224a1, 0xb5d9cae5,
- 0x82459bab, 0x9f21b311, 0xaf6c5247, 0xb447b13a, 0x7b2676c3, 0xc38979cd,
- 0x8526ae25, 0xc550ad5b, 0x685099a7, 0x65e9c2bd, 0xe5c6dc36, 0xe10b37a9,
- 0x88016878, 0xce81d4e4, 0x24d6fc80, 0x4106152d, 0x6d4f5f90, 0xc4dc74be,
- 0xdb48676c, 0x6cb569b7, 0xf3bf598f, 0x042b08d9, 0x02ccb2de, 0xb1056f65,
- 0x47994af4, 0xfa141ba4, 0x9376ab2e, 0x07a76737, 0x75e7e6fc, 0x449d80a1,
- 0x03b7259d, 0xf6df358a, 0x5a75d5b9, 0x47286923, 0x3b1a30ef, 0xeebe3d6a,
- 0x9db1aa00, 0x007a90d9, 0x24667071, 0x019c73cf, 0x69039bcd, 0x95900744,
- 0x6518b1eb, 0x6905f202, 0xee3951b2, 0xe141fca9, 0x797fa832, 0x5a95e55b,
- 0xd6263b15, 0x5b61f394, 0x897acb1c, 0x005f83a9, 0x22420f71, 0xf495176e,
- 0x7e138f3d, 0x1392e384, 0x373bf7aa, 0x8e512816, 0xa960b3ca, 0x0474d74c,
- 0xffacd6d7, 0x2ef5ed9e, 0x60992aaa, 0x7e690e99, 0x23c0749d, 0xd8e29105,
- 0x555d5909, 0x15631bfe, 0xa69c5a1c, 0x501017ca, 0x99438048, 0x38733ac7,
- 0xe682e2c8, 0xd4655fd6, 0x956e4c04, 0x347df643, 0x2f4b177b, 0x93ed3aa4,
- 0xa77e1dd5, 0x7ae55702, 0xd2a52fd9, 0xef8ba18c, 0xb7d3c1ee, 0x8078ba8d,
- 0xab5aaadb, 0x752be08f, 0x068b31c1, 0x078aae3c, 0xaa5a8343, 0x123d9268,
- 0x2ceaee43, 0x8ebdb239, 0x650251f3, 0x04883648, 0x8c62e12e, 0x12b32167,
- 0xe5112e9a, 0x10002548, 0x3e7a818d, 0x077e5327, 0xf140cc21, 0x6ce7d75d,
- 0x9b99f9a5, 0x3215741c, 0xb6aadbae, 0x738768dc, 0x82a3742f, 0x76517020,
- 0xdd872ad8, 0x9d0902b2, 0x7d1a6b04, 0x49381592, 0x63a652a5, 0x0c15e626,
- 0xe22f70d6, 0x01e84385, 0xb29de134, 0x20c5000e, 0xe961f443, 0x2d31662e,
- 0x3ce6bc28, 0x34f9dd94, 0xfa45de53, 0x497588bd, 0x9468215b, 0x0777fa5c,
- 0x6f7114c0, 0xe0e82694, 0xe4371986, 0x57112de2, 0xe0cac289, 0xf2a3cee0,
- 0x6a41e1b9, 0xbfcea77d, 0xf927fd52, 0x69747d98, 0xbea76cdb, 0x8dd39557,
- 0x04db5ece, 0x2a0885c8, 0x3be4e8ee, 0x21d785dc, 0x09de7c0e, 0x3258ea33,
- 0x51922982, 0xee8dd024, 0x3df6965d, 0x30c1237b, 0xf7f6686a, 0x9faca186,
- 0x7c400076, 0x85acef8a, 0xf4b6d220, 0xddc3481c, 0x439eaec4, 0x717bbe63,
- 0x8259faa7, 0xd682bd68, 0x932a8610, 0x38bf0a7f, 0x6212e2c7, 0x88ee3168,
- 0xb3c27047, 0x6133cb1e, 0x15295506, 0x5ae66246, 0x1d208ddd, 0xa91d3dba,
- 0xc315968d, 0x6aa2664b, 0x716d0cca, 0x891f4956, 0x80866bff, 0xbd56c847,
- 0x9093425a, 0x28dd9e87, 0x84ef3e08, 0x690a49d6, 0x6a7eff82, 0xabcfe400,
- 0x3d3be5ca, 0x381b650c, 0x4b7c8622, 0x3e0246f3, 0xa3561654, 0x9488865c,
- 0x3aef1bf2, 0x5e5d68a2, 0xd32f1ddc, 0x51972bf0, 0x177a213b, 0x469375c2,
- 0x37640bd0, 0xfc3324c8, 0x07091a09, 0x2d63d3fb, 0x2153f023, 0x48223875,
- 0x61a55826, 0x8c136538, 0x49f71d98, 0x84c7d51e, 0x85551a73, 0x13d604c5,
- 0xd701a626, 0x87b844ca, 0x741eb29d, 0x2a2c977c, 0xc797ca03, 0x6c4085d7,
- 0x2dacf79b, 0x734fa2eb, 0xcc290557, 0xfa1e75e4, 0x06b29a27, 0xbece2a7a,
- 0x70a4554b, 0xc935942e, 0xa764bbc1, 0x1fe391d6, 0x7807f0c2, 0x40606ed9,
- 0xe5153086, 0xe91d7dd2, 0xed5d3ba9, 0xaa14b64a, 0x83b24dd9, 0xec1ff5cd,
- 0xba33ead3, 0xe4ef735c, 0xbc062438, 0xd8bfd523, 0x473d1e04, 0x2007f8a7,
- 0xb02903ed, 0x86ea8ada, 0x95ab69cf, 0xfd1f9809, 0x9cb3d8bb, 0x51f45958,
- 0x9cdd4276, 0xc245865e, 0x8f0c836b, 0x4ee7dc07, 0xf6368d9d, 0xef2c1dc1,
- 0xee56b54b, 0xbd62ce2f, 0xf4916aad, 0xc81cb594, 0x41729f49, 0x24bef0a4,
- 0xdef487a9, 0x222e05b8, 0x8d3bf5c6, 0x11b55009, 0xad09d2b3, 0x19db9fd1,
- 0xd7427085, 0x33dbfc8b, 0x526b9378, 0x790e1bc8, 0xb2998a00, 0xa5641703,
- 0x0676d249, 0x6b9185cc, 0x30e4348f, 0x82c52f65, 0x57c7dc24, 0x489c1ecd,
- 0x9fcab02a, 0x56d61117, 0xfe869cac, 0x55fc5140, 0x7fbbb382, 0x9e5afc79,
- 0x10047c99, 0xfc9f5984, 0x56587e2d, 0xb98193f0, 0x98fe5e8e, 0x29b15b6b,
- 0x9561f055, 0xbb0caa25, 0x1e4ecc15, 0x23f5393b, 0x0845b458, 0xceff67ca,
- 0xb099900c, 0x00b1564f, 0x39eef3d1, 0xfcc1bf84, 0xac8893b5, 0x6484bf0e,
- 0x91c02ab3, 0x8c0c0c70, 0x686fa8c6, 0xe171bed6, 0xdfae37df, 0xd5a1a4e7,
- 0xe3eb49a1, 0x5e6014e0, 0x205b21ac, 0xfd58b3da, 0x2e7c07cd, 0xef2cc85a,
- 0xd7587b46, 0xf417847d, 0x8a30cec1, 0x70984f6c, 0xf0b63388, 0xc220c98d,
- 0xede62936, 0x92c0a7b3, 0x1ef371e8, 0x2005f7af, 0x91a47265, 0xb0cf5504,
- 0xd500aba8, 0xcb5c4bd3, 0x9b3bcbc3, 0xcf6644b5, 0xce9488ef, 0x003fc96e,
- 0xaa42222f, 0x4844f3d0, 0x4db89d77, 0x08681aae, 0x662f3a28, 0x761552db,
- 0x1df7a17a, 0x93feed9a, 0xcc496a4f, 0xa217cfcd, 0x3ba3c930, 0x268f7e77,
- 0x0797b4a1, 0x8bebfc51, 0x068930c4, 0x16c874e2, 0xc242da24, 0xfb229f76,
- 0xa0795b02, 0x689fc036, 0x17a73732, 0xd21aec00, 0xac00a692, 0x5b217f18,
- 0xae421624, 0x2bc05cc0, 0x48c1db7a, 0x4f4e63b4, 0x1667f04e, 0x34020f94,
- 0x972b2555, 0x9a07355b, 0x01665970, 0x7db60c6f, 0x3ad7103b, 0x5c3d09c0,
- 0xeea3dada, 0x88c21c10, 0x102436d7, 0x6a3b3400, 0xeb523c4c, 0xfb97d896,
- 0x964cb86b, 0xdd878038, 0x0529da4d, 0x0b1468a5, 0x18739ac8, 0xf7f26668,
- 0xf64f4471, 0x5c14f5c3, 0x44a081fb, 0x39ac7e37, 0x8a17c26b, 0x868f5e67,
- 0x3931978d, 0x6edf7817, 0x4951cc67, 0x943407f3, 0xcc5e748f, 0x2b7ee729,
- 0xcbb320f0, 0x11fec8e7, 0xfccfc658, 0x03454354, 0x373aa1ec, 0x1d58fe9a,
- 0x064710ae, 0xa88aa0ba, 0xd183a23e, 0x40d150a3, 0xf531b8d1, 0xa7d99f85,
- 0x11838cd5, 0xb19e64b3, 0x3d67a5e9, 0xb02c5ac6, 0x99b9b9e8, 0x4c202b7a,
- 0x15f261d3, 0xa84c2d0d, 0x50f185a6, 0x33ba41d5, 0x39791013, 0x4baff44e,
- 0xeeeeaa1c, 0xe0488314, 0x559ccd2b, 0xa104f445, 0x636f37c4, 0x264d5e3b,
- 0x75c17f35, 0x75424131, 0xbb115739, 0x74fe755a, 0x7d3a7aa6, 0x2d8be784,
- 0x83ed154a, 0xfc2673d8, 0x44dd4a7f, 0x79056cc8, 0x82cc8831, 0x9d3c1b7c,
- 0xe9453bfa, 0x24315694, 0x661f3253, 0x75549f5c, 0xbb2b63ed, 0x67e00d96,
- 0xf48966c7, 0x0d7bea56, 0xc25f92ef, 0xa947a79d, 0xde4adf6f, 0xac0f0342,
- 0xd3eb246b, 0xa4aa118e, 0x3c3e6a46, 0x457f4441, 0xa50a406f, 0x6c508d9f,
- 0xe9ac18e7, 0x1ecdb4ba, 0x39ac7e3a, 0x7fb304fa, 0x6f38f8e8, 0x4aecea6d,
- 0x61035e73, 0x81708907, 0xebc07205, 0x90fd7614, 0xb52d217f, 0x6c4de195,
- 0x1dd49084, 0x64ee482c, 0x94c7a521, 0x540c09d8, 0x75df8dd5, 0x414131f7,
- 0x3698fd76, 0xf784db4f, 0xf8c97a03, 0x048f39b9, 0x3bf4f0bd, 0x8cb50992,
- 0x9b58d9ee, 0xe5ab79cc, 0x9a5f6052, 0xbd9591b0, 0xfad2232b, 0x5a632254,
- 0x0286e618, 0x8ad3c8f7, 0xe4060176, 0x754c4617, 0x5c10490b, 0x6f7d6fff,
- 0x2187b42a, 0x5775095b, 0x02f4c663, 0x5a5dca06, 0xfe4ad4c7, 0x53e19f7d,
- 0x59ff46b5, 0xbcc42ba5, 0xfd2f4a97, 0xbed6d905, 0x95629b6b, 0x21a1c0db,
- 0xaa10b45d, 0xe6ef6d58, 0x2892cf4d, 0x9fed6c10, 0x1e386bf7, 0x9be0c6e8,
- 0x2b2f15ef, 0x19f5ac7b, 0x7aff0e72, 0x31da576f, 0x30252cb4, 0x577960ac,
- 0x166e9e5a, 0xa9374a61, 0x71369c96, 0x7ff826ae, 0xe8175326, 0xcabbfd33,
- 0x0191190e, 0x699d3c3e, 0x36b40b22, 0xb3950513, 0x9b889bfa, 0xa52a5007,
- 0xac290fed, 0x3b4e4a4f, 0xb753d8d6, 0x3c531f22, 0x582f6427, 0xa9cd93a9,
- 0x546e39ae, 0x242faad2, 0xd2e0f747, 0x09f6325d, 0x59d48719, 0xad7eb66e,
- 0xd5512878, 0x56debf9d, 0x5107e5a5, 0xf1c00aa4, 0x814ccca8, 0x600d90f0,
- 0x9be97619, 0x915fa5f2, 0x2b5628dd, 0xa33d5f5a, 0x595df7c1, 0x6966215d,
- 0x50ec8337, 0xf1d21372, 0x0ee2eefb, 0xad9e70b7, 0xab0d2fe4, 0xcf277b5d,
- 0x62585a2c, 0x835a7844, 0x74b1fa6b, 0x49baffd5, 0x2ea9c864, 0x129311a8,
- 0xbdfa1867, 0x83ca5997, 0x9d1db719, 0x84bb79e6, 0x9e3f99f2, 0x313f6101,
- 0x1b99245b, 0xd15d8fb2, 0xcef90f81, 0x2945268d, 0xdbbcf573, 0xb1021886,
- 0x9ee7ec1d, 0x1cf824f7, 0x7eaa2e32, 0x69c0a2b5, 0x7494419c, 0xe253d7d3,
- 0x48da3d12, 0x45b8b571, 0xdb4d147a, 0xd82d8dde, 0x265d10a2, 0xb0a6eb9a,
- 0x7e1c93a6, 0x36fe2f46, 0xdcad6b00, 0x05439191, 0xb0ce5484, 0x61d1c309,
- 0x8da62a03, 0x06d0fe2f, 0xbac6dd3c, 0xca2006f3, 0x8321b1af, 0x0411a6f3,
- 0xe8918eac, 0x21a2c152, 0x91c0d54f, 0x6aaa14fa, 0xdd22a440, 0x88cb2075,
- 0x7a4eb813, 0x67afa071, 0xd8d98c9c, 0x31f10d47, 0x6ff1a8a8, 0x2faaf0a1,
- 0x48a221bb, 0x3be6948b, 0xaa79e79b, 0x0ea7278c, 0x7a3857ef, 0x49b7fe55,
- 0xd51cb931, 0x041c018d, 0x00b90501, 0x45ea7881, 0x8fc1dbcf, 0xb80b32a9,
- 0xabacd2e9, 0x677bdc40, 0xecace542, 0x6d6514eb, 0x31c09ff7, 0x5e6c1abd,
- 0x1c391d0f, 0x0e9d77f1, 0x7119392d, 0x6be9b0ba, 0x6194fa77, 0x45e62148,
- 0x42234af2, 0xc3239d66, 0x939cbdbc, 0x56200d9c, 0x6b275208, 0x001a61f3,
- 0xccc2a546, 0x4b722be0, 0xee25f2b7, 0x6d86cf9e, 0xaa6be0cd, 0x4dcda7b6,
- 0x78d4aa13, 0x36ea7ad9, 0x3f29d700, 0xdeea2d84, 0x6a6af5bd, 0x18afb81c,
- 0xd8e4e73c, 0x8aa708ba, 0x658b94d9, 0xa676478c, 0xcfa10c22, 0x25593c74,
- 0x8d962235, 0x5f980270, 0x3df6ebc0, 0x8e7d92fa, 0xc3ee55e1, 0xd5f72447,
- 0x02b0fa95, 0x52b0b520, 0x70d2c11f, 0x3a6fdd6c, 0x193aa698, 0x5496f7d5,
- 0x4208931b, 0x7a4106ec, 0x83e86840, 0xf49b6f8c, 0xba3d9a51, 0x55f54ddd,
- 0x2de51372, 0x9afb571b, 0x3ab35406, 0xad64ff1f, 0xc77764fe, 0x7f864466,
- 0x416d9cd4, 0xa2489278, 0xe30b86e4, 0x0b5231b6, 0xba67aed6, 0xe5ab2467,
- 0x60028b90, 0x1d9e20c6, 0x2a7c692a, 0x6b691cdb, 0x9e51f817, 0x9b763dec,
- 0x3d29323f, 0xcfe12b68, 0x754b459b, 0xa2238047, 0xd9c55514, 0x6bdcffc1,
- 0x693e6340, 0x82383fe7, 0x1916ea5f, 0xec7bcd59, 0x72de165a, 0xe79a1617,
- 0x8ec86234, 0xa8f0d284, 0x20c90226, 0x7bf98884, 0x28a58331, 0x3ec3fa6e,
- 0x4ce0895b, 0xc353b4d0, 0x33ef064f, 0x21e5e210, 0xc8bb589d, 0xe85dcab2,
- 0xac65829f, 0xa7bf92d0, 0x05a6174d, 0x25a50c2e, 0xe5c78777, 0x3d75021f,
- 0x4baa9c98, 0x23bdc884, 0x9653bbd7, 0xbadce7f5, 0xc283a484, 0xc040df2e,
- 0x9370a841, 0x2f316022, 0x36eed231, 0xac2cbc0c, 0x13c0a49b, 0xcdd12997,
- 0x07fe91b2, 0xcd7eabcd, 0x2c01271d, 0x18432df8, 0x599c6bc7, 0x75e93d5a,
- 0xb67a6ee2, 0x8e738e16, 0xff9073fd, 0xaf77026a, 0xf86ea2fc, 0x91509ea3,
- 0x33a78dc6, 0x4f79234a, 0x3a7535bc, 0x3539fcb1, 0x3103ee52, 0x4f6f1e69,
- 0x6bb3ebbc, 0x4cb77555, 0x8dd1e999, 0x2ade439d, 0x11521fae, 0xb94d2545,
- 0x8dde9abd, 0x1909393f, 0xb792a23d, 0x749c455b, 0xb5b60f2c, 0x380459ce,
- 0x0dad5820, 0xb130845b, 0x291cbd52, 0xde9a5bb7, 0x51def961, 0x515b6408,
- 0xca6e823e, 0x382e6e74, 0xeebe3d71, 0x4c8f0c6a, 0xe676dcea, 0x14e1dc7c,
- 0x6f7fc634, 0xcf85a943, 0xd39ea96e, 0x136e7c93, 0x7164b304, 0xf32f1333,
- 0x35c34034, 0xde39d721, 0x91a87439, 0xc410111f, 0x29f17aac, 0x1316a6ff,
- 0x12f194ee, 0x420b9499, 0xf72db0dc, 0x690b9f93, 0x17d14bb2, 0x8f931ab8,
- 0x217500bc, 0x875413f8, 0x98b2e43d, 0xc51f9571, 0x54cebdca, 0x0719cc79,
- 0xf3c7080d, 0xe4286771, 0xa3eab3cd, 0x4a6b00e0, 0x11cf0759, 0x7e897379,
- 0x5b32876c, 0x5e8cd4f6, 0x0cedfa64, 0x919ac2c7, 0xb214f3b3, 0x0e89c38c,
- 0xf0c43a39, 0xeae10522, 0x835bce06, 0x9eec43c2, 0xea26a9d6, 0x69531821,
- 0x6725b24a, 0xda81b0e2, 0xd5b4ae33, 0x080f99fb, 0x15a83daf, 0x29dfc720,
- 0x91e1900f, 0x28163d58, 0x83d107a2, 0x4eac149a, 0x9f71da18, 0x61d5c4fa,
- 0xe3ab2a5f, 0xc7b0d63f, 0xb3cc752a, 0x61ebcfb6, 0x26ffb52a, 0xed789e3f,
- 0xaa3bc958, 0x455a8788, 0xc9c082a9, 0x0a1bef0e, 0xc29a5a7e, 0x150d4735,
- 0x943809e0, 0x69215510, 0xef0b0da9, 0x3b4e9fb3, 0xd8b5d04c, 0xc7a023a8,
- 0xb0d50288, 0x64821375, 0xc260e8cf, 0x8496bd2c, 0xff4f5435, 0x0fb5560c,
- 0x7cd74a52, 0x93589c80, 0x88975c47, 0x83bda89d, 0x8bcc4296, 0x01b82c21,
- 0xfd821dbf, 0x26520b47, 0x04983e19, 0xd3e1ca27, 0x782c580f, 0x326ff573,
- 0xc157bcc7, 0x4f5e6b84, 0x44ebfbfb, 0xda26d9d8, 0x6cd9d08e, 0x1719f1d8,
- 0x715c0487, 0x2c2d3c92, 0x53faaba9, 0xbc836146, 0x510c92d6, 0xe089f82a,
- 0x4680171f, 0x369f00de, 0x70ec2331, 0x0e253d55, 0xdafb9717, 0xe5dd922d,
- 0x95915d21, 0xa0202f96, 0xa161cc47, 0xeacfa6f1, 0xed5e9189, 0xdab87684,
- 0xa4b76d4a, 0xfa704897, 0x631f10ba, 0xd39da8f9, 0x5db4c0e4, 0x16fde42a,
- 0x2dff7580, 0xb56fec7e, 0xc3ffb370, 0x8e6f36bc, 0x6097d459, 0x514d5d36,
- 0xa5a737e2, 0x3977b9b3, 0xfd31a0ca, 0x903368db, 0xe8370d61, 0x98109520,
- 0xade23cac, 0x99f82e04, 0x41de7ea3, 0x84a1c295, 0x09191be0, 0x30930d02,
- 0x1c9fa44a, 0xc406b6d7, 0xeedca152, 0x6149809c, 0xb0099ef4, 0xc5f653a5,
- 0x4c10790d, 0x7303286c
-};
diff --git a/dep/libmpq/libmpq/explode.c b/dep/libmpq/libmpq/explode.c
deleted file mode 100644
index 2d778d25c39..00000000000
--- a/dep/libmpq/libmpq/explode.c
+++ /dev/null
@@ -1,602 +0,0 @@
-/*
- * explode.c -- explode function of pkware data compression library.
- *
- * Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
- *
- * This source was adepted from the C++ version of pkware.cpp included
- * in stormlib. The C++ version belongs to the following authors:
- *
- * Ladislav Zezula <ladik@zezula.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/* generic includes. */
-#include <string.h>
-
-/* libmpq main includes. */
-#include "mpq.h"
-
-/* libmpq generic includes. */
-#include "explode.h"
-
-/* tables used for data extraction. */
-static const uint8_t pkzip_dist_bits[] = {
- 0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
- 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
- 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
-};
-
-/* tables used for data extraction. */
-static const uint8_t pkzip_dist_code[] = {
- 0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A,
- 0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C,
- 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
- 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00
-};
-
-/* tables used for data extraction. */
-static const uint8_t pkzip_clen_bits[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
-};
-
-/* tables used for data extraction. */
-static const uint16_t pkzip_len_base[] = {
- 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
- 0x0008, 0x000A, 0x000E, 0x0016, 0x0026, 0x0046, 0x0086, 0x0106
-};
-
-/* tables used for data extraction. */
-static const uint8_t pkzip_slen_bits[] = {
- 0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07
-};
-
-/* tables used for data extraction. */
-static const uint8_t pkzip_len_code[] = {
- 0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00
-};
-
-/* tables used for data extraction. */
-static const uint8_t pkzip_bits_asc[] = {
- 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C,
- 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
- 0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08,
- 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B,
- 0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06,
- 0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08,
- 0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05,
- 0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C,
- 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
- 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
- 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
- 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
- 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
- 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
- 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D,
- 0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D
-};
-
-/* tables used for data extraction. */
-static const uint16_t pkzip_code_asc[] = {
- 0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0,
- 0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0,
- 0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360,
- 0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60,
- 0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8,
- 0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098,
- 0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C,
- 0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710,
- 0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8,
- 0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E,
- 0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8,
- 0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088,
- 0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A,
- 0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D,
- 0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078,
- 0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0,
- 0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040,
- 0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380,
- 0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180,
- 0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280,
- 0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080,
- 0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300,
- 0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0,
- 0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320,
- 0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220,
- 0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0,
- 0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0,
- 0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340,
- 0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900,
- 0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600,
- 0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200,
- 0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000
-};
-
-/* local unused variables. */
-char pkware_copyright[] = "PKWARE Data Compression Library for Win32\r\n"
- "Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n"
- "Patent No. 5,051,745\r\n"
- "PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n"
- "Version 1.11\r\n";
-
-/* skips given number of bits. */
-static int32_t skip_bit(pkzip_cmp_s *mpq_pkzip, uint32_t bits) {
-
- /* check if number of bits required is less than number of bits in the buffer. */
- if (bits <= mpq_pkzip->extra_bits) {
- mpq_pkzip->extra_bits -= bits;
- mpq_pkzip->bit_buf >>= bits;
- return 0;
- }
-
- /* load input buffer if necessary. */
- mpq_pkzip->bit_buf >>= mpq_pkzip->extra_bits;
- if (mpq_pkzip->in_pos == mpq_pkzip->in_bytes) {
- mpq_pkzip->in_pos = sizeof(mpq_pkzip->in_buf);
- if ((mpq_pkzip->in_bytes = mpq_pkzip->read_buf((char *)mpq_pkzip->in_buf, &mpq_pkzip->in_pos, mpq_pkzip->param)) == 0) {
- return 1;
- }
- mpq_pkzip->in_pos = 0;
- }
-
- /* update bit buffer. */
- mpq_pkzip->bit_buf |= (mpq_pkzip->in_buf[mpq_pkzip->in_pos++] << 8);
- mpq_pkzip->bit_buf >>= (bits - mpq_pkzip->extra_bits);
- mpq_pkzip->extra_bits = (mpq_pkzip->extra_bits - bits) + 8;
-
- /* if no error was found, return zero. */
- return 0;
-}
-
-/* this function generate the decode tables used for decryption. */
-static void generate_tables_decode(int32_t count, uint8_t *bits, const uint8_t *code, uint8_t *buf2) {
-
- /* some common variables. */
- int32_t i;
-
- /* EBX - count */
- for (i = count-1; i >= 0; i--) {
-
- /* some common variables. */
- uint32_t idx1 = code[i];
- uint32_t idx2 = 1 << bits[i];
-
- /* loop until table is ready. */
- do {
- buf2[idx1] = (uint8_t)i;
- idx1 += idx2;
- } while (idx1 < 0x100);
- }
-}
-
-/* this function generate the tables for ascii decompression. */
-static void generate_tables_ascii(pkzip_cmp_s *mpq_pkzip) {
-
- /* some common variables. */
- const uint16_t *code_asc = &pkzip_code_asc[0xFF];
- uint32_t acc;
- uint32_t add;
- uint16_t count;
-
- /* loop through ascii table. */
- for (count = 0x00FF; code_asc >= pkzip_code_asc; code_asc--, count--) {
- uint8_t *bits_asc = mpq_pkzip->bits_asc + count;
- uint8_t bits_tmp = *bits_asc;
-
- /* check if byte is finished. */
- if (bits_tmp <= 8) {
- add = (1 << bits_tmp);
- acc = *code_asc;
- do {
- mpq_pkzip->offs_2c34[acc] = (uint8_t)count;
- acc += add;
- } while (acc < 0x100);
- } else {
- if ((acc = (*code_asc & 0xFF)) != 0) {
- mpq_pkzip->offs_2c34[acc] = 0xFF;
- if (*code_asc & 0x3F) {
-
- /* decrease bit by four. */
- bits_tmp -= 4;
- *bits_asc = bits_tmp;
- add = (1 << bits_tmp);
- acc = *code_asc >> 4;
- do {
- mpq_pkzip->offs_2d34[acc] = (uint8_t)count;
- acc += add;
- } while (acc < 0x100);
- } else {
-
- /* decrease bit by six. */
- bits_tmp -= 6;
- *bits_asc = bits_tmp;
- add = (1 << bits_tmp);
- acc = *code_asc >> 6;
- do {
- mpq_pkzip->offs_2e34[acc] = (uint8_t)count;
- acc += add;
- } while (acc < 0x80);
- }
- } else {
-
- /* decrease bit by eight. (one byte) */
- bits_tmp -= 8;
- *bits_asc = bits_tmp;
- add = (1 << bits_tmp);
- acc = *code_asc >> 8;
- do {
- mpq_pkzip->offs_2eb4[acc] = (uint8_t)count;
- acc += add;
- } while (acc < 0x100);
- }
- }
- }
-}
-
-/*
- * decompress the imploded data using coded literals.
- *
- * returns: 0x000 - 0x0FF : one byte from compressed file.
- * 0x100 - 0x305 : copy previous block. (0x100 = 1 byte)
- * 0x306 : out of buffer?
- */
-static uint32_t decode_literal(pkzip_cmp_s *mpq_pkzip) {
-
- /* number of bits to skip. */
- uint32_t bits;
-
- /* position in buffers. */
- uint32_t value;
-
- /* check if bit the current buffer is set, if not return the next byte. */
- if (mpq_pkzip->bit_buf & 1) {
-
- /* skip current bit in the buffer. */
- if (skip_bit(mpq_pkzip, 1)) {
- return 0x306;
- }
-
- /* the next bits are position in buffers. */
- value = mpq_pkzip->pos2[(mpq_pkzip->bit_buf & 0xFF)];
-
- /* get number of bits to skip. */
- if (skip_bit(mpq_pkzip, mpq_pkzip->slen_bits[value])) {
- return 0x306;
- }
-
- /* check bits. */
- if ((bits = mpq_pkzip->clen_bits[value]) != 0) {
-
- /* some common variables. */
- uint32_t val2 = mpq_pkzip->bit_buf & ((1 << bits) - 1);
-
- /* check if we should skip one bit. */
- if (skip_bit(mpq_pkzip, bits)) {
-
- /* check position if we should skip the bit. */
- if ((value + val2) != 0x10E) {
- return 0x306;
- }
- }
-
- /* fill values. */
- value = mpq_pkzip->len_base[value] + val2;
- }
-
- /* return number of bytes to repeat. */
- return value + 0x100;
- }
-
- /* skip one bit. */
- if (skip_bit(mpq_pkzip, 1)) {
- return 0x306;
- }
-
- /* check the binary compression type, read 8 bits and return them as one byte. */
- if (mpq_pkzip->cmp_type == LIBMPQ_PKZIP_CMP_BINARY) {
-
- /* fill values. */
- value = mpq_pkzip->bit_buf & 0xFF;
-
- /* check if we should skip one bit. */
- if (skip_bit(mpq_pkzip, 8)) {
- return 0x306;
- }
-
- /* return value from bit buffer. */
- return value;
- }
-
- /* check if ascii compression is used. */
- if (mpq_pkzip->bit_buf & 0xFF) {
-
- /* fill values. */
- value = mpq_pkzip->offs_2c34[mpq_pkzip->bit_buf & 0xFF];
-
- /* check value. */
- if (value == 0xFF) {
- if (mpq_pkzip->bit_buf & 0x3F) {
-
- /* check if four bits are in bit buffer for skipping. */
- if (skip_bit(mpq_pkzip, 4)) {
- return 0x306;
- }
-
- /* fill values. */
- value = mpq_pkzip->offs_2d34[mpq_pkzip->bit_buf & 0xFF];
- } else {
-
- /* check if six bits are in bit buffer for skipping. */
- if (skip_bit(mpq_pkzip, 6)) {
- return 0x306;
- }
-
- /* fill values. */
- value = mpq_pkzip->offs_2e34[mpq_pkzip->bit_buf & 0x7F];
- }
- }
- } else {
-
- /* check if eight bits are in bit buffer for skipping. */
- if (skip_bit(mpq_pkzip, 8)) {
- return 0x306;
- }
-
- /* fill values. */
- value = mpq_pkzip->offs_2eb4[mpq_pkzip->bit_buf & 0xFF];
- }
-
- /* return out of buffer error (0x306) or position in buffer. */
- return skip_bit(mpq_pkzip, mpq_pkzip->bits_asc[value]) ? 0x306 : value;
-}
-
-/* this function retrieves the number of bytes to move back. */
-static uint32_t decode_distance(pkzip_cmp_s *mpq_pkzip, uint32_t length) {
-
- /* some common variables. */
- uint32_t pos = mpq_pkzip->pos1[(mpq_pkzip->bit_buf & 0xFF)];
-
- /* number of bits to skip. */
- uint32_t skip = mpq_pkzip->dist_bits[pos];
-
- /* skip the appropriate number of bits. */
- if (skip_bit(mpq_pkzip, skip) == 1) {
- return 0;
- }
-
- /* check if length is two. */
- if (length == 2) {
- pos = (pos << 2) | (mpq_pkzip->bit_buf & 0x03);
-
- /* skip the bits. */
- if (skip_bit(mpq_pkzip, 2) == 1) {
- return 0;
- }
- } else {
- pos = (pos << mpq_pkzip->dsize_bits) | (mpq_pkzip->bit_buf & mpq_pkzip->dsize_mask);
-
- /* skip the bits */
- if (skip_bit(mpq_pkzip, mpq_pkzip->dsize_bits) == 1) {
- return 0;
- }
- }
-
- /* return the bytes to move back. */
- return pos + 1;
-}
-
-/*
- * function loads data from the input buffer used by mpq_pkzip
- * "implode" and "explode" function as user defined callback and
- * returns number of bytes loaded.
- *
- * char *buf - pointer to a buffer where to store loaded data.
- * uint32_t *size - maximum number of bytes to read.
- * void *param - custom pointer, parameter of implode/explode.
- */
-static uint32_t data_read_input(char *buf, uint32_t *size, void *param) {
-
- /* some common variables. */
- pkzip_data_s *info = (pkzip_data_s *)param;
- uint32_t max_avail = (info->in_bytes - info->in_pos);
- uint32_t to_read = *size;
-
- /* check the case when not enough data available. */
- if (to_read > max_avail) {
- to_read = max_avail;
- }
-
- /* load data and increment offsets. */
- memcpy(buf, info->in_buf + info->in_pos, to_read);
- info->in_pos += to_read;
-
- /* return bytes read. */
- return to_read;
-}
-
-/*
- * function for store output data used by mpq_pkzip "implode" and
- * "explode" as userdefined callback.
- *
- * char *buf - pointer to data to be written.
- * uint32_t *size - number of bytes to write.
- * void *param - custom pointer, parameter of implode/explode.
- */
-static void data_write_output(char *buf, uint32_t *size, void *param) {
-
- /* some common variables. */
- pkzip_data_s *info = (pkzip_data_s *)param;
- uint32_t max_write = (info->max_out - info->out_pos);
- uint32_t to_write = *size;
-
- /* check the case when not enough space in the output buffer. */
- if (to_write > max_write) {
- to_write = max_write;
- }
-
- /* write output data and increments offsets. */
- memcpy(info->out_buf + info->out_pos, buf, to_write);
- info->out_pos += to_write;
-}
-
-/* this function extract the data from input stream. */
-static uint32_t expand(pkzip_cmp_s *mpq_pkzip) {
-
- /* number of bytes to copy. */
- uint32_t copy_bytes;
-
- /* one byte from compressed file. */
- uint32_t one_byte;
-
- /* some common variables. */
- uint32_t result;
-
- /* initialize output buffer position. */
- mpq_pkzip->out_pos = 0x1000;
-
- /* check if end of data or error, so terminate decompress. */
- while ((result = one_byte = decode_literal(mpq_pkzip)) < 0x305) {
-
- /* check if one byte is greater than 0x100, which means 'repeat n - 0xFE bytes'. */
- if (one_byte >= 0x100) {
-
- /* ECX */
- uint8_t *source;
-
- /* EDX */
- uint8_t *target;
-
- /* some common variables. */
- uint32_t copy_length = one_byte - 0xFE;
- uint32_t move_back;
-
- /* get length of data to copy. */
- if ((move_back = decode_distance(mpq_pkzip, copy_length)) == 0) {
- result = 0x306;
- break;
- }
-
- /* target and source pointer. */
- target = &mpq_pkzip->out_buf[mpq_pkzip->out_pos];
- source = target - move_back;
- mpq_pkzip->out_pos += copy_length;
-
- /* copy until nothing left. */
- while (copy_length-- > 0) {
- *target++ = *source++;
- }
- } else {
-
- /* byte is 0x100 great, so add one byte. */
- mpq_pkzip->out_buf[mpq_pkzip->out_pos++] = (uint8_t)one_byte;
- }
-
- /* check if number of extracted bytes has reached 1/2 of output buffer, so flush output buffer. */
- if (mpq_pkzip->out_pos >= 0x2000) {
-
- /* copy decompressed data into user buffer. */
- copy_bytes = 0x1000;
- mpq_pkzip->write_buf((char *)&mpq_pkzip->out_buf[0x1000], &copy_bytes, mpq_pkzip->param);
-
- /* check if there are some data left, keep them alive. */
- memcpy(mpq_pkzip->out_buf, &mpq_pkzip->out_buf[0x1000], mpq_pkzip->out_pos - 0x1000);
- mpq_pkzip->out_pos -= 0x1000;
- }
- }
-
- /* copy the rest. */
- copy_bytes = mpq_pkzip->out_pos - 0x1000;
- mpq_pkzip->write_buf((char *)&mpq_pkzip->out_buf[0x1000], &copy_bytes, mpq_pkzip->param);
-
- /* return copied bytes. */
- return result;
-}
-
-/* this function explode the data stream. */
-uint32_t libmpq__do_decompress_pkzip(uint8_t *work_buf, void *param) {
-
- /* some common variables. */
- pkzip_cmp_s *mpq_pkzip = (pkzip_cmp_s *)work_buf;
-
- /* set the whole work buffer to zeros. */
- memset(mpq_pkzip, 0, sizeof(pkzip_cmp_s));
-
- /* initialize work struct and load compressed data. */
- mpq_pkzip->read_buf = data_read_input;
- mpq_pkzip->write_buf = data_write_output;
- mpq_pkzip->param = param;
- mpq_pkzip->in_pos = sizeof(mpq_pkzip->in_buf);
- mpq_pkzip->in_bytes = mpq_pkzip->read_buf((char *)mpq_pkzip->in_buf, &mpq_pkzip->in_pos, mpq_pkzip->param);
-
- /* check if we have pkzip data. */
- if (mpq_pkzip->in_bytes <= 4) {
- return LIBMPQ_PKZIP_CMP_BAD_DATA;
- }
-
- /* get the compression type. */
- mpq_pkzip->cmp_type = mpq_pkzip->in_buf[0];
-
- /* get the dictionary size. */
- mpq_pkzip->dsize_bits = mpq_pkzip->in_buf[1];
-
- /* initialize 16-bit bit buffer. */
- mpq_pkzip->bit_buf = mpq_pkzip->in_buf[2];
-
- /* extra (over 8) bits. */
- mpq_pkzip->extra_bits = 0;
-
- /* position in input buffer. */
- mpq_pkzip->in_pos = 3;
-
- /* check if valid dictionary size. */
- if (4 > mpq_pkzip->dsize_bits || mpq_pkzip->dsize_bits > 6) {
- return LIBMPQ_PKZIP_CMP_INV_DICTSIZE;
- }
-
- /* shifted by 'sar' instruction. */
- mpq_pkzip->dsize_mask = 0xFFFF >> (0x10 - mpq_pkzip->dsize_bits);
-
- /* check if we are using binary compression. */
- if (mpq_pkzip->cmp_type != LIBMPQ_PKZIP_CMP_BINARY) {
-
- /* check if we are using ascii compression. */
- if (mpq_pkzip->cmp_type != LIBMPQ_PKZIP_CMP_ASCII) {
- return LIBMPQ_PKZIP_CMP_INV_MODE;
- }
-
- /* create ascii buffer. */
- memcpy(mpq_pkzip->bits_asc, pkzip_bits_asc, sizeof(mpq_pkzip->bits_asc));
- generate_tables_ascii(mpq_pkzip);
- }
-
- /* create the tables for decode. */
- memcpy(mpq_pkzip->slen_bits, pkzip_slen_bits, sizeof(mpq_pkzip->slen_bits));
- generate_tables_decode(0x10, mpq_pkzip->slen_bits, pkzip_len_code, mpq_pkzip->pos2);
-
- /* create the tables for decode. */
- memcpy(mpq_pkzip->clen_bits, pkzip_clen_bits, sizeof(mpq_pkzip->clen_bits));
- memcpy(mpq_pkzip->len_base, pkzip_len_base, sizeof(mpq_pkzip->len_base));
- memcpy(mpq_pkzip->dist_bits, pkzip_dist_bits, sizeof(mpq_pkzip->dist_bits));
- generate_tables_decode(0x40, mpq_pkzip->dist_bits, pkzip_dist_code, mpq_pkzip->pos1);
-
- /* check if data extraction works. */
- if (expand(mpq_pkzip) != 0x306) {
- return LIBMPQ_PKZIP_CMP_NO_ERROR;
- }
-
- /* something failed, so return error. */
- return LIBMPQ_PKZIP_CMP_ABORT;
-}
diff --git a/dep/libmpq/libmpq/explode.h b/dep/libmpq/libmpq/explode.h
deleted file mode 100644
index 1d14dfc0e0a..00000000000
--- a/dep/libmpq/libmpq/explode.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * explode.h -- header file for pkware data decompression library
- * used by mpq-tools.
- *
- * Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
- *
- * This source was adepted from the C++ version of pklib.h included
- * in stormlib. The C++ version belongs to the following authors:
- *
- * Ladislav Zezula <ladik@zezula.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _EXPLODE_H
-#define _EXPLODE_H
-
-/* define compression constants and return values. */
-#define LIBMPQ_PKZIP_CMP_BINARY 0 /* binary compression. */
-#define LIBMPQ_PKZIP_CMP_ASCII 1 /* ascii compression. */
-#define LIBMPQ_PKZIP_CMP_NO_ERROR 0
-#define LIBMPQ_PKZIP_CMP_INV_DICTSIZE 1
-#define LIBMPQ_PKZIP_CMP_INV_MODE 2
-#define LIBMPQ_PKZIP_CMP_BAD_DATA 3
-#define LIBMPQ_PKZIP_CMP_ABORT 4
-
-#include "pack_begin.h"
-/* compression structure. */
-typedef struct {
- uint32_t offs0000; /* 0000 - start. */
- uint32_t cmp_type; /* 0004 - compression type (binary or ascii). */
- uint32_t out_pos; /* 0008 - position in output buffer. */
- uint32_t dsize_bits; /* 000C - dict size (4, 5, 6 for 0x400, 0x800, 0x1000). */
- uint32_t dsize_mask; /* 0010 - dict size bitmask (0x0F, 0x1F, 0x3F for 0x400, 0x800, 0x1000). */
- uint32_t bit_buf; /* 0014 - 16-bit buffer for processing input data. */
- uint32_t extra_bits; /* 0018 - number of extra (above 8) bits in bit buffer. */
- uint32_t in_pos; /* 001C - position in in_buf. */
- uint32_t in_bytes; /* 0020 - number of bytes in input buffer. */
- void *param; /* 0024 - custom parameter. */
- uint32_t (*read_buf)(char *buf, uint32_t *size, void *param); /* 0028 offset.*/
- void (*write_buf)(char *buf, uint32_t *size, void *param); /* 002C offset. */
- uint8_t out_buf[0x2000]; /* 0030 - output circle buffer, starting position is 0x1000. */
- uint8_t offs_2030[0x204]; /* 2030 - whats that? */
- uint8_t in_buf[0x800]; /* 2234 - buffer for data to be decompressed. */
- uint8_t pos1[0x100]; /* 2A34 - positions in buffers. */
- uint8_t pos2[0x100]; /* 2B34 - positions in buffers. */
- uint8_t offs_2c34[0x100]; /* 2C34 - buffer. */
- uint8_t offs_2d34[0x100]; /* 2D34 - buffer. */
- uint8_t offs_2e34[0x80]; /* 2EB4 - buffer. */
- uint8_t offs_2eb4[0x100]; /* 2EB4 - buffer. */
- uint8_t bits_asc[0x100]; /* 2FB4 - buffer. */
- uint8_t dist_bits[0x40]; /* 30B4 - numbers of bytes to skip copied block length. */
- uint8_t slen_bits[0x10]; /* 30F4 - numbers of bits for skip copied block length. */
- uint8_t clen_bits[0x10]; /* 3104 - number of valid bits for copied block. */
- uint16_t len_base[0x10]; /* 3114 - buffer. */
-} PACK_STRUCT pkzip_cmp_s;
-#include "pack_end.h"
-
-/* data structure. */
-typedef struct {
- uint8_t *in_buf; /* pointer to input data buffer. */
- uint32_t in_pos; /* current offset in input data buffer. */
- int32_t in_bytes; /* number of bytes in the input buffer. */
- uint8_t *out_buf; /* pointer to output data buffer. */
- uint32_t out_pos; /* position in the output buffer. */
- int32_t max_out; /* maximum number of bytes in the output buffer. */
-} pkzip_data_s;
-
-/* decompress the stream using pkzip compression. */
-uint32_t libmpq__do_decompress_pkzip(
- uint8_t *work_buf,
- void *param
-);
-
-#endif /* _EXPLODE_H */
diff --git a/dep/libmpq/libmpq/extract.c b/dep/libmpq/libmpq/extract.c
deleted file mode 100644
index 11de1071683..00000000000
--- a/dep/libmpq/libmpq/extract.c
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * extract.c -- global extracting function for all known file compressions
- * in a mpq archive.
- *
- * Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/* generic includes. */
-#include <stdlib.h>
-#include <string.h>
-
-/* zlib includes. */
-#include <zlib.h>
-#include <bzlib.h>
-
-/* libmpq main includes. */
-#include "mpq.h"
-
-/* libmpq generic includes. */
-#include "explode.h"
-#include "extract.h"
-#include "huffman.h"
-#include "wave.h"
-
-/* table with decompression bits and functions. */
-static decompress_table_s dcmp_table[] = {
- {LIBMPQ_COMPRESSION_HUFFMAN, libmpq__decompress_huffman}, /* decompression using huffman trees. */
- {LIBMPQ_COMPRESSION_ZLIB, libmpq__decompress_zlib}, /* decompression with the zlib library. */
- {LIBMPQ_COMPRESSION_PKZIP, libmpq__decompress_pkzip}, /* decompression with pkware data compression library. */
- {LIBMPQ_COMPRESSION_BZIP2, libmpq__decompress_bzip2}, /* decompression with bzip2 library. */
- {LIBMPQ_COMPRESSION_WAVE_MONO, libmpq__decompress_wave_mono}, /* decompression for mono waves. */
- {LIBMPQ_COMPRESSION_WAVE_STEREO, libmpq__decompress_wave_stereo} /* decompression for stereo waves. */
-};
-
-/* this function decompress a stream using huffman algorithm. */
-int32_t libmpq__decompress_huffman(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) {
-
- /* TODO: make typdefs of this structs? */
- /* some common variables. */
- int32_t tb = 0;
- struct huffman_tree_s *ht;
- struct huffman_input_stream_s *is;
-
- /* allocate memory for the huffman tree. */
- if ((ht = malloc(sizeof(struct huffman_tree_s))) == NULL ||
- (is = malloc(sizeof(struct huffman_input_stream_s))) == NULL) {
-
- /* memory allocation problem. */
- return LIBMPQ_ERROR_MALLOC;
- }
-
- /* cleanup structures. */
- memset(ht, 0, sizeof(struct huffman_tree_s));
- memset(is, 0, sizeof(struct huffman_input_stream_s));
-
- /* initialize input stream. */
- is->bit_buf = *(uint32_t *)in_buf;
- in_buf += sizeof(int32_t);
- is->in_buf = (uint8_t *)in_buf;
- is->bits = 32;
-
-// TODO: add all the mallocs to init function and add function libmpq__huffman_tree_free() */
-// if ((result = libmpq__huffman_tree_init(ht, LIBMPQ_HUFF_DECOMPRESS)) < 0) {
-//
-// /* something on zlib initialization failed. */
-// return LIBMPQ_ERROR_UNPACK;
-// }
-
- /* initialize the huffman tree for decompression. */
- libmpq__huffman_tree_init(ht, LIBMPQ_HUFF_DECOMPRESS);
-
- /* save the number of copied bytes. */
- tb = libmpq__do_decompress_huffman(ht, is, out_buf, out_size);
-
- /* free structures. */
- free(is);
- free(ht);
-
- /* return transferred bytes. */
- return tb;
-}
-
-/* this function decompress a stream using zlib algorithm. */
-int32_t libmpq__decompress_zlib(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) {
-
- /* some common variables. */
- int32_t result = 0;
- int32_t tb = 0;
- z_stream z;
-
- /* fill the stream structure for zlib. */
- z.next_in = (Bytef *)in_buf;
- z.avail_in = (uInt)in_size;
- z.total_in = in_size;
- z.next_out = (Bytef *)out_buf;
- z.avail_out = (uInt)out_size;
- z.total_out = 0;
- z.zalloc = NULL;
- z.zfree = NULL;
-
- /* initialize the decompression structure, storm.dll uses zlib version 1.1.3. */
- if ((result = inflateInit(&z)) != Z_OK) {
-
- /* something on zlib initialization failed. */
- return result;
- }
-
- /* call zlib to decompress the data. */
- if ((result = inflate(&z, Z_FINISH)) != Z_STREAM_END) {
-
- /* something on zlib decompression failed. */
- return result;
- }
-
- /* save transferred bytes. */
- tb = z.total_out;
-
- /* cleanup zlib. */
- if ((result = inflateEnd(&z)) != Z_OK) {
-
- /* something on zlib finalization failed. */
- return result;
- }
-
- /* return transferred bytes. */
- return tb;
-}
-
-/* this function decompress a stream using pkzip algorithm. */
-int32_t libmpq__decompress_pkzip(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) {
-
- /* some common variables. */
- int32_t tb = 0;
- uint8_t *work_buf;
- pkzip_data_s info;
-
- /* allocate memory for pkzip data structure. */
- if ((work_buf = malloc(sizeof(pkzip_cmp_s))) == NULL) {
-
- /* memory allocation problem. */
- return LIBMPQ_ERROR_MALLOC;
- }
-
- /* cleanup. */
- memset(work_buf, 0, sizeof(pkzip_cmp_s));
-
- /* fill data information structure. */
- info.in_buf = in_buf;
- info.in_pos = 0;
- info.in_bytes = in_size;
- info.out_buf = out_buf;
- info.out_pos = 0;
- info.max_out = out_size;
-
- /* do the decompression. */
- if ((tb = libmpq__do_decompress_pkzip(work_buf, &info)) < 0) {
-
- /* free working buffer. */
- free(work_buf);
-
- /* something failed on pkzip decompression. */
- return tb;
- }
-
- /* save transferred bytes. */
- tb = info.out_pos;
-
- /* free working buffer. */
- free(work_buf);
-
- /* return transferred bytes. */
- return tb;
-}
-
-/* this function decompress a stream using bzip2 library. */
-int32_t libmpq__decompress_bzip2(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) {
-
- /* some common variables. */
- int32_t result = 0;
- int32_t tb = 0;
- bz_stream strm;
-
- /* initialize the bzlib decompression. */
- strm.bzalloc = NULL;
- strm.bzfree = NULL;
-
- /* initialize the structure. */
- if ((result = BZ2_bzDecompressInit(&strm, 0, 0)) != BZ_OK) {
-
- /* something on bzlib initialization failed. */
- return result;
- }
-
- /* fill the stream structure for bzlib. */
- strm.next_in = (char *)in_buf;
- strm.avail_in = in_size;
- strm.next_out = (char *)out_buf;
- strm.avail_out = out_size;
-
- /* do the decompression. */
- while (BZ2_bzDecompress(&strm) != BZ_STREAM_END);
-
- /* save transferred bytes. */
- tb = strm.total_out_lo32;
-
- /* cleanup of bzip stream. */
- BZ2_bzDecompressEnd(&strm);
-
- /* return transferred bytes. */
- return tb;
-}
-
-/* this function decompress a stream using wave algorithm. (1 channel) */
-int32_t libmpq__decompress_wave_mono(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) {
-
- /* some common variables. */
- int32_t tb = 0;
-
- /* save the number of copied bytes. */
- if ((tb = libmpq__do_decompress_wave(out_buf, out_size, in_buf, in_size, 1)) < 0) {
-
- /* something on wave decompression failed. */
- return tb;
- }
-
- /* return transferred bytes. */
- return tb;
-}
-
-/* this function decompress a stream using wave algorithm. (2 channels) */
-int32_t libmpq__decompress_wave_stereo(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) {
-
- /* some common variables. */
- int32_t tb = 0;
-
- /* save the number of copied bytes. */
- if ((tb = libmpq__do_decompress_wave(out_buf, out_size, in_buf, in_size, 2)) < 0) {
-
- /* something on wave decompression failed. */
- return tb;
- }
-
- /* return transferred bytes. */
- return tb;
-}
-
-/* this function decompress a stream using a combination of the other compression algorithm. */
-int32_t libmpq__decompress_multi(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) {
-
- /* some common variables. */
- int32_t tb = 0;
- uint32_t count = 0;
- uint32_t entries = (sizeof(dcmp_table) / sizeof(decompress_table_s));
- uint8_t *temp_buf = NULL;
- uint8_t *work_buf = 0;
- uint8_t decompress_flag, decompress_unsupp;
- uint32_t i;
-
- /* get applied compression types. */
- decompress_flag = decompress_unsupp = *in_buf++;
-
- /* decrement data size. */
- in_size--;
-
- /* search decompression table type and get all types of compression. */
- for (i = 0; i < entries; i++) {
-
- /* check if have to apply this decompression. */
- if (decompress_flag & dcmp_table[i].mask) {
-
- /* increase counter for used compression algorithms. */
- count++;
- /* this algorithm is supported, remove from unsupp mask */
- decompress_unsupp &= ~dcmp_table[i].mask;
- }
- }
-
- /* check if there is some method unhandled. (e.g. compressed by future versions) */
- if (decompress_unsupp) {
-
- /* compression type is unknown and we need to implement it. :) */
- return LIBMPQ_ERROR_UNPACK;
- }
-
- /* if multiple decompressions should be made, we need temporary buffer for the data. */
- if (count > 1) {
-
- /* allocate memory for temporary buffer. */
- if ((temp_buf = malloc(out_size)) == NULL) {
-
- /* memory allocation problem. */
- return LIBMPQ_ERROR_MALLOC;
- }
-
- /* cleanup. */
- memset(temp_buf, 0, out_size);
- }
-
- /* apply all decompressions. */
- for (i = 0, count = 0; i < entries; i++) {
-
- /* check if not used this kind of compression. */
- if (decompress_flag & dcmp_table[i].mask) {
-
- /* if multiple decompressions should be made, we need temporary buffer for the data. */
- if (count == 0) {
-
- /* use output buffer as working buffer. */
- work_buf = out_buf;
- } else {
-
- /* use temporary buffer as working buffer. */
- work_buf = temp_buf;
- }
-
- /* decompress buffer using corresponding function. */
- if ((tb = dcmp_table[i].decompress(in_buf, in_size, work_buf, out_size)) < 0) {
-
- /* free temporary buffer. */
- free(temp_buf);
-
- /* something on decompression failed. */
- return tb;
- }
-
- /* move output size to source size for next compression. */
- in_size = out_size;
- in_buf = work_buf;
-
- /* increase counter. */
- count++;
- }
- }
-
- /* if output buffer is not the same like target buffer, we have to copy data (this will happen on multiple decompressions). */
- if (work_buf != out_buf) {
-
- /* copy buffer. */
- memcpy(out_buf, in_buf, out_size);
- }
-
- /* free temporary buffer. */
- free(temp_buf);
-
- /* return transferred bytes. */
- return tb;
-}
diff --git a/dep/libmpq/libmpq/extract.h b/dep/libmpq/libmpq/extract.h
deleted file mode 100644
index d6ea794f162..00000000000
--- a/dep/libmpq/libmpq/extract.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * extract.h -- header for the extraction functions used by mpq-tools.
- *
- * Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _EXTRACT_H
-#define _EXTRACT_H
-
-/* define compression types for multilpe compressions. */
-#define LIBMPQ_COMPRESSION_HUFFMAN 0x01 /* huffman compression. (used on wave files only and introduced in starcraft) */
-#define LIBMPQ_COMPRESSION_ZLIB 0x02 /* zlib compression. (introduced in warcraft 3) */
-#define LIBMPQ_COMPRESSION_PKZIP 0x08 /* pkware dcl compression. (first used compression algorithm) */
-#define LIBMPQ_COMPRESSION_BZIP2 0x10 /* bzip compression. (introduced in warcraft 3 - the frozen throne) */
-#define LIBMPQ_COMPRESSION_WAVE_MONO 0x40 /* adpcm 4:1 compression. (introduced in starcraft) */
-#define LIBMPQ_COMPRESSION_WAVE_STEREO 0x80 /* adpcm 4:1 compression. (introduced in starcraft) */
-
-/*
- * table for decompression functions, return value for all functions
- * is the transferred data size or one of the following error constants:
- *
- * LIBMPQ_ERROR_MALLOC
- * LIBMPQ_ERROR_DECOMPRESS
- */
-typedef int32_t (*DECOMPRESS)(uint8_t *, uint32_t, uint8_t *, uint32_t);
-typedef struct {
- uint32_t mask; /* decompression bit. */
- DECOMPRESS decompress; /* decompression function. */
-} decompress_table_s;
-
-/*
- * huffman decompression routine, the in_size parameter is not used,
- * but needs to be specified due to compatibility reasons.
- *
- * 1500F5F0
- */
-extern int32_t libmpq__decompress_huffman(
- uint8_t *in_buf,
- uint32_t in_size,
- uint8_t *out_buf,
- uint32_t out_size
-);
-
-/* decompression using zlib. */
-extern int32_t libmpq__decompress_zlib(
- uint8_t *in_buf,
- uint32_t in_size,
- uint8_t *out_buf,
- uint32_t out_size
-);
-
-/* decompression using pkzip. */
-extern int32_t libmpq__decompress_pkzip(
- uint8_t *in_buf,
- uint32_t in_size,
- uint8_t *out_buf,
- uint32_t out_size
-);
-
-/* decompression using bzip2. */
-extern int32_t libmpq__decompress_bzip2(
- uint8_t *in_buf,
- uint32_t in_size,
- uint8_t *out_buf,
- uint32_t out_size
-);
-
-/* decompression using wave. (1 channel) */
-extern int32_t libmpq__decompress_wave_mono(
- uint8_t *in_buf,
- uint32_t in_size,
- uint8_t *out_buf,
- uint32_t out_size
-);
-
-/* decompression using wave. (2 channels) */
-extern int32_t libmpq__decompress_wave_stereo(
- uint8_t *in_buf,
- uint32_t in_size,
- uint8_t *out_buf,
- uint32_t out_size
-);
-
-/* decompression using multiple of the above algorithm. */
-extern int32_t libmpq__decompress_multi(
- uint8_t *in_buf,
- uint32_t in_size,
- uint8_t *out_buf,
- uint32_t out_size
-);
-
-#endif /* _EXTRACT_H */
diff --git a/dep/libmpq/libmpq/huffman.c b/dep/libmpq/libmpq/huffman.c
deleted file mode 100644
index 8fc87be2f60..00000000000
--- a/dep/libmpq/libmpq/huffman.c
+++ /dev/null
@@ -1,1101 +0,0 @@
-/*
- * huffman.c -- functions do decompress files in mpq files which
- * uses a modified huffman version.
- *
- * Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
- *
- * Differences between C++ and C version:
- *
- * - Removed the object oriented stuff.
- * - Replaced the goto things with some better C code.
- *
- * This source was adepted from the C++ version of huffman.cpp included
- * in stormlib. The C++ version belongs to the following authors:
- *
- * Ladislav Zezula <ladik@zezula.net>
- * ShadowFlare <BlakFlare@hotmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/* generic includes. */
-#include <stdlib.h>
-#include <string.h>
-
-/* libmpq main includes. */
-#include "mpq.h"
-#include "mpq-internal.h"
-
-/* libmpq generic includes. */
-#include "huffman.h"
-
-/* tables for huffman tree. */
-static const uint8_t table_1502A630[] = {
-
- /* data for compression type 0x00. */
- 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
- 0x00, 0x00,
-
- /* data for compression type 0x01. */
- 0x54, 0x16, 0x16, 0x0D, 0x0C, 0x08, 0x06, 0x05, 0x06, 0x05, 0x06, 0x03, 0x04, 0x04, 0x03, 0x05,
- 0x0E, 0x0B, 0x14, 0x13, 0x13, 0x09, 0x0B, 0x06, 0x05, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02,
- 0x0D, 0x07, 0x09, 0x06, 0x06, 0x04, 0x03, 0x02, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02,
- 0x09, 0x06, 0x04, 0x04, 0x04, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x04,
- 0x08, 0x03, 0x04, 0x07, 0x09, 0x05, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02,
- 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02,
- 0x06, 0x0A, 0x08, 0x08, 0x06, 0x07, 0x04, 0x03, 0x04, 0x04, 0x02, 0x02, 0x04, 0x02, 0x03, 0x03,
- 0x04, 0x03, 0x07, 0x07, 0x09, 0x06, 0x04, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x0A, 0x02, 0x02, 0x03, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x03, 0x05, 0x02, 0x03,
- 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x01, 0x01, 0x01,
- 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x04, 0x04, 0x07, 0x09, 0x08, 0x0C, 0x02,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03,
- 0x04, 0x01, 0x02, 0x04, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
- 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x4B,
- 0x00, 0x00,
-
- /* data for compression type 0x02. */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x27, 0x00, 0x00, 0x23, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x06, 0x0E, 0x10, 0x04,
- 0x06, 0x08, 0x05, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x01, 0x01, 0x02, 0x01, 0x01,
- 0x01, 0x04, 0x02, 0x04, 0x02, 0x02, 0x02, 0x01, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x03, 0x02,
- 0x03, 0x01, 0x03, 0x06, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01,
- 0x01, 0x29, 0x07, 0x16, 0x12, 0x40, 0x0A, 0x0A, 0x11, 0x25, 0x01, 0x03, 0x17, 0x10, 0x26, 0x2A,
- 0x10, 0x01, 0x23, 0x23, 0x2F, 0x10, 0x06, 0x07, 0x02, 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-
- /* data for compression type 0x03. */
- 0xFF, 0x0B, 0x07, 0x05, 0x0B, 0x02, 0x02, 0x02, 0x06, 0x02, 0x02, 0x01, 0x04, 0x02, 0x01, 0x03,
- 0x09, 0x01, 0x01, 0x01, 0x03, 0x04, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
- 0x05, 0x01, 0x01, 0x01, 0x0D, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x02, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
- 0x0A, 0x04, 0x02, 0x01, 0x06, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01,
- 0x05, 0x02, 0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x03, 0x03,
- 0x01, 0x03, 0x01, 0x01, 0x02, 0x05, 0x01, 0x01, 0x04, 0x03, 0x05, 0x01, 0x03, 0x01, 0x03, 0x03,
- 0x02, 0x01, 0x04, 0x03, 0x0A, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x02, 0x02, 0x01, 0x0A, 0x02, 0x05, 0x01, 0x01, 0x02, 0x07, 0x02, 0x17, 0x01, 0x05, 0x01, 0x01,
- 0x0E, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x06, 0x02, 0x01, 0x04, 0x05, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
- 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11,
- 0x00, 0x00,
-
- /* data for compression type 0x04. */
- 0xFF, 0xFB, 0x98, 0x9A, 0x84, 0x85, 0x63, 0x64, 0x3E, 0x3E, 0x22, 0x22, 0x13, 0x13, 0x18, 0x17,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-
- /* data for compression type 0x05. */
- 0xFF, 0xF1, 0x9D, 0x9E, 0x9A, 0x9B, 0x9A, 0x97, 0x93, 0x93, 0x8C, 0x8E, 0x86, 0x88, 0x80, 0x82,
- 0x7C, 0x7C, 0x72, 0x73, 0x69, 0x6B, 0x5F, 0x60, 0x55, 0x56, 0x4A, 0x4B, 0x40, 0x41, 0x37, 0x37,
- 0x2F, 0x2F, 0x27, 0x27, 0x21, 0x21, 0x1B, 0x1C, 0x17, 0x17, 0x13, 0x13, 0x10, 0x10, 0x0D, 0x0D,
- 0x0B, 0x0B, 0x09, 0x09, 0x08, 0x08, 0x07, 0x07, 0x06, 0x05, 0x05, 0x04, 0x04, 0x04, 0x19, 0x18,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-
- /* data for compression type 0x06. */
- 0xC3, 0xCB, 0xF5, 0x41, 0xFF, 0x7B, 0xF7, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xBF, 0xCC, 0xF2, 0x40, 0xFD, 0x7C, 0xF7, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7A, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-
- /* data for compression type 0x07. */
- 0xC3, 0xD9, 0xEF, 0x3D, 0xF9, 0x7C, 0xE9, 0x1E, 0xFD, 0xAB, 0xF1, 0x2C, 0xFC, 0x5B, 0xFE, 0x17,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xBD, 0xD9, 0xEC, 0x3D, 0xF5, 0x7D, 0xE8, 0x1D, 0xFB, 0xAE, 0xF0, 0x2C, 0xFB, 0x5C, 0xFF, 0x18,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x70, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-
- /* data for compression type 0x08. */
- 0xBA, 0xC5, 0xDA, 0x33, 0xE3, 0x6D, 0xD8, 0x18, 0xE5, 0x94, 0xDA, 0x23, 0xDF, 0x4A, 0xD1, 0x10,
- 0xEE, 0xAF, 0xE4, 0x2C, 0xEA, 0x5A, 0xDE, 0x15, 0xF4, 0x87, 0xE9, 0x21, 0xF6, 0x43, 0xFC, 0x12,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xB0, 0xC7, 0xD8, 0x33, 0xE3, 0x6B, 0xD6, 0x18, 0xE7, 0x95, 0xD8, 0x23, 0xDB, 0x49, 0xD0, 0x11,
- 0xE9, 0xB2, 0xE2, 0x2B, 0xE8, 0x5C, 0xDD, 0x15, 0xF1, 0x87, 0xE7, 0x20, 0xF7, 0x44, 0xFF, 0x13,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5F, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00
-};
-
-/* this function insert an item to a huffman tree. */
-void libmpq__huffman_insert_item(struct huffman_tree_item_s **p_item, struct huffman_tree_item_s *item, uint32_t where, struct huffman_tree_item_s *item2) {
-
- /* EDI - next to the first item. */
- struct huffman_tree_item_s *next = item->next;
-
- /* ESI - prev to the first item. */
- struct huffman_tree_item_s *prev = item->prev;
-
- /* pointer to previous item. */
- struct huffman_tree_item_s *prev2;
-
- /* pointer to next item. */
- long next2;
-
- /* check the first item already has next one. */
- if (next != 0) {
-
- /* check if previous item exist. */
- if (PTR_INT(prev) < 0) {
-
- /* return previous item. */
- prev = PTR_NOT(prev);
- } else {
-
- /* add item. */
- prev += (item - next->prev);
- }
-
- /* 150083C1 - remove the item from the tree. */
- prev->next = next;
- next->prev = prev;
-
- /* invalidate prev and next pointer. */
- item->next = 0;
- item->prev = 0;
- }
-
- /* EDX - check if the second item is not entered. */
- if (item2 == NULL) {
-
- /* take the first tree item. */
- item2 = PTR_PTR(&p_item[1]);
- }
-
- /* check if items should be switched or new one inserted. */
- switch (where) {
- case SWITCH_ITEMS:
-
- /* item2->next (pointer to pointer to first). */
- item->next = item2->next;
- item->prev = item2->next->prev;
- item2->next->prev = item;
-
- /* set the first item. */
- item2->next = item;
-
- /* return from function. */
- return;
- case INSERT_ITEM:
-
- /* set next item (or pointer to pointer to first item) - insert as last item. */
- item->next = item2;
-
- /* set previous item (or last item in the tree). */
- item->prev = item2->prev;
-
- /* usually NULL. */
- next2 = PTR_INT(p_item[0]);
-
- /* previous item to the second (or last tree item). */
- prev2 = item2->prev;
-
- /* check if previous item is a valid pointer. */
- if (PTR_INT(prev2) < 0) {
-
- /* set values. */
- prev2 = PTR_NOT(prev);
- prev2->next = item;
-
- /* next after last item. */
- item2->prev = item;
-
- /* return from function. */
- return;
- }
-
- /* check if next item is empty. */
- if (next2 < 0) {
-
- /* set next item. */
- next2 = item2 - item2->next->prev;
- }
-
- /* add next item to previous one. */
- prev2 += next2;
- prev2->next = item;
-
- /* set the next and last item. */
- item2->prev = item;
-
- /* return from function. */
- return;
- default:
-
- /* nothing to do, so return from function. */
- return;
- }
-}
-
-/* 1500BC90 - remove item from huffman tree.*/
-void libmpq__huffman_remove_item(struct huffman_tree_item_s *hi) {
-
- /* EDX - some common variables. */
- struct huffman_tree_item_s *temp;
-
- /* check if next item is not empty. */
- if (hi->next != NULL) {
-
- /* fetch previous item. */
- temp = hi->prev;
-
- /* check if previous item is a pointer. */
- if (PTR_INT(temp) <= 0) {
- temp = PTR_NOT(temp);
- } else {
- temp += (hi - hi->next->prev);
- }
-
- /* reorganize tree. */
- temp->next = hi->next;
- hi->next->prev = hi->prev;
- hi->next = hi->prev = NULL;
- }
-}
-
-/* get previous huffman tree item. */
-struct huffman_tree_item_s *libmpq__huffman_previous_item(struct huffman_tree_item_s *hi, long value) {
-
- /* check if previous item exist. */
- if (PTR_INT(hi->prev) < 0) {
-
- /* return previous item. */
- return PTR_NOT(hi->prev);
- }
-
- /* check if something else should returned. */
- if (value < 0) {
-
- /* fetch previous item of next item. */
- value = hi - hi->next->prev;
- }
-
- /* return previous item with value. */
- return hi->prev + value;
-}
-
-/* get one bit from input stream. */
-uint32_t libmpq__huffman_get_1bit(struct huffman_input_stream_s *is) {
-
- /* some common variables. */
- uint32_t bit = (is->bit_buf & 1);
-
- /* shift bit right by one. */
- is->bit_buf >>= 1;
-
- /* check if we should extract bits. */
- if (--is->bits == 0) {
- is->bit_buf = *(uint32_t *)is->in_buf;
- is->in_buf += sizeof(int32_t);
- is->bits = 32;
- }
-
- /* return the bit. */
- return bit;
-}
-
-/* get 7 bits from the input stream. */
-uint32_t libmpq__huffman_get_7bit(struct huffman_input_stream_s *is) {
-
- /* check if we should extract bits. */
- if (is->bits <= 7) {
- is->bit_buf |= *(uint16_t *)is->in_buf << is->bits;
- is->in_buf += sizeof(int16_t);
- is->bits += 16;
- }
-
- /* get 7 bits from input stream. */
- return (is->bit_buf & 0x7F);
-}
-
-/* get the whole byte from the input stream. */
-uint32_t libmpq__huffman_get_8bit(struct huffman_input_stream_s *is) {
-
- /* some common variables. */
- uint32_t one_byte;
-
- /* check if we should extract bits. */
- if (is->bits <= 8) {
- is->bit_buf |= *(uint16_t *)is->in_buf << is->bits;
- is->in_buf += sizeof(int16_t);
- is->bits += 16;
- }
-
- /* fill values. */
- one_byte = (is->bit_buf & 0xFF);
- is->bit_buf >>= 8;
- is->bits -= 8;
-
- /* return the 8 bits. */
- return one_byte;
-}
-
-/* return struct for 1500E740. */
-struct huffman_tree_item_s *libmpq__huffman_call_1500E740(struct huffman_tree_s *ht) {
-
- /* EDX */
- struct huffman_tree_item_s *p_item1 = ht->item3058;
-
- /* EAX */
- struct huffman_tree_item_s *p_item2;
-
- /* some common variables. */
- struct huffman_tree_item_s *p_next;
- struct huffman_tree_item_s *p_prev;
- struct huffman_tree_item_s **pp_item;
-
- /* check if item is empty. */
- if (PTR_INT(p_item1) <= 0 || (p_item2 = p_item1) == NULL) {
-
- /* check if item is not empty. */
- if ((p_item2 = &ht->items0008[ht->items++]) != NULL) {
- p_item1 = p_item2;
- } else {
- p_item1 = ht->first;
- }
- } else {
- p_item1 = p_item2;
- }
-
- /* set next item. */
- p_next = p_item1->next;
-
- /* check if next item is not empty. */
- if (p_next != NULL) {
-
- /* set previous item. */
- p_prev = p_item1->prev;
-
- /* check if previous item is a valid pointer. */
- if (PTR_INT(p_prev) <= 0) {
- p_prev = PTR_NOT(p_prev);
- } else {
- p_prev += (p_item1 - p_item1->next->prev);
- }
-
- /* fill values. */
- p_prev->next = p_next;
- p_next->prev = p_prev;
- p_item1->next = NULL;
- p_item1->prev = NULL;
- }
-
- /* ESI */
- pp_item = &ht->first;
- p_item1->next = (struct huffman_tree_item_s *)pp_item;
- p_item1->prev = pp_item[1];
-
- /* EDI = ht->item305C - ECX */
- p_prev = pp_item[1];
-
- /* check if previous pointer is valid. */
- if (p_prev <= 0) {
-
- /* fill values. */
- p_prev = PTR_NOT(p_prev);
- p_prev->next = p_item1;
- p_prev->prev = p_item2;
- p_item2->parent = NULL;
- p_item2->child = NULL;
- } else {
-
- /* check if pointer is valid. */
- if (PTR_INT(ht->item305C) < 0) {
- p_prev += (struct huffman_tree_item_s *)pp_item - (*pp_item)->prev;
- } else {
- p_prev += PTR_INT(ht->item305C);
- }
-
- /* fill values. */
- p_prev->next = p_item1;
- pp_item[1] = p_item2;
- p_item2->parent = NULL;
- p_item2->child = NULL;
- }
-
- /* return item. */
- return p_item2;
-}
-
-/* return struct for 1500E820. */
-void libmpq__huffman_call_1500E820(struct huffman_tree_s *ht, struct huffman_tree_item_s *p_item) {
-
- /* EDI */
- struct huffman_tree_item_s *p_item1;
-
- /* EAX */
- struct huffman_tree_item_s *p_item2 = NULL;
-
- /* EDX */
- struct huffman_tree_item_s *p_item3;
-
- /* EBX */
- struct huffman_tree_item_s *p_prev;
-
- /* loop through parent items. */
- for (; p_item != NULL; p_item = p_item->parent) {
-
- /* increase byte counter. */
- p_item->byte_value++;
-
- /* loop through previous items. */
- for (p_item1 = p_item; ; p_item1 = p_prev) {
-
- /* set previous item. */
- p_prev = p_item1->prev;
-
- /* check if pointer is valid. */
- if (PTR_INT(p_prev) <= 0) {
- p_prev = NULL;
- break;
- }
-
- /* check if byte value of previous item is higher than actual item. */
- if (p_prev->byte_value >= p_item->byte_value) {
- break;
- }
- }
-
- /* check if previous item is same like actual item. */
- if (p_item1 == p_item) {
- continue;
- }
-
- /* check if next item is not empty, */
- if (p_item1->next != NULL) {
-
- /* fill values. */
- p_item2 = libmpq__huffman_previous_item(p_item1, -1);
- p_item2->next = p_item1->next;
- p_item1->next->prev = p_item1->prev;
- p_item1->next = NULL;
- p_item1->prev = NULL;
- }
-
- /* fill values. */
- p_item2 = p_item->next;
- p_item1->next = p_item2;
- p_item1->prev = p_item2->prev;
- p_item2->prev = p_item1;
- p_item->next = p_item1;
-
- /* check if both items are not empty. */
- if ((p_item2 = p_item1) != NULL) {
-
- /* fill values. */
- p_item2 = libmpq__huffman_previous_item(p_item, -1);
- p_item2->next = p_item->next;
- p_item->next->prev = p_item->prev;
- p_item->next = NULL;
- p_item->prev = NULL;
- }
-
- /* check if previous item is empty. */
- if (p_prev == NULL) {
- p_prev = PTR_PTR(&ht->first);
- }
-
- /* fill values. */
- p_item2 = p_prev->next;
- p_item->next = p_item2;
- p_item->prev = p_item2->prev;
- p_item2->prev = p_item;
- p_prev->next = p_item;
- p_item3 = p_item1->parent->child;
- p_item2 = p_item->parent;
-
- /* check if child item and parent item match. */
- if (p_item2->child == p_item) {
- p_item2->child = p_item1;
- }
-
- /* check if items match. */
- if (p_item3 == p_item1) {
- p_item1->parent->child = p_item;
- }
-
- /* fill values. */
- p_item2 = p_item->parent;
- p_item->parent = p_item1->parent;
- p_item1->parent = p_item2;
-
- /* increase counter. */
- ht->offs0004++;
- }
-}
-
-/* this function initialize a huffman tree. */
-void libmpq__huffman_tree_init(struct huffman_tree_s *ht, uint32_t cmp) {
-
- /* some common variables. */
- uint32_t count;
- struct huffman_tree_item_s *hi;
-
- /* clear links for all the items in the tree. */
- for (hi = ht->items0008, count = 0x203; count != 0; hi++, count--) {
- hi->next = hi->prev = NULL;
- }
-
- /* fill values. */
- ht->item3050 = NULL;
- ht->item3054 = PTR_PTR(&ht->item3054);
- ht->item3058 = PTR_NOT(ht->item3054);
- ht->item305C = NULL;
- ht->first = PTR_PTR(&ht->first);
- ht->last = PTR_NOT(ht->first);
- ht->offs0004 = 1;
- ht->items = 0;
-
- /* clear all huffman decompress items, do this only if preparing for decompression. */
- if (cmp == LIBMPQ_HUFF_DECOMPRESS) {
- for (count = 0; count < sizeof(ht->qd3474) / sizeof(struct huffman_decompress_s); count++) {
- ht->qd3474[count].offs00 = 0;
- }
- }
-}
-
-/* this function build a huffman tree, called with the first 8 bits loaded from input stream. */
-void libmpq__huffman_tree_build(struct huffman_tree_s *ht, uint32_t cmp_type) {
-
- /* [ESP+10] - the greatest character found in table. */
- uint32_t max_byte;
-
- /* [ESP+1C] - pointer to uint8_t in table_1502A630. */
- const uint8_t *byte_array;
-
- /* thats needed to replace the goto stuff from original source. :) */
- uint32_t found;
-
- /* [ESP+14] - Pointer to Huffman tree item pointer array. */
- struct huffman_tree_item_s **p_item;
- struct huffman_tree_item_s *child1;
-
- /* some common variables. */
- uint32_t i;
-
- /* ESI - loop while pointer has a negative value (last entry). */
- while (PTR_INT(ht->last) > 0) {
-
- /* EAX */
- struct huffman_tree_item_s *temp;
-
- /* ESI->next */
- if (ht->last->next != NULL) {
- libmpq__huffman_remove_item(ht->last);
- }
-
- /* [EDI+4] */
- ht->item3058 = PTR_PTR(&ht->item3054);
-
- /* EAX */
- ht->last->prev = ht->item3058;
- temp = libmpq__huffman_previous_item(PTR_PTR(&ht->item3054), PTR_INT(&ht->item3050));
- temp->next = ht->last;
- ht->item3054 = ht->last;
- }
-
- /* clear all pointers in huffman tree item array. */
- memset(ht->items306C, 0, sizeof(ht->items306C));
-
- /* greatest character found init to zero. */
- max_byte = 0;
-
- /* pointer to current entry in huffman tree item pointer array. */
- p_item = (struct huffman_tree_item_s **)&ht->items306C;
-
- /* ensure we have low 8 bits only. */
- cmp_type &= 0xFF;
-
- /* EDI also. */
- byte_array = table_1502A630 + cmp_type * 258;
-
- /* loop to build huffman tree. */
- for (i = 0; i < 0x100; i++, p_item++) {
-
- /* item to be created. */
- struct huffman_tree_item_s *item = ht->item3058;
- struct huffman_tree_item_s *p_item3 = ht->item3058;
- uint8_t one_byte = byte_array[i];
-
- /* skip all the bytes which are zero. */
- if (byte_array[i] == 0) {
- continue;
- }
-
- /* if not valid pointer, take the first available item in the array. */
- if (PTR_INT(item) <= 0) {
- item = &ht->items0008[ht->items++];
- }
-
- /* insert this item as the top of the tree. */
- libmpq__huffman_insert_item(&ht->item305C, item, SWITCH_ITEMS, NULL);
-
- /* invalidate child and parent. */
- item->parent = NULL;
- item->child = NULL;
-
- /* store pointer into pointer array. */
- *p_item = item;
-
- /* store counter. */
- item->dcmp_byte = i;
-
- /* store byte value. */
- item->byte_value = one_byte;
-
- /* check if byte is to big. */
- if (one_byte >= max_byte) {
-
- /* set max byte to highest value. */
- max_byte = one_byte;
-
- /* continue loop. */
- continue;
- }
-
- /* find the first item which has byte value greater than current one byte. */
- found = 0;
-
- /* EDI - Pointer to the last item. */
- if (PTR_INT((p_item3 = ht->last)) > 0) {
-
- /* 15006AF7 */
- if (p_item3 != NULL) {
-
- /* 15006AFB */
- do {
-
- /* check if we found item. */
- if (p_item3->byte_value >= one_byte) {
- found = 1;
- break;
- }
-
- /* switch to previous item. */
- p_item3 = p_item3->prev;
- } while (PTR_INT(p_item3) > 0);
- }
- }
-
- /* check if item was not found. */
- if (found == 0) {
- p_item3 = NULL;
- }
-
- /* 15006B09 */
- if (item->next != NULL) {
- libmpq__huffman_remove_item(item);
- }
-
- /* 15006B15 */
- if (p_item3 == NULL) {
- p_item3 = PTR_PTR(&ht->first);
- }
-
- /* 15006B1F */
- item->next = p_item3->next;
- item->prev = p_item3->next->prev;
- p_item3->next->prev = item;
- p_item3->next = item;
- }
-
- /* 15006B4A */
- for (; i < 0x102; i++) {
-
- /* EDI */
- struct huffman_tree_item_s **p_item2 = &ht->items306C[i];
-
- /* 15006B59 - ESI */
- struct huffman_tree_item_s *item2 = ht->item3058;
-
- /* check if item is a valid pointer. */
- if (PTR_INT(item2) <= 0) {
- item2 = &ht->items0008[ht->items++];
- }
-
- /* insert the item into tree. */
- libmpq__huffman_insert_item(&ht->item305C, item2, INSERT_ITEM, NULL);
-
- /* 15006B89 */
- item2->dcmp_byte = i;
- item2->byte_value = 1;
- item2->parent = NULL;
- item2->child = NULL;
- *p_item2++ = item2;
- }
-
- /* 15006BAA - EDI - last item (first child to item). */
- if (PTR_INT((child1 = ht->last)) > 0) {
-
- /* EBP */
- struct huffman_tree_item_s *child2;
-
- /* ESI */
- struct huffman_tree_item_s *item;
-
- /* 15006BB8 */
- while (PTR_INT((child2 = child1->prev)) > 0) {
- if (PTR_INT((item = ht->item3058)) <= 0) {
- item = &ht->items0008[ht->items++];
- }
-
- /* 15006BE3 */
- libmpq__huffman_insert_item(&ht->item305C, item, SWITCH_ITEMS, NULL);
-
- /* 15006BF3 */
- item->parent = NULL;
- item->child = NULL;
-
- /*
- * EDX = child2->byte_value + child1->byte_value;
- * EAX = child1->byte_value;
- * ECX = max_byte; (the greatest character (0xFF usually))
- * item->byte_value (0x02 usually)
- */
- item->byte_value = child1->byte_value + child2->byte_value;
-
- /* previous item in the tree. */
- item->child = child1;
- child1->parent = item;
- child2->parent = item;
-
- /* EAX = item->byte_value */
- if (item->byte_value >= max_byte) {
- max_byte = item->byte_value;
- } else {
-
- /* EDI */
- struct huffman_tree_item_s *p_item2 = child2->prev;
- found = 0;
-
- /* check if item is a valid pointer. */
- if (PTR_INT(p_item2) > 0) {
-
- /* 15006C2D */
- do {
-
- /* check if we found item. */
- if (p_item2->byte_value >= item->byte_value) {
- found = 1;
- break;
- }
-
- /* switch to previous item. */
- p_item2 = p_item2->prev;
- } while (PTR_INT(p_item2) > 0);
- }
-
- /* check if item was not found. */
- if (found == 0) {
- p_item2 = NULL;
- }
-
- /* check if next item exist. */
- if (item->next != 0) {
-
- /* some common variables. */
- struct huffman_tree_item_s *temp4 = libmpq__huffman_previous_item(item, -1);
-
- /* zhe first item changed. */
- temp4->next = item->next;
-
- /* first->prev changed to negative value. */
- item->next->prev = item->prev;
- item->next = NULL;
- item->prev = NULL;
- }
-
- /* 15006C62 */
- if (p_item2 == NULL) {
- p_item2 = PTR_PTR(&ht->first);
- }
-
- /* set item with 0x100 byte value. */
- item->next = p_item2->next;
-
- /* set item with 0x17 byte value. */
- item->prev = p_item2->next->prev;
-
- /* changed prev of item with. */
- p_item2->next->prev = item;
- p_item2->next = item;
- }
-
- /* 15006C7B */
- if (PTR_INT((child1 = child2->prev)) <= 0) {
- break;
- }
- }
- }
-
- /* 15006C88 */
- ht->offs0004 = 1;
-}
-
-/* this function did the real decompression. */
-int32_t libmpq__do_decompress_huffman(struct huffman_tree_s *ht, struct huffman_input_stream_s *is, uint8_t *out_buf, uint32_t out_length) {
-
- /* some common variables. */
- uint32_t dcmp_byte = 0;
- uint8_t *out_pos = out_buf;
- uint32_t bit_count;
- struct huffman_decompress_s *qd;
- struct huffman_tree_item_s *p_item1;
- struct huffman_tree_item_s *p_item2;
-
- /* 8 bits loaded from input stream. */
- uint32_t n8bits;
-
- /* 7 bits loaded from input stream. */
- uint32_t n7bits;
-
- /* thats needed to replace the goto stuff from original source. :) */
- uint32_t found;
-
- /* can we use quick decompression */
- uint32_t has_qd;
-
- /* test the output length, must not be non zero. */
- if (out_length == 0) {
- return 0;
- }
-
- /* get the compression type from the input stream. */
- n8bits = libmpq__huffman_get_8bit(is);
-
- /* build the Huffman tree. */
- libmpq__huffman_tree_build(ht, n8bits);
-
- /* compression 8 bit or not? */
- ht->cmp0 = (n8bits == 0) ? TRUE : FALSE;
-
- /* loop until break. */
- for(;;) {
-
- /* get 7 bits from input stream. */
- n7bits = libmpq__huffman_get_7bit(is);
-
- /* try to use quick decompression, check huffman decompress struct for corresponding item. */
- qd = &ht->qd3474[n7bits];
-
- /* if there is a quick-pass possible (ebx). */
- has_qd = (qd->offs00 >= ht->offs0004) ? TRUE : FALSE;
-
- /* if we can use quick decompress, use it. */
- if (has_qd) {
- found = 0;
- if (qd->bits > 7) {
- is->bit_buf >>= 7;
- is->bits -= 7;
- p_item1 = qd->p_item;
- found = 1;
- }
- if (found == 0) {
- is->bit_buf >>= qd->bits;
- is->bits -= qd->bits;
- dcmp_byte = qd->dcmp_byte;
- }
- } else {
- found = 1;
- p_item1 = ht->first->next->prev;
- if (PTR_INT(p_item1) <= 0) {
- p_item1 = NULL;
- }
- }
-
- /* check if item was found. */
- if (found == 1) {
- bit_count = 0;
- p_item2 = NULL;
-
- /* loop until tree has no deeper level. */
- do {
-
- /* move down by one level. */
- p_item1 = p_item1->child;
-
- /* check if current bit is set, move to previous. */
- if (libmpq__huffman_get_1bit(is)) {
- p_item1 = p_item1->prev;
- }
-
- /* check if we are at 7th bit, save current huffman tree item. */
- if (++bit_count == 7) {
- p_item2 = p_item1;
- }
- } while (p_item1->child != NULL);
-
- /* no quick decompression. :( */
- if (has_qd == FALSE) {
-
- /* check bit counter. */
- if (bit_count > 7) {
- qd->offs00 = ht->offs0004;
- qd->bits = bit_count;
- qd->p_item = p_item2;
- } else {
- uint32_t index = n7bits & (0xFFFFFFFF >> (32 - bit_count));
- uint32_t add = (1 << bit_count);
-
- /* loop through compression. */
- for (qd = &ht->qd3474[index]; index <= 0x7F; index += add, qd += add) {
- qd->offs00 = ht->offs0004;
- qd->bits = bit_count;
- qd->dcmp_byte = p_item1->dcmp_byte;
- }
- }
- }
-
- /* set compression byte. */
- dcmp_byte = p_item1->dcmp_byte;
- }
-
- /* check if huffman tree needs to be modified. */
- if (dcmp_byte == 0x101) {
-
- /* fill values. */
- n8bits = libmpq__huffman_get_8bit(is);
- p_item1 = (ht->last <= 0) ? NULL : ht->last;
- p_item2 = libmpq__huffman_call_1500E740(ht);
- p_item2->parent = p_item1;
- p_item2->dcmp_byte = p_item1->dcmp_byte;
- p_item2->byte_value = p_item1->byte_value;
- ht->items306C[p_item2->dcmp_byte] = p_item2;
- p_item2 = libmpq__huffman_call_1500E740(ht);
- p_item2->parent = p_item1;
- p_item2->dcmp_byte = n8bits;
- p_item2->byte_value = 0;
- ht->items306C[p_item2->dcmp_byte] = p_item2;
- p_item1->child = p_item2;
-
- /* call 1500E820. */
- libmpq__huffman_call_1500E820(ht, p_item2);
-
- /* check if compression is not set. */
- if (ht->cmp0 == 0) {
- libmpq__huffman_call_1500E820(ht, ht->items306C[n8bits]);
- }
-
- /* set compression byte. */
- dcmp_byte = n8bits;
- }
-
- /* check for compression. */
- if (dcmp_byte == 0x100) {
- break;
- }
-
- /* increase position by compression byte. */
- *out_pos++ = (uint8_t)dcmp_byte;
- if (--out_length == 0) {
- break;
- }
-
- /* check if compression is not set. */
- if (ht->cmp0) {
- libmpq__huffman_call_1500E820(ht, ht->items306C[dcmp_byte]);
- }
- }
-
- /* return copied bytes. */
- return (out_pos - out_buf);
-}
diff --git a/dep/libmpq/libmpq/huffman.h b/dep/libmpq/libmpq/huffman.h
deleted file mode 100644
index 6f691088fa0..00000000000
--- a/dep/libmpq/libmpq/huffman.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * huffman.h -- structures used for huffman compression.
- *
- * Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
- *
- * This source was adepted from the C++ version of huffman.h included
- * in stormlib. The C++ version belongs to the following authors:
- *
- * Ladislav Zezula <ladik@zezula.net>
- * ShadowFlare <BlakFlare@hotmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _HUFFMAN_H
-#define _HUFFMAN_H
-
-/* define huffman compression and decompression values. */
-#define LIBMPQ_HUFF_DECOMPRESS 0 /* we want to decompress using huffman trees. */
-
-/* define pointer conversions. */
-#define PTR_NOT(ptr) (struct huffman_tree_item_s *)(~(unsigned long)(ptr))
-#define PTR_PTR(ptr) ((struct huffman_tree_item_s *)(ptr))
-#define PTR_INT(ptr) (long)(ptr)
-
-/* define item handling. */
-#define INSERT_ITEM 1 /* insert item into huffman tree. */
-#define SWITCH_ITEMS 2 /* switch items isnide huffman tree. */
-
-/* input stream for huffman decompression. */
-struct huffman_input_stream_s {
- uint8_t *in_buf; /* 00 - input data. */
- uint32_t bit_buf; /* 04 - input bit buffer. */
- uint32_t bits; /* 08 - number of bits remaining in byte. */
-};
-
-/* huffman tree item. */
-struct huffman_tree_item_s {
- struct huffman_tree_item_s *next; /* 00 - pointer to next huffman tree item. */
- struct huffman_tree_item_s *prev; /* 04 - pointer to prev huffman tree item (< 0 if none). */
- uint32_t dcmp_byte; /* 08 - index of this item in item pointer array, decompressed byte value. */
- uint32_t byte_value; /* 0C - some byte value. */
- struct huffman_tree_item_s *parent; /* 10 - pointer to parent huffman tree item (NULL if none). */
- struct huffman_tree_item_s *child; /* 14 - pointer to child huffman tree item. */
-};
-
-/* structure used for quick decompression. */
-struct huffman_decompress_s {
- uint32_t offs00; /* 00 - 1 if resolved. */
- uint32_t bits; /* 04 - bit count. */
- union {
- uint32_t dcmp_byte; /* 08 - byte value for decompress (if bitCount <= 7). */
- struct huffman_tree_item_s *p_item; /* 08 - huffman tree item (if number of bits is greater than 7). */
- };
-};
-
-/* structure for huffman tree. */
-struct huffman_tree_s {
- uint32_t cmp0; /* 0000 - 1 if compression type 0. */
- uint32_t offs0004; /* 0004 - some flag. */
- struct huffman_tree_item_s items0008[0x203]; /* 0008 - huffman tree items. */
- struct huffman_tree_item_s *item3050; /* 3050 - always NULL? */
- struct huffman_tree_item_s *item3054; /* 3054 - pointer to huffman tree item. */
- struct huffman_tree_item_s *item3058; /* 3058 - pointer to huffman tree item (< 0 if invalid). */
- struct huffman_tree_item_s *item305C; /* 305C - usually NULL. */
- struct huffman_tree_item_s *first; /* 3060 - pointer to top (first) huffman tree item. */
- struct huffman_tree_item_s *last; /* 3064 - pointer to bottom (last) huffman tree item (< 0 if invalid). */
- uint32_t items; /* 3068 - number of used huffman tree items. */
- struct huffman_tree_item_s *items306C[0x102]; /* 306C - huffman tree item pointer array. */
- struct huffman_decompress_s qd3474[0x80]; /* 3474 - array for quick decompression. */
- uint8_t table_1502A630[]; /* some table to make struct size flexible. */
-};
-
-/* insert a new item into huffman tree. */
-void libmpq__huffman_insert_item(
- struct huffman_tree_item_s **p_item,
- struct huffman_tree_item_s *item,
- uint32_t where,
- struct huffman_tree_item_s *item2
-);
-
-/* remove item from huffman tree. */
-void libmpq__huffman_remove_item(
- struct huffman_tree_item_s *hi
-);
-
-/* get previous item from huffman tree. */
-struct huffman_tree_item_s *libmpq__huffman_previous_item(
- struct huffman_tree_item_s *hi,
- long value
-);
-
-/* get one bit from stream. */
-uint32_t libmpq__huffman_get_1bit(
- struct huffman_input_stream_s *is
-);
-
-/* get seven bit from stream. */
-uint32_t libmpq__huffman_get_7bit(
- struct huffman_input_stream_s *is
-);
-
-/* get eight bit from stream. */
-uint32_t libmpq__huffman_get_8bit(
- struct huffman_input_stream_s *is
-);
-
-/* call 1500E740. */
-struct huffman_tree_item_s *libmpq__huffman_call_1500E740(
- struct huffman_tree_s *ht
-);
-
-/* call 1500E820- */
-void libmpq__huffman_call_1500E820(
- struct huffman_tree_s *ht,
- struct huffman_tree_item_s *p_item
-);
-
-/* initialize the huffman tree. */
-void libmpq__huffman_tree_init(
- struct huffman_tree_s *ht,
- uint32_t cmp
-);
-
-/* build the huffman tree. */
-void libmpq__huffman_tree_build(
- struct huffman_tree_s *ht,
- uint32_t cmp_type
-);
-
-/* decompress the stream using huffman compression. */
-int32_t libmpq__do_decompress_huffman(
- struct huffman_tree_s *ht,
- struct huffman_input_stream_s *is,
- uint8_t *out_buf,
- uint32_t out_length
-);
-
-#endif /* _HUFFMAN_H */
diff --git a/dep/libmpq/libmpq/mpq-internal.h b/dep/libmpq/libmpq/mpq-internal.h
deleted file mode 100644
index 76eabe4190a..00000000000
--- a/dep/libmpq/libmpq/mpq-internal.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * mpq-internal.h -- some default types and defines, but only required for
- * compilation of the library.
- *
- * Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _MPQ_INTERNAL_H
-#define _MPQ_INTERNAL_H
-
-/* generic includes. */
-#include <stdint.h>
-#include <stdio.h>
-
-/* define return value if nothing failed. */
-#define LIBMPQ_SUCCESS 0 /* return value for all functions which success. */
-
-/* define generic mpq archive information. */
-#define LIBMPQ_HEADER 0x1A51504D /* mpq archive header ('MPQ\x1A') */
-
-/* define the known archive versions. */
-#define LIBMPQ_ARCHIVE_VERSION_ONE 0 /* version one used until world of warcraft. */
-#define LIBMPQ_ARCHIVE_VERSION_TWO 1 /* version two used from world of warcraft - the burning crusade. */
-
-/* define values used by blizzard as flags. */
-#define LIBMPQ_FLAG_EXISTS 0x80000000 /* set if file exists, reset when the file was deleted. */
-#define LIBMPQ_FLAG_ENCRYPTED 0x00010000 /* indicates whether file is encrypted. */
-#define LIBMPQ_FLAG_COMPRESSED 0x0000FF00 /* file is compressed. */
-#define LIBMPQ_FLAG_COMPRESS_PKZIP 0x00000100 /* compression made by pkware data compression library. */
-#define LIBMPQ_FLAG_COMPRESS_MULTI 0x00000200 /* multiple compressions. */
-#define LIBMPQ_FLAG_COMPRESS_NONE 0x00000300 /* no compression (no blizzard flag used by myself). */
-#define LIBMPQ_FLAG_SINGLE 0x01000000 /* file is stored in one single sector, first seen in world of warcraft. */
-#define LIBMPQ_FLAG_CRC 0x04000000 /* compressed block offset table has CRC checksum. */
-
-/* define generic hash values. */
-#define LIBMPQ_HASH_FREE 0xFFFFFFFF /* hash table entry is empty and has always been empty. */
-
-/* define special files. */
-#define LIBMPQ_LISTFILE_NAME "(listfile)" /* internal listfile. */
-#define LIBMPQ_SIGNATURE_NAME "(signature)" /* internal signature file. */
-#define LIBMPQ_ATTRIBUTES_NAME "(attributes)" /* internal attributes file. */
-
-/* define true and false, because not all systems have them. */
-#ifndef FALSE
-#define FALSE 0
-#endif
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#include "pack_begin.h"
-/* mpq archive header. */
-typedef struct {
- uint32_t mpq_magic; /* the 0x1A51504D ('MPQ\x1A') signature. */
- uint32_t header_size; /* mpq archive header size. */
- uint32_t archive_size; /* size of mpq archive. */
- uint16_t version; /* 0000 for starcraft and broodwar. */
- uint16_t block_size; /* size of file block is (512 * 2 ^ block size). */
- uint32_t hash_table_offset; /* file position of mpq_hash. */
- uint32_t block_table_offset; /* file position of mpq_block, each entry has 16 bytes. */
- uint32_t hash_table_count; /* number of entries in hash table. */
- uint32_t block_table_count; /* number of entries in the block table. */
-} PACK_STRUCT mpq_header_s;
-
-/* mpq extended archive header, used since world of warcraft - the burning crusade. */
-typedef struct {
- uint64_t extended_offset; /* offset to the beginning of the extended block table, relative to the beginning of the archive. */
- uint16_t hash_table_offset_high; /* upper 16 bits of the hash table offset for large archives. */
- uint16_t block_table_offset_high;/* upper 16 bits of the block table offset for large archives.*/
-} PACK_STRUCT mpq_header_ex_s;
-
-/* hash entry, all files in the archive are searched by their hashes. */
-typedef struct {
- uint32_t hash_a; /* the first two uint32_ts are the encrypted file. */
- uint32_t hash_b; /* the first two uint32_ts are the encrypted file. */
- uint16_t locale; /* locale information. */
- uint16_t platform; /* platform information and zero is default. */
- uint32_t block_table_index; /* index to file description block. */
-} PACK_STRUCT mpq_hash_s;
-
-/* file description block contains informations about the file. */
-typedef struct {
- uint32_t offset; /* block file starting position in the archive. */
- uint32_t packed_size; /* packed file size. */
- uint32_t unpacked_size; /* unpacked file size. */
- uint32_t flags; /* flags. */
-} PACK_STRUCT mpq_block_s;
-
-/* extended file description block contains information about the offset beyond 2^32 (4GB). */
-typedef struct {
- uint16_t offset_high; /* upper 16 bit of the file offset in archive. */
-} PACK_STRUCT mpq_block_ex_s;
-
-/* file structure used since diablo 1.00 (0x38 bytes). */
-typedef struct {
- uint32_t seed; /* seed used for file decrypt. */
- uint32_t *packed_offset; /* position of each file block (only for packed files). */
- uint32_t open_count; /* number of times it has been opened - used for freeing */
-} PACK_STRUCT mpq_file_s;
-
-/* map structure for valid blocks and hashes (first seen in warcraft 3 archives). */
-typedef struct {
- uint32_t block_table_indices; /* real mapping for file number to block entry. */
- uint32_t block_table_diff; /* block table difference between valid blocks and invalid blocks before. */
-} PACK_STRUCT mpq_map_s;
-#include "pack_end.h"
-
-/* archive structure used since diablo 1.00 by blizzard. */
-struct mpq_archive {
-
- /* generic file information. */
- FILE *fp; /* file handle. */
-
- /* generic size information. */
- uint32_t block_size; /* size of the mpq block. */
- off_t archive_offset; /* absolute start position of archive. */
-
- /* archive related buffers and tables. */
- mpq_header_s mpq_header; /* mpq file header. */
- mpq_header_ex_s mpq_header_ex; /* mpq extended file header. */
- mpq_hash_s *mpq_hash; /* hash table. */
- mpq_block_s *mpq_block; /* block table. */
- mpq_block_ex_s *mpq_block_ex; /* extended block table. */
- mpq_file_s **mpq_file; /* pointer to the file pointers which are opened. */
-
- /* non archive structure related members. */
- mpq_map_s *mpq_map; /* map table between valid blocks and hashes. */
- uint32_t files; /* number of files in archive, which could be extracted. */
-};
-
-#endif /* _MPQ_INTERNAL_H */
diff --git a/dep/libmpq/libmpq/mpq.c b/dep/libmpq/libmpq/mpq.c
deleted file mode 100644
index a6ab5db82d9..00000000000
--- a/dep/libmpq/libmpq/mpq.c
+++ /dev/null
@@ -1,1004 +0,0 @@
-/*
- * mpq.c -- functions for developers using libmpq.
- *
- * Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/* mpq-tools configuration includes. */
-#include "config.h"
-
-/* libmpq main includes. */
-#include "mpq.h"
-#include "mpq-internal.h"
-
-/* libmpq generic includes. */
-#include "common.h"
-
-/* generic includes. */
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-/* support for platform specific things */
-#include "platform.h"
-
-/* this function returns the library version information. */
-const char *libmpq__version(void) {
-
- /* return version information. */
- return VERSION;
-}
-
-static const char *__libmpq_error_strings[] = {
- "success",
- "open error on file",
- "close error on file",
- "lseek error on file",
- "read error on file",
- "write error on file",
- "memory allocation error",
- "format errror",
- "init() wasn't called",
- "buffer size is to small",
- "file or block does not exist in archive",
- "we don't know the decryption seed",
- "error on unpacking file"
- };
-
-/* this function returns a string message for a return code. */
-const char *libmpq__strerror(int32_t returncode) {
- /* check for array bounds */
- if (-returncode < 0 || -returncode > sizeof(__libmpq_error_strings)/sizeof(char*))
- return NULL;
-
- /* return appropriate string */
- return __libmpq_error_strings[-returncode];
-}
-
-/* this function read a file and verify if it is a valid mpq archive, then it read and decrypt the hash table. */
-int32_t libmpq__archive_open(mpq_archive_s **mpq_archive, const char *mpq_filename, libmpq__off_t archive_offset) {
-
- /* some common variables. */
- uint32_t rb = 0;
- uint32_t i = 0;
- uint32_t count = 0;
- int32_t result = 0;
- uint32_t header_search = FALSE;
-
- if (archive_offset == -1) {
- archive_offset = 0;
- header_search = TRUE;
- }
-
- if ((*mpq_archive = calloc(1, sizeof(mpq_archive_s))) == NULL) {
-
- /* archive struct could not be allocated */
- return LIBMPQ_ERROR_MALLOC;
- }
-
- /* check if file exists and is readable */
- if (((*mpq_archive)->fp = fopen(mpq_filename, "rb")) == NULL) {
-
- /* file could not be opened. */
- result = LIBMPQ_ERROR_OPEN;
- goto error;
- }
-
- /* assign some default values. */
- (*mpq_archive)->mpq_header.mpq_magic = 0;
- (*mpq_archive)->files = 0;
-
- /* loop through file and search for mpq signature. */
- while (TRUE) {
-
- /* reset header values. */
- (*mpq_archive)->mpq_header.mpq_magic = 0;
-
- /* seek in file. */
- if (fseeko((*mpq_archive)->fp, archive_offset, SEEK_SET) < 0) {
-
- /* seek in file failed. */
- result = LIBMPQ_ERROR_SEEK;
- goto error;
- }
-
- /* read header from file. */
- if ((rb = fread(&(*mpq_archive)->mpq_header, 1, sizeof(mpq_header_s), (*mpq_archive)->fp)) != sizeof(mpq_header_s)) {
-
- /* no valid mpq archive. */
- result = LIBMPQ_ERROR_FORMAT;
- goto error;
- }
-
- /* check if we found a valid mpq header. */
- if ((*mpq_archive)->mpq_header.mpq_magic == LIBMPQ_HEADER) {
-
- /* check if we process old mpq archive version. */
- if ((*mpq_archive)->mpq_header.version == LIBMPQ_ARCHIVE_VERSION_ONE) {
-
- /* check if the archive is protected. */
- if ((*mpq_archive)->mpq_header.header_size != sizeof(mpq_header_s)) {
-
- /* correct header size. */
- (*mpq_archive)->mpq_header.header_size = sizeof(mpq_header_s);
- }
- }
-
- /* check if we process new mpq archive version. */
- if ((*mpq_archive)->mpq_header.version == LIBMPQ_ARCHIVE_VERSION_TWO) {
-
- /* check if the archive is protected. */
- if ((*mpq_archive)->mpq_header.header_size != sizeof(mpq_header_s) + sizeof(mpq_header_ex_s)) {
-
- /* correct header size. */
- (*mpq_archive)->mpq_header.header_size = sizeof(mpq_header_s) + sizeof(mpq_header_ex_s);
- }
- }
-
- /* break the loop, because header was found. */
- break;
- }
-
- /* move to the next possible offset. */
- if (!header_search) {
-
- /* no valid mpq archive. */
- result = LIBMPQ_ERROR_FORMAT;
- goto error;
- }
- archive_offset += 512;
- }
-
- /* store block size for later use. */
- (*mpq_archive)->block_size = 512 << (*mpq_archive)->mpq_header.block_size;
-
- /* store archive offset and size for later use. */
- (*mpq_archive)->archive_offset = archive_offset;
-
- /* check if we process new mpq archive version. */
- if ((*mpq_archive)->mpq_header.version == LIBMPQ_ARCHIVE_VERSION_TWO) {
-
- /* seek in file. */
- if (fseeko((*mpq_archive)->fp, sizeof(mpq_header_s) + archive_offset, SEEK_SET) < 0) {
-
- /* seek in file failed. */
- result = LIBMPQ_ERROR_SEEK;
- goto error;
- }
-
- /* read header from file. */
- if ((rb = fread(&(*mpq_archive)->mpq_header_ex, 1, sizeof(mpq_header_ex_s), (*mpq_archive)->fp)) != sizeof(mpq_header_ex_s)) {
-
- /* no valid mpq archive. */
- result = LIBMPQ_ERROR_FORMAT;
- goto error;
- }
- }
-
- /* allocate memory for the block table, hash table, file and block table to file mapping. */
- if (((*mpq_archive)->mpq_block = calloc((*mpq_archive)->mpq_header.block_table_count, sizeof(mpq_block_s))) == NULL ||
- ((*mpq_archive)->mpq_block_ex = calloc((*mpq_archive)->mpq_header.block_table_count, sizeof(mpq_block_ex_s))) == NULL ||
- ((*mpq_archive)->mpq_hash = calloc((*mpq_archive)->mpq_header.hash_table_count, sizeof(mpq_hash_s))) == NULL ||
- ((*mpq_archive)->mpq_file = calloc((*mpq_archive)->mpq_header.block_table_count, sizeof(mpq_file_s))) == NULL ||
- ((*mpq_archive)->mpq_map = calloc((*mpq_archive)->mpq_header.block_table_count, sizeof(mpq_map_s))) == NULL) {
-
- /* memory allocation problem. */
- result = LIBMPQ_ERROR_MALLOC;
- goto error;
- }
-
- /* seek in file. */
- if (fseeko((*mpq_archive)->fp, (*mpq_archive)->mpq_header.hash_table_offset + (((long long)((*mpq_archive)->mpq_header_ex.hash_table_offset_high)) << 32) + (*mpq_archive)->archive_offset, SEEK_SET) < 0) {
-
- /* seek in file failed. */
- result = LIBMPQ_ERROR_SEEK;
- goto error;
- }
-
- /* read the hash table into the buffer. */
- if ((rb = fread((*mpq_archive)->mpq_hash, 1, (*mpq_archive)->mpq_header.hash_table_count * sizeof(mpq_hash_s), (*mpq_archive)->fp)) < 0) {
-
- /* something on read failed. */
- result = LIBMPQ_ERROR_READ;
- goto error;
- }
-
- /* decrypt the hashtable. */
- libmpq__decrypt_block((uint32_t *)((*mpq_archive)->mpq_hash), (*mpq_archive)->mpq_header.hash_table_count * sizeof(mpq_hash_s), libmpq__hash_string("(hash table)", 0x300));
-
- /* seek in file. */
- if (fseeko((*mpq_archive)->fp, (*mpq_archive)->mpq_header.block_table_offset + (((long long)((*mpq_archive)->mpq_header_ex.block_table_offset_high)) << 32) + (*mpq_archive)->archive_offset, SEEK_SET) < 0) {
-
- /* seek in file failed. */
- result = LIBMPQ_ERROR_SEEK;
- goto error;
- }
-
- /* read the block table into the buffer. */
- if ((rb = fread((*mpq_archive)->mpq_block, 1, (*mpq_archive)->mpq_header.block_table_count * sizeof(mpq_block_s), (*mpq_archive)->fp)) < 0) {
-
- /* something on read failed. */
- result = LIBMPQ_ERROR_READ;
- goto error;
- }
-
- /* decrypt block table. */
- libmpq__decrypt_block((uint32_t *)((*mpq_archive)->mpq_block), (*mpq_archive)->mpq_header.block_table_count * sizeof(mpq_block_s), libmpq__hash_string("(block table)", 0x300));
-
- /* check if extended block table is present, regardless of version 2 it is only present in archives > 4GB. */
- if ((*mpq_archive)->mpq_header_ex.extended_offset > 0) {
-
- /* seek in file. */
- if (fseeko((*mpq_archive)->fp, (*mpq_archive)->mpq_header_ex.extended_offset + archive_offset, SEEK_SET) < 0) {
-
- /* seek in file failed. */
- result = LIBMPQ_ERROR_SEEK;
- goto error;
- }
-
- /* read header from file. */
- if ((rb = fread((*mpq_archive)->mpq_block_ex, 1, (*mpq_archive)->mpq_header.block_table_count * sizeof(mpq_block_ex_s), (*mpq_archive)->fp)) < 0) {
-
- /* no valid mpq archive. */
- result = LIBMPQ_ERROR_FORMAT;
- goto error;
- }
- }
-
- /* loop through all files in mpq archive and check if they are valid. */
- for (i = 0; i < (*mpq_archive)->mpq_header.block_table_count; i++) {
-
- /* save block difference between valid and invalid blocks. */
- (*mpq_archive)->mpq_map[i].block_table_diff = i - count;
-
- /* check if file exists, sizes and offsets are correct. */
- if (((*mpq_archive)->mpq_block[i].flags & LIBMPQ_FLAG_EXISTS) == 0) {
-
- /* file does not exist, so nothing to do with that block. */
- continue;
- }
-
- /* create final indices tables. */
- (*mpq_archive)->mpq_map[count].block_table_indices = i;
-
- /* increase file counter. */
- count++;
- }
-
- /* save the number of files. */
- (*mpq_archive)->files = count;
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-
-error:
- if ((*mpq_archive)->fp)
- fclose((*mpq_archive)->fp);
-
- free((*mpq_archive)->mpq_map);
- free((*mpq_archive)->mpq_file);
- free((*mpq_archive)->mpq_hash);
- free((*mpq_archive)->mpq_block);
- free((*mpq_archive)->mpq_block_ex);
- free(*mpq_archive);
-
- *mpq_archive = NULL;
-
- return result;
-}
-
-/* this function close the file descriptor, free the decryption buffer and the file list. */
-int32_t libmpq__archive_close(mpq_archive_s *mpq_archive) {
-
- /* try to close the file */
- if ((fclose(mpq_archive->fp)) < 0) {
-
- /* don't free anything here, so the caller can try calling us
- * again.
- */
- return LIBMPQ_ERROR_CLOSE;
- }
-
- /* free header, tables and list. */
- free(mpq_archive->mpq_map);
- free(mpq_archive->mpq_file);
- free(mpq_archive->mpq_hash);
- free(mpq_archive->mpq_block);
- free(mpq_archive->mpq_block_ex);
- free(mpq_archive);
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function return the packed size of all files in the archive. */
-int32_t libmpq__archive_packed_size(mpq_archive_s *mpq_archive, libmpq__off_t *packed_size) {
-
- /* some common variables. */
- uint32_t i;
-
- /* loop through all files in archive and count packed size. */
- for (i = 0; i < mpq_archive->files; i++) {
- *packed_size += mpq_archive->mpq_block[mpq_archive->mpq_map[i].block_table_indices].packed_size;
- }
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function return the unpacked size of all files in the archive. */
-int32_t libmpq__archive_unpacked_size(mpq_archive_s *mpq_archive, libmpq__off_t *unpacked_size) {
-
- /* some common variables. */
- uint32_t i;
-
- /* loop through all files in archive and count unpacked size. */
- for (i = 0; i < mpq_archive->files; i++) {
- *unpacked_size += mpq_archive->mpq_block[mpq_archive->mpq_map[i].block_table_indices].unpacked_size;
- }
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function return the archive offset (beginning of archive in file). */
-int32_t libmpq__archive_offset(mpq_archive_s *mpq_archive, libmpq__off_t *offset) {
-
- /* return archive offset. */
- *offset = mpq_archive->archive_offset;
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function return the archive offset. */
-int32_t libmpq__archive_version(mpq_archive_s *mpq_archive, uint32_t *version) {
-
- /* return archive version. */
- *version = mpq_archive->mpq_header.version + 1;
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function return the number of valid files in archive. */
-int32_t libmpq__archive_files(mpq_archive_s *mpq_archive, uint32_t *files) {
-
- /* return archive version. */
- *files = mpq_archive->files;
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-#define CHECK_FILE_NUM(file_number, mpq_archive) \
- if (file_number < 0 || file_number > mpq_archive->files - 1) { \
- return LIBMPQ_ERROR_EXIST; \
- }
-
-#define CHECK_BLOCK_NUM(block_number, mpq_archive) \
- if (block_number < 0 || block_number >= ((mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].flags & LIBMPQ_FLAG_SINGLE) != 0 ? 1 : (mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].unpacked_size + mpq_archive->block_size - 1) / mpq_archive->block_size)) { \
- return LIBMPQ_ERROR_EXIST; \
- }
-
-/* this function return the packed size of the given files in the archive. */
-int32_t libmpq__file_packed_size(mpq_archive_s *mpq_archive, uint32_t file_number, libmpq__off_t *packed_size) {
-
- /* check if given file number is not out of range. */
- CHECK_FILE_NUM(file_number, mpq_archive)
-
- /* get the packed size of file. */
- *packed_size = mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].packed_size;
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function return the unpacked size of the given file in the archive. */
-int32_t libmpq__file_unpacked_size(mpq_archive_s *mpq_archive, uint32_t file_number, libmpq__off_t *unpacked_size) {
-
- /* check if given file number is not out of range. */
- CHECK_FILE_NUM(file_number, mpq_archive)
-
- /* get the unpacked size of file. */
- *unpacked_size = mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].unpacked_size;
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function return the file offset (beginning of file in archive). */
-int32_t libmpq__file_offset(mpq_archive_s *mpq_archive, uint32_t file_number, libmpq__off_t *offset) {
-
- /* check if given file number is not out of range. */
- CHECK_FILE_NUM(file_number, mpq_archive)
-
- /* return file offset relative to archive start. */
- *offset = mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].offset + (((long long)mpq_archive->mpq_block_ex[mpq_archive->mpq_map[file_number].block_table_indices].offset_high) << 32);
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function return the number of blocks for the given file in the archive. */
-int32_t libmpq__file_blocks(mpq_archive_s *mpq_archive, uint32_t file_number, uint32_t *blocks) {
-
- /* check if given file number is not out of range. */
- CHECK_FILE_NUM(file_number, mpq_archive)
-
- /* return the number of blocks for the given file. */
- *blocks = (mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].flags & LIBMPQ_FLAG_SINGLE) != 0 ? 1 : (mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].unpacked_size + mpq_archive->block_size - 1) / mpq_archive->block_size;
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function return if the file is encrypted or not. */
-int32_t libmpq__file_encrypted(mpq_archive_s *mpq_archive, uint32_t file_number, uint32_t *encrypted) {
-
- /* check if given file number is not out of range. */
- CHECK_FILE_NUM(file_number, mpq_archive)
-
- /* return the encryption status of file. */
- *encrypted = (mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].flags & LIBMPQ_FLAG_ENCRYPTED) != 0 ? TRUE : FALSE;
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function return if the file is compressed or not. */
-int32_t libmpq__file_compressed(mpq_archive_s *mpq_archive, uint32_t file_number, uint32_t *compressed) {
-
- /* check if given file number is not out of range. */
- CHECK_FILE_NUM(file_number, mpq_archive)
-
- /* return the compression status of file. */
- *compressed = (mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].flags & LIBMPQ_FLAG_COMPRESS_MULTI) != 0 ? TRUE : FALSE;
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function return if the file is imploded or not. */
-int32_t libmpq__file_imploded(mpq_archive_s *mpq_archive, uint32_t file_number, uint32_t *imploded) {
-
- /* check if given file number is not out of range. */
- CHECK_FILE_NUM(file_number, mpq_archive)
-
- /* return the implosion status of file. */
- *imploded = (mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].flags & LIBMPQ_FLAG_COMPRESS_PKZIP) != 0 ? TRUE : FALSE;
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function return filenumber by the given name. */
-int32_t libmpq__file_number(mpq_archive_s *mpq_archive, const char *filename, uint32_t *number) {
-
- /* some common variables. */
- uint32_t i, hash1, hash2, hash3, ht_count;
-
- /* if the list of file names doesn't include this one, we'll have
- * to figure out the file number the "hard" way.
- */
- ht_count = mpq_archive->mpq_header.hash_table_count;
-
- hash1 = libmpq__hash_string (filename, 0x0) & (ht_count - 1);
- hash2 = libmpq__hash_string (filename, 0x100);
- hash3 = libmpq__hash_string (filename, 0x200);
-
- /* loop through all files in mpq archive.
- * hash1 gives us a clue about the starting position of this
- * search.
- */
- for (i = hash1; mpq_archive->mpq_hash[i].block_table_index != LIBMPQ_HASH_FREE; i = (i + 1) & (ht_count - 1)) {
-
- /* if the other two hashes match, we found our file number. */
- if (mpq_archive->mpq_hash[i].hash_a == hash2 &&
- mpq_archive->mpq_hash[i].hash_b == hash3) {
-
- /* return the file number. */
- *number = mpq_archive->mpq_hash[i].block_table_index - mpq_archive->mpq_map[mpq_archive->mpq_hash[i].block_table_index].block_table_diff;
-
- /* we found our file, return zero. */
- return LIBMPQ_SUCCESS;
- }
-
- /* check if we have cycled through the whole hash table */
- if (((i + 1) & (ht_count - 1)) == hash1) {
- break;
- }
- }
-
- /* if no matching entry found, so return error. */
- return LIBMPQ_ERROR_EXIST;
-}
-
-/* this function read the given file from archive into a buffer. */
-int32_t libmpq__file_read(mpq_archive_s *mpq_archive, uint32_t file_number, uint8_t *out_buf, libmpq__off_t out_size, libmpq__off_t *transferred) {
-
- /* some common variables. */
- uint32_t i;
- uint32_t blocks = 0;
- int32_t result = 0;
- libmpq__off_t file_offset = 0;
- libmpq__off_t unpacked_size = 0;
- libmpq__off_t transferred_block = 0;
- libmpq__off_t transferred_total = 0;
-
- /* check if given file number is not out of range. */
- CHECK_FILE_NUM(file_number, mpq_archive)
-
- /* get target size of block. */
- libmpq__file_unpacked_size(mpq_archive, file_number, &unpacked_size);
-
- /* check if target buffer is to small. */
- if (unpacked_size > out_size) {
-
- /* output buffer size is to small or block size is unknown. */
- return LIBMPQ_ERROR_SIZE;
- }
-
- /* fetch file offset. */
- libmpq__file_offset(mpq_archive, file_number, &file_offset);
-
- /* get block count for file. */
- libmpq__file_blocks(mpq_archive, file_number, &blocks);
-
- /* open the packed block offset table. */
- if ((result = libmpq__block_open_offset(mpq_archive, file_number)) < 0) {
-
- /* something on opening packed block offset table failed. */
- return result;
- }
-
- /* loop through all blocks. */
- for (i = 0; i < blocks; i++) {
-
- /* cleanup size variable. */
- unpacked_size = 0;
-
- /* get unpacked block size. */
- libmpq__block_unpacked_size(mpq_archive, file_number, i, &unpacked_size);
-
- /* read block. */
- if ((result = libmpq__block_read(mpq_archive, file_number, i, out_buf + transferred_total, unpacked_size, &transferred_block)) < 0) {
-
- /* close the packed block offset table. */
- libmpq__block_close_offset(mpq_archive, file_number);
-
- /* something on reading block failed. */
- return result;
- }
-
- transferred_total += transferred_block;
-
- }
-
- /* close the packed block offset table. */
- libmpq__block_close_offset(mpq_archive, file_number);
-
- /* check for null pointer. */
- if (transferred != NULL) {
-
- /* store transferred bytes. */
- *transferred = transferred_total;
- }
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function open a file in the given archive and caches the block offset information. */
-int32_t libmpq__block_open_offset(mpq_archive_s *mpq_archive, uint32_t file_number) {
-
- /* some common variables. */
- uint32_t i;
- uint32_t packed_size;
- int32_t rb = 0;
- int32_t result = 0;
-
- /* check if given file number is not out of range. */
- CHECK_FILE_NUM(file_number, mpq_archive)
-
- if (mpq_archive->mpq_file[file_number]) {
-
- /* file already opened, so increment counter */
- mpq_archive->mpq_file[file_number]->open_count++;
- return LIBMPQ_SUCCESS;
- }
-
- /* check if file is not stored in a single sector. */
- if ((mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].flags & LIBMPQ_FLAG_SINGLE) == 0) {
-
- /* get packed size based on block size and block count. */
- packed_size = sizeof(uint32_t) * (((mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].unpacked_size + mpq_archive->block_size - 1) / mpq_archive->block_size) + 1);
- } else {
-
- /* file is stored in single sector and we need only two entries for the packed block offset table. */
- packed_size = sizeof(uint32_t) * 2;
- }
-
- /* check if data has one extra entry. */
- if ((mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].flags & LIBMPQ_FLAG_CRC) != 0) {
-
- /* add one uint32_t. */
- packed_size += sizeof(uint32_t);
- }
-
- /* allocate memory for the file. */
- if ((mpq_archive->mpq_file[file_number] = calloc(1, sizeof(mpq_file_s))) == NULL) {
-
- /* memory allocation problem. */
- result = LIBMPQ_ERROR_MALLOC;
- goto error;
- }
-
- /* allocate memory for the packed block offset table. */
- if ((mpq_archive->mpq_file[file_number]->packed_offset = calloc(1, packed_size)) == NULL) {
-
- /* memory allocation problem. */
- result = LIBMPQ_ERROR_MALLOC;
- goto error;
- }
-
- /* initialize counter to one opening */
- mpq_archive->mpq_file[file_number]->open_count = 1;
-
- /* check if we need to load the packed block offset table, we will maintain this table for unpacked files too. */
- if ((mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].flags & LIBMPQ_FLAG_COMPRESSED) != 0 &&
- (mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].flags & LIBMPQ_FLAG_SINGLE) == 0) {
-
- /* seek to block position. */
- if (fseeko(mpq_archive->fp, mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].offset + (((long long)mpq_archive->mpq_block_ex[mpq_archive->mpq_map[file_number].block_table_indices].offset_high) << 32) + mpq_archive->archive_offset, SEEK_SET) < 0) {
-
- /* seek in file failed. */
- result = LIBMPQ_ERROR_SEEK;
- goto error;
- }
-
- /* read block positions from begin of file. */
- if ((rb = fread(mpq_archive->mpq_file[file_number]->packed_offset, 1, packed_size, mpq_archive->fp)) < 0) {
-
- /* something on read from archive failed. */
- result = LIBMPQ_ERROR_READ;
- goto error;
- }
-
- /* check if the archive is protected some way, sometimes the file appears not to be encrypted, but it is.
- * a special case are files with an additional sector but LIBMPQ_FLAG_CRC not set. we don't want to handle
- * them as encrypted. */
- if (mpq_archive->mpq_file[file_number]->packed_offset[0] != rb &&
- mpq_archive->mpq_file[file_number]->packed_offset[0] != rb + 4) {
-
- /* file is encrypted. */
- mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].flags |= LIBMPQ_FLAG_ENCRYPTED;
- }
-
- /* check if packed offset block is encrypted, we have to decrypt it. */
- if (mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].flags & LIBMPQ_FLAG_ENCRYPTED) {
-
- /* check if we don't know the file seed, try to find it. */
- if (libmpq__decrypt_key((uint8_t *)mpq_archive->mpq_file[file_number]->packed_offset, packed_size, mpq_archive->block_size, &mpq_archive->mpq_file[file_number]->seed) < 0) {
-
- /* sorry without seed, we cannot extract file. */
- result = LIBMPQ_ERROR_DECRYPT;
- goto error;
- }
-
- /* decrypt block in input buffer. */
- if (libmpq__decrypt_block(mpq_archive->mpq_file[file_number]->packed_offset, packed_size, mpq_archive->mpq_file[file_number]->seed - 1) < 0 ) {
-
- /* something on decrypt failed. */
- result = LIBMPQ_ERROR_DECRYPT;
- goto error;
- }
-
- /* check if the block positions are correctly decrypted. */
- if (mpq_archive->mpq_file[file_number]->packed_offset[0] != packed_size) {
-
- /* sorry without seed, we cannot extract file. */
- result = LIBMPQ_ERROR_DECRYPT;
- goto error;
- }
- }
- } else {
-
- /* check if file is not stored in a single sector. */
- if ((mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].flags & LIBMPQ_FLAG_SINGLE) == 0) {
-
- /* loop through all blocks and create packed block offset table based on block size. */
- for (i = 0; i < ((mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].unpacked_size + mpq_archive->block_size - 1) / mpq_archive->block_size + 1); i++) {
-
- /* check if we process the last block. */
- if (i == ((mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].unpacked_size + mpq_archive->block_size - 1) / mpq_archive->block_size)) {
-
- /* store size of last block. */
- mpq_archive->mpq_file[file_number]->packed_offset[i] = mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].unpacked_size;
- } else {
-
- /* store default block size. */
- mpq_archive->mpq_file[file_number]->packed_offset[i] = i * mpq_archive->block_size;
- }
- }
- } else {
-
- /* store offsets. */
- mpq_archive->mpq_file[file_number]->packed_offset[0] = 0;
- mpq_archive->mpq_file[file_number]->packed_offset[1] = mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].packed_size;
- }
- }
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-
-error:
-
- /* free packed block offset table and file pointer. */
- free(mpq_archive->mpq_file[file_number]->packed_offset);
- free(mpq_archive->mpq_file[file_number]);
-
- /* return error constant. */
- return result;
-}
-
-/* this function free the file pointer to the opened file in archive. */
-int32_t libmpq__block_close_offset(mpq_archive_s *mpq_archive, uint32_t file_number) {
-
- /* check if given file number is not out of range. */
- CHECK_FILE_NUM(file_number, mpq_archive)
-
- if (mpq_archive->mpq_file[file_number] == NULL) {
-
- /* packed block offset table is not opened. */
- return LIBMPQ_ERROR_OPEN;
- }
-
- mpq_archive->mpq_file[file_number]->open_count--;
-
- if (mpq_archive->mpq_file[file_number]->open_count != 0) {
-
- /* still in use */
- return LIBMPQ_SUCCESS;
- }
-
- /* free packed block offset table and file pointer. */
- free(mpq_archive->mpq_file[file_number]->packed_offset);
- free(mpq_archive->mpq_file[file_number]);
-
- /* mark it as unopened - libmpq__block_open_offset checks for this to decide whether to increment the counter */
- mpq_archive->mpq_file[file_number] = NULL;
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function return the unpacked size of the given file and block in the archive. */
-int32_t libmpq__block_unpacked_size(mpq_archive_s *mpq_archive, uint32_t file_number, uint32_t block_number, libmpq__off_t *unpacked_size) {
-
- /* check if given file number is not out of range. */
- CHECK_FILE_NUM(file_number, mpq_archive)
-
- /* check if given block number is not out of range. */
- CHECK_BLOCK_NUM(block_number, mpq_archive)
-
- /* check if packed block offset table is opened. */
- if (mpq_archive->mpq_file[file_number] == NULL ||
- mpq_archive->mpq_file[file_number]->packed_offset == NULL) {
-
- /* packed block offset table is not opened. */
- return LIBMPQ_ERROR_OPEN;
- }
-
- /* check if block is stored as single sector. */
- if ((mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].flags & LIBMPQ_FLAG_SINGLE) != 0) {
-
- /* return the unpacked size of the block in the mpq archive. */
- *unpacked_size = mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].unpacked_size;
- }
-
- /* check if block is not stored as single sector. */
- if ((mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].flags & LIBMPQ_FLAG_SINGLE) == 0) {
-
- /* check if we not process the last block. */
- if (block_number < ((mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].unpacked_size + mpq_archive->block_size - 1) / mpq_archive->block_size) - 1) {
-
- /* return the block size as unpacked size. */
- *unpacked_size = mpq_archive->block_size;
- } else {
-
- /* return the unpacked size of the last block in the mpq archive. */
- *unpacked_size = mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].unpacked_size - mpq_archive->block_size * block_number;
- }
- }
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function return the decryption seed for the given file and block. */
-int32_t libmpq__block_seed(mpq_archive_s *mpq_archive, uint32_t file_number, uint32_t block_number, uint32_t *seed) {
-
- /* check if given file number is not out of range. */
- CHECK_FILE_NUM(file_number, mpq_archive)
-
- /* check if given block number is not out of range. */
- CHECK_BLOCK_NUM(block_number, mpq_archive)
-
- /* check if packed block offset table is opened. */
- if (mpq_archive->mpq_file[file_number] == NULL ||
- mpq_archive->mpq_file[file_number]->packed_offset == NULL) {
-
- /* packed block offset table is not opened. */
- return LIBMPQ_ERROR_OPEN;
- }
-
- /* return the decryption key. */
- *seed = mpq_archive->mpq_file[file_number]->seed + block_number;
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
-
-/* this function read the given block from archive into a buffer. */
-int32_t libmpq__block_read(mpq_archive_s *mpq_archive, uint32_t file_number, uint32_t block_number, uint8_t *out_buf, libmpq__off_t out_size, libmpq__off_t *transferred) {
-
- /* some common variables. */
- uint8_t *in_buf;
- uint32_t seed = 0;
- uint32_t encrypted = 0;
- uint32_t compressed = 0;
- uint32_t imploded = 0;
- int32_t tb = 0;
- libmpq__off_t block_offset = 0;
- off_t in_size = 0;
- libmpq__off_t unpacked_size = 0;
-
- /* check if given file number is not out of range. */
- CHECK_FILE_NUM(file_number, mpq_archive)
-
- /* check if given block number is not out of range. */
- CHECK_BLOCK_NUM(block_number, mpq_archive)
-
- /* check if packed block offset table is opened. */
- if (mpq_archive->mpq_file[file_number] == NULL ||
- mpq_archive->mpq_file[file_number]->packed_offset == NULL) {
-
- /* packed block offset table is not opened. */
- return LIBMPQ_ERROR_OPEN;
- }
-
- /* get target size of block. */
- libmpq__block_unpacked_size(mpq_archive, file_number, block_number, &unpacked_size);
-
- /* check if target buffer is to small. */
- if (unpacked_size > out_size) {
-
- /* output buffer size is to small or block size is unknown. */
- return LIBMPQ_ERROR_SIZE;
- }
-
- /* fetch some required values like input buffer size and block offset. */
- block_offset = mpq_archive->mpq_block[mpq_archive->mpq_map[file_number].block_table_indices].offset + (((long long)mpq_archive->mpq_block_ex[mpq_archive->mpq_map[file_number].block_table_indices].offset_high) << 32) + mpq_archive->mpq_file[file_number]->packed_offset[block_number];
- in_size = mpq_archive->mpq_file[file_number]->packed_offset[block_number + 1] - mpq_archive->mpq_file[file_number]->packed_offset[block_number];
-
- /* seek in file. */
- if (fseeko(mpq_archive->fp, block_offset + mpq_archive->archive_offset, SEEK_SET) < 0) {
-
- /* something with seek in file failed. */
- return LIBMPQ_ERROR_SEEK;
- }
-
- /* allocate memory for the read buffer. */
- if ((in_buf = calloc(1, in_size)) == NULL) {
-
- /* memory allocation problem. */
- return LIBMPQ_ERROR_MALLOC;
- }
-
- /* read block from file. */
- if (fread(in_buf, 1, in_size, mpq_archive->fp) < 0) {
-
- /* free buffers. */
- free(in_buf);
-
- /* something on reading block failed. */
- return LIBMPQ_ERROR_READ;
- }
-
- /* get encryption status. */
- libmpq__file_encrypted(mpq_archive, file_number, &encrypted);
-
- /* check if file is encrypted. */
- if (encrypted == 1) {
-
- /* get decryption key. */
- libmpq__block_seed(mpq_archive, file_number, block_number, &seed);
-
- /* decrypt block. */
- if (libmpq__decrypt_block((uint32_t *)in_buf, in_size, seed) < 0) {
-
- /* free buffers. */
- free(in_buf);
-
- /* something on decrypting block failed. */
- return LIBMPQ_ERROR_DECRYPT;
- }
- }
-
- /* get compression status. */
- libmpq__file_compressed(mpq_archive, file_number, &compressed);
-
- /* check if file is compressed. */
- if (compressed == 1) {
-
- /* decompress block. */
- if ((tb = libmpq__decompress_block(in_buf, in_size, out_buf, out_size, LIBMPQ_FLAG_COMPRESS_MULTI)) < 0) {
-
- /* free temporary buffer. */
- free(in_buf);
-
- /* something on decompressing block failed. */
- return LIBMPQ_ERROR_UNPACK;
- }
- }
-
- /* get implosion status. */
- libmpq__file_imploded(mpq_archive, file_number, &imploded);
-
- /* check if file is imploded. */
- if (imploded == 1) {
-
- /* explode block. */
- if ((tb = libmpq__decompress_block(in_buf, in_size, out_buf, out_size, LIBMPQ_FLAG_COMPRESS_PKZIP)) < 0) {
-
- /* free temporary buffer. */
- free(in_buf);
-
- /* something on decompressing block failed. */
- return LIBMPQ_ERROR_UNPACK;
- }
- }
-
- /* check if file is neither compressed nor imploded. */
- if (compressed == 0 && imploded == 0) {
-
- /* copy block. */
- if ((tb = libmpq__decompress_block(in_buf, in_size, out_buf, out_size, LIBMPQ_FLAG_COMPRESS_NONE)) < 0) {
-
- /* free temporary buffer. */
- free(in_buf);
-
- /* something on decompressing block failed. */
- return LIBMPQ_ERROR_UNPACK;
- }
- }
-
- /* free read buffer. */
- free(in_buf);
-
- /* check for null pointer. */
- if (transferred != NULL) {
-
- /* store transferred bytes. */
- *transferred = tb;
- }
-
- /* if no error was found, return zero. */
- return LIBMPQ_SUCCESS;
-}
diff --git a/dep/libmpq/libmpq/mpq.h b/dep/libmpq/libmpq/mpq.h
deleted file mode 100644
index abd4862c334..00000000000
--- a/dep/libmpq/libmpq/mpq.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * mpq.h -- some default types and defines.
- *
- * Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
- *
- * Some parts (the encryption and decryption stuff) were adapted from
- * the C++ version of StormLib.h and StormPort.h included in stormlib.
- * The C++ version belongs to the following authors:
- *
- * Ladislav Zezula <ladik@zezula.net>
- * Marko Friedemann <marko.friedemann@bmx-chemnitz.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _MPQ_H
-#define _MPQ_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* generic includes. */
-#include <stdint.h>
-#include <sys/types.h>
-
-#if defined(__GNUC__) && (__GNUC__ >= 4)
-# define LIBMPQ_API __attribute__((visibility("default")))
-#else
-# define LIBMPQ_API
-#endif
-
-/* define errors. */
-#define LIBMPQ_ERROR_OPEN -1 /* open error on file. */
-#define LIBMPQ_ERROR_CLOSE -2 /* close error on file. */
-#define LIBMPQ_ERROR_SEEK -3 /* lseek error on file. */
-#define LIBMPQ_ERROR_READ -4 /* read error on file. */
-#define LIBMPQ_ERROR_WRITE -5 /* write error on file. */
-#define LIBMPQ_ERROR_MALLOC -6 /* memory allocation error. */
-#define LIBMPQ_ERROR_FORMAT -7 /* format errror. */
-#define LIBMPQ_ERROR_NOT_INITIALIZED -8 /* libmpq__init() wasn't called. */
-#define LIBMPQ_ERROR_SIZE -9 /* buffer size is to small. */
-#define LIBMPQ_ERROR_EXIST -10 /* file or block does not exist in archive. */
-#define LIBMPQ_ERROR_DECRYPT -11 /* we don't know the decryption seed. */
-#define LIBMPQ_ERROR_UNPACK -12 /* error on unpacking file. */
-
-/* internal data structure. */
-typedef struct mpq_archive mpq_archive_s;
-
-/* file offset data type for API*/
-typedef int64_t libmpq__off_t;
-
-/* generic information about library. */
-extern LIBMPQ_API const char *libmpq__version(void);
-
-/* string error message for a libmpq return code. */
-extern LIBMPQ_API const char *libmpq__strerror(int32_t returncode);
-
-/* generic mpq archive information. */
-extern LIBMPQ_API int32_t libmpq__archive_open(mpq_archive_s **mpq_archive, const char *mpq_filename, libmpq__off_t archive_offset);
-extern LIBMPQ_API int32_t libmpq__archive_close(mpq_archive_s *mpq_archive);
-extern LIBMPQ_API int32_t libmpq__archive_packed_size(mpq_archive_s *mpq_archive, libmpq__off_t *packed_size);
-extern LIBMPQ_API int32_t libmpq__archive_unpacked_size(mpq_archive_s *mpq_archive, libmpq__off_t *unpacked_size);
-extern LIBMPQ_API int32_t libmpq__archive_offset(mpq_archive_s *mpq_archive, libmpq__off_t *offset);
-extern LIBMPQ_API int32_t libmpq__archive_version(mpq_archive_s *mpq_archive, uint32_t *version);
-extern LIBMPQ_API int32_t libmpq__archive_files(mpq_archive_s *mpq_archive, uint32_t *files);
-
-/* generic file processing functions. */
-extern LIBMPQ_API int32_t libmpq__file_packed_size(mpq_archive_s *mpq_archive, uint32_t file_number, libmpq__off_t *packed_size);
-extern LIBMPQ_API int32_t libmpq__file_unpacked_size(mpq_archive_s *mpq_archive, uint32_t file_number, libmpq__off_t *unpacked_size);
-extern LIBMPQ_API int32_t libmpq__file_offset(mpq_archive_s *mpq_archive, uint32_t file_number, libmpq__off_t *offset);
-extern LIBMPQ_API int32_t libmpq__file_blocks(mpq_archive_s *mpq_archive, uint32_t file_number, uint32_t *blocks);
-extern LIBMPQ_API int32_t libmpq__file_encrypted(mpq_archive_s *mpq_archive, uint32_t file_number, uint32_t *encrypted);
-extern LIBMPQ_API int32_t libmpq__file_compressed(mpq_archive_s *mpq_archive, uint32_t file_number, uint32_t *compressed);
-extern LIBMPQ_API int32_t libmpq__file_imploded(mpq_archive_s *mpq_archive, uint32_t file_number, uint32_t *imploded);
-extern LIBMPQ_API int32_t libmpq__file_number(mpq_archive_s *mpq_archive, const char *filename, uint32_t *number);
-extern LIBMPQ_API int32_t libmpq__file_read(mpq_archive_s *mpq_archive, uint32_t file_number, uint8_t *out_buf, libmpq__off_t out_size, libmpq__off_t *transferred);
-
-/* generic block processing functions. */
-extern LIBMPQ_API int32_t libmpq__block_open_offset(mpq_archive_s *mpq_archive, uint32_t file_number);
-extern LIBMPQ_API int32_t libmpq__block_close_offset(mpq_archive_s *mpq_archive, uint32_t file_number);
-extern LIBMPQ_API int32_t libmpq__block_unpacked_size(mpq_archive_s *mpq_archive, uint32_t file_number, uint32_t block_number, libmpq__off_t *unpacked_size);
-extern LIBMPQ_API int32_t libmpq__block_read(mpq_archive_s *mpq_archive, uint32_t file_number, uint32_t block_number, uint8_t *out_buf, libmpq__off_t out_size, libmpq__off_t *transferred);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _MPQ_H */
diff --git a/dep/libmpq/libmpq/pack_begin.h b/dep/libmpq/libmpq/pack_begin.h
deleted file mode 100644
index eb4a6ddebbb..00000000000
--- a/dep/libmpq/libmpq/pack_begin.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * pack_begin.h -- header file for struct packing used by libmpq.
- *
- * Copyright (c) 2010 Georg Lukas <georg@op-co.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _PACK_BEGIN
-#define _PACK_BEGIN
-#else
-#error "pack_begin.h may not be included twice!"
-#endif
-
-#ifdef _MSC_VER
- #pragma pack(push,1)
- #define PACK_STRUCT
-#else
- /* we assume GNU here */
- #define PACK_STRUCT __attribute__((packed))
-#endif
-
diff --git a/dep/libmpq/libmpq/pack_end.h b/dep/libmpq/libmpq/pack_end.h
deleted file mode 100644
index a8a35113bfb..00000000000
--- a/dep/libmpq/libmpq/pack_end.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * pack_end.h -- header file for struct packing used by libmpq.
- *
- * Copyright (c) 2010 Georg Lukas <georg@op-co.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef _PACK_BEGIN
-#undef _PACK_BEGIN
-#else
-#error "pack_begin.h must be includede before pack_end.h"
-#endif
-
-#ifdef _MSC_VER
- #pragma pack(pop)
-#endif
-
-#undef PACK_STRUCT
diff --git a/dep/libmpq/libmpq/platform.h b/dep/libmpq/libmpq/platform.h
deleted file mode 100644
index 68fdfdc5ded..00000000000
--- a/dep/libmpq/libmpq/platform.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * platform.h -- header file for platform specific parts.
- *
- * Copyright (c) 2010 Georg Lukas <georg@op-co.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _PLATFORM_H
-#define _PLATFORM_H
-
-#ifdef _MSC_VER
- #define fseeko _fseeki64
-#endif
-
-#endif /* _PLATFORM_H */
diff --git a/dep/libmpq/libmpq/wave.c b/dep/libmpq/libmpq/wave.c
deleted file mode 100644
index 628593fce83..00000000000
--- a/dep/libmpq/libmpq/wave.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * wave.c -- this file contains decompression methods used by mpq-tools
- * to decompress wave files.
- *
- * Copyright (c) 2003-2007 Maik Broemme <mbroemme@plusserver.de>
- *
- * This source was adepted from the C++ version of wave.cpp included
- * in stormlib. The C++ version belongs to the following authors:
- *
- * Ladislav Zezula <ladik@zezula.net>
- * Tom Amigo <tomamigo@apexmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/* generic includes. */
-#include <stdint.h>
-
-/* libmpq generic includes. */
-#include "wave.h"
-
-/* table necessary dor decompression. */
-static const uint32_t wave_table_1503f120[] = {
- 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000006,
- 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
- 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
- 0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000006, 0xFFFFFFFF, 0x00000008
-};
-
-/* table necessary dor decompression. */
-static const uint32_t wave_table_1503f1a0[] = {
- 0x00000007, 0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E,
- 0x00000010, 0x00000011, 0x00000013, 0x00000015, 0x00000017, 0x00000019, 0x0000001C, 0x0000001F,
- 0x00000022, 0x00000025, 0x00000029, 0x0000002D, 0x00000032, 0x00000037, 0x0000003C, 0x00000042,
- 0x00000049, 0x00000050, 0x00000058, 0x00000061, 0x0000006B, 0x00000076, 0x00000082, 0x0000008F,
- 0x0000009D, 0x000000AD, 0x000000BE, 0x000000D1, 0x000000E6, 0x000000FD, 0x00000117, 0x00000133,
- 0x00000151, 0x00000173, 0x00000198, 0x000001C1, 0x000001EE, 0x00000220, 0x00000256, 0x00000292,
- 0x000002D4, 0x0000031C, 0x0000036C, 0x000003C3, 0x00000424, 0x0000048E, 0x00000502, 0x00000583,
- 0x00000610, 0x000006AB, 0x00000756, 0x00000812, 0x000008E0, 0x000009C3, 0x00000ABD, 0x00000BD0,
- 0x00000CFF, 0x00000E4C, 0x00000FBA, 0x0000114C, 0x00001307, 0x000014EE, 0x00001706, 0x00001954,
- 0x00001BDC, 0x00001EA5, 0x000021B6, 0x00002515, 0x000028CA, 0x00002CDF, 0x0000315B, 0x0000364B,
- 0x00003BB9, 0x000041B2, 0x00004844, 0x00004F7E, 0x00005771, 0x0000602F, 0x000069CE, 0x00007462,
- 0x00007FFF
-};
-
-/* this function decompress a wave file, mono or stereo, 1500F230 offset. */
-int32_t libmpq__do_decompress_wave(uint8_t *out_buf, int32_t out_length, uint8_t *in_buf, int32_t in_length, int32_t channels) {
-
- /* some common variables. */
- byte_and_int16_t out;
- byte_and_int16_t in;
- uint32_t index;
- int32_t nr_array1[2];
- int32_t nr_array2[2];
- int32_t count = 0;
-
- /* end on input buffer. */
- uint8_t *in_end = in_buf + in_length;
-
- /* assign default values. */
- out.pb = out_buf;
- in.pb = in_buf;
- nr_array1[0] = 0x2C;
- nr_array1[1] = 0x2C;
-
- /* increase. */
- in.pw++;
-
- /* 15007AD7 */
- for (count = 0; count < channels; count++) {
-
- /* some common variables. */
- int32_t temp;
-
- /* save pointer. */
- temp = *(int16_t *)in.pw++;
- nr_array2[count] = temp;
-
- /* check if should break. */
- if (out_length < 2) {
- return out.pb - out_buf;
- }
-
- /* return values. */
- *out.pw++ = (uint16_t)temp;
- out_length -= 2;
- }
-
- /* decrease channels. */
- index = channels - 1;
-
- /* loop through input buffer until end reached. */
- while (in.pb < in_end) {
-
- /* save the byte. */
- uint8_t one_byte = *in.pb++;
-
- /* check how many channels and set index. */
- if (channels == 2) {
- index = (index == 0) ? 1 : 0;
- }
-
- /* 15007B25 - get one byte from input buffer. */
- if (one_byte & 0x80) {
-
- /* 15007B32 */
- switch (one_byte & 0x7F) {
- case 0:
-
- /* 15007B8E */
- if (nr_array1[index] != 0) {
- nr_array1[index]--;
- }
-
- /* check if should break. */
- if (out_length < 2) {
- break;
- }
-
- /* return values. */
- *out.pw++ = (uint16_t)nr_array2[index];
- out_length -= 2;
-
- /* continue loop. */
- continue;
- case 1:
- /* 15007B72 and EBX. */
- nr_array1[index] += 8;
-
- /* check index. */
- if (nr_array1[index] > 0x58) {
- nr_array1[index] = 0x58;
- }
-
- /* check how many channels and set index. */
- if (channels == 2) {
- index = (index == 0) ? 1 : 0;
- }
-
- /* continue loop. */
- continue;
- case 2:
-
- /* nothing todo, so continue. */
- continue;
- default:
-
- /* decrease index. */
- nr_array1[index] -= 8;
-
- /* check index. */
- if (nr_array1[index] < 0) {
- nr_array1[index] = 0;
- }
-
- /* check if two channels left. */
- if (channels != 2) {
- continue;
- }
- index = (index == 0) ? 1 : 0;
-
- /* continue loop. */
- continue;
- }
- } else {
-
- /* EDI */
- uint32_t temp1 = wave_table_1503f1a0[nr_array1[index]];
-
- /* ESI */
- uint32_t temp2 = temp1 >> in_buf[1];
-
- /* ECX */
- int32_t temp3 = nr_array2[index];
-
- /* EBX = one byte. */
- if (one_byte & 0x01) {
- temp2 += (temp1 >> 0);
- }
- if (one_byte & 0x02) {
- temp2 += (temp1 >> 1);
- }
- if (one_byte & 0x04) {
- temp2 += (temp1 >> 2);
- }
- if (one_byte & 0x08) {
- temp2 += (temp1 >> 3);
- }
- if (one_byte & 0x10) {
- temp2 += (temp1 >> 4);
- }
- if (one_byte & 0x20) {
- temp2 += (temp1 >> 5);
- }
- if (one_byte & 0x40) {
- temp3 -= temp2;
- if (temp3 <= (int32_t)0xFFFF8000) {
- temp3 = (int32_t)0xFFFF8000;
- }
- } else {
- temp3 += temp2;
- if (temp3 >= 0x7FFF) {
- temp3 = 0x7FFF;
- }
- }
-
- /* restore index. */
- nr_array2[index] = temp3;
-
- /* check if should break. */
- if (out_length < 2) {
- break;
- }
-
- /* assign values. */
- temp2 = nr_array1[index];
- one_byte &= 0x1F;
- *out.pw++ = (uint16_t)temp3;
- out_length -= 2;
- temp2 += wave_table_1503f120[one_byte];
- nr_array1[index] = temp2;
-
- /* check index. */
- if (nr_array1[index] < 0) {
- nr_array1[index] = 0;
- } else {
-
- /* check index. */
- if (nr_array1[index] > 0x58) {
- nr_array1[index] = 0x58;
- }
- }
- }
- }
-
- /* return copied bytes. */
- return (out.pb - out_buf);
-}
diff --git a/dep/libmpq/libmpq/wave.h b/dep/libmpq/libmpq/wave.h
deleted file mode 100644
index 1b9491bd70a..00000000000
--- a/dep/libmpq/libmpq/wave.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * wave.h -- header file for wav unplode functions used by mpq-tools.
- *
- * Copyright (c) 2003-2007 Maik Broemme <mbroemme@plusserver.de>
- *
- * This source was adepted from the C++ version of wave.h included
- * in stormlib. The C++ version belongs to the following authors:
- *
- * Ladislav Zezula <ladik.zezula.net>
- * Tom Amigo <tomamigo@apexmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _WAVE_H
-#define _WAVE_H
-
-/* buffer. */
-typedef union {
- uint16_t *pw;
- uint8_t *pb;
-} byte_and_int16_t;
-
-/* decompress a wave file, mono or stereo, 1500F230 offset. */
-int32_t libmpq__do_decompress_wave(
- uint8_t *out_buf,
- int32_t out_length,
- uint8_t *in_buf,
- int32_t in_length,
- int32_t channels
-);
-
-#endif /* _WAVE_H */
diff --git a/dep/libmpq/tools/Makefile.am b/dep/libmpq/tools/Makefile.am
deleted file mode 100644
index 607205379a4..00000000000
--- a/dep/libmpq/tools/Makefile.am
+++ /dev/null
@@ -1,8 +0,0 @@
-# minimum required automake 1.6
-AUTOMAKE_OPTIONS = 1.6
-
-# the main programs.
-bin_PROGRAMS = crypt_buf_gen
-
-# sources for crypt_buf_gen program.
-crypt_buf_gen_SOURCES = crypt_buf_gen.c
diff --git a/dep/libmpq/tools/crypt_buf_gen.c b/dep/libmpq/tools/crypt_buf_gen.c
deleted file mode 100644
index 3d150fc661f..00000000000
--- a/dep/libmpq/tools/crypt_buf_gen.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * crypt_buf_gen.c -- tool to re-create the static decryption buffer.
- *
- * Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.de>
- * Copyright (c) 2008 Georg Lukas <georg@op-co.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- *
- * Usage:
- * $ make crypt_buf_gen
- * $ ./crypt_buf_gen > crypt_buf.h
- *
- */
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-static uint32_t *buffer;
-
-int32_t libmpq__buffer_init() {
- buffer = malloc(sizeof(uint32_t) * 0x500);
-
- if (!buffer)
- return -1;
-
- /* some common variables. */
- uint32_t seed = 0x00100001;
- uint32_t index1 = 0;
- uint32_t index2 = 0;
- uint32_t i;
-
- /* initialize the decryption buffer. */
- for (index1 = 0; index1 < 0x100; index1++) {
- for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100) {
-
- /* some common variables. */
- uint32_t temp1, temp2;
-
- /* temporary copy. */
- seed = (seed * 125 + 3) % 0x2AAAAB;
- temp1 = (seed & 0xFFFF) << 0x10;
-
- /* temporary copy. */
- seed = (seed * 125 + 3) % 0x2AAAAB;
- temp2 = (seed & 0xFFFF);
-
- /* assign buffer. */
- buffer[index2] = (temp1 | temp2);
- }
- }
-
- /* if no error was found, return zero. */
- return 0;
-}
-
-int main() {
- if (libmpq__buffer_init() != 0)
- perror("libmpq__buffer_init()");
- int x;
- printf("/* DO NOT CHANGE! this file is auto-generated by crypt_buf_gen.c */\n");
- printf("static const uint32_t crypt_buf[0x500] = {\n\t");
- for (x = 0; x < 0x500; x++) {
- printf("0x%08x", buffer[x]);
- if (x < 0x500 - 1) {
- if (x % 6 == 5)
- printf(",\n\t");
- else
- printf(", ");
- }
- }
- printf("\n};\n");
-}
diff --git a/dep/libmpq/win/config.h b/dep/libmpq/win/config.h
deleted file mode 100644
index 6833494624d..00000000000
--- a/dep/libmpq/win/config.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* config.h. Generated from config.h.in by configure. */
-/* config.h.in. Generated from configure.ac by autoheader. */
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#define HAVE_DLFCN_H 1
-
-/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
-#define HAVE_FSEEKO 1
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the `bz2' library (-lbz2). */
-#define HAVE_LIBBZ2 1
-
-/* Define to 1 if you have the `z' library (-lz). */
-#define HAVE_LIBZ 1
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#define HAVE_STDINT_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 0
-
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
- */
-#define LT_OBJDIR ".libs/"
-
-/* Name of package */
-#define PACKAGE "libmpq"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT "mbroemme@plusserver.de"
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "libmpq"
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "libmpq 0.4.2"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "libmpq"
-
-/* Define to the home page for this package. */
-#define PACKAGE_URL ""
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "0.4.2"
-
-/* Define to 1 if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Version number of package */
-#define VERSION "0.4.2"
-
-/* Number of bits in a file offset, on hosts where this is settable. */
-/* #undef _FILE_OFFSET_BITS */
-
-/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
-/* #undef _LARGEFILE_SOURCE */
-
-/* Define for large files, on AIX-style hosts. */
-/* #undef _LARGE_FILES */
diff --git a/dep/libmpq/win/dirent.h b/dep/libmpq/win/dirent.h
deleted file mode 100644
index 6425174092d..00000000000
--- a/dep/libmpq/win/dirent.h
+++ /dev/null
@@ -1,230 +0,0 @@
-/*****************************************************************************
- * dirent.h - dirent API for Microsoft Visual Studio
- *
- * Copyright (C) 2006 Toni Ronkko
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * ``Software''), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Dec 15, 2009, John Cunningham
- * Added rewinddir member function
- *
- * Jan 18, 2008, Toni Ronkko
- * Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string
- * between multi-byte and unicode representations. This makes the
- * code simpler and also allows the code to be compiled under MingW. Thanks
- * to Azriel Fasten for the suggestion.
- *
- * Mar 4, 2007, Toni Ronkko
- * Bug fix: due to the strncpy_s() function this file only compiled in
- * Visual Studio 2005. Using the new string functions only when the
- * compiler version allows.
- *
- * Nov 2, 2006, Toni Ronkko
- * Major update: removed support for Watcom C, MS-DOS and Turbo C to
- * simplify the file, updated the code to compile cleanly on Visual
- * Studio 2005 with both unicode and multi-byte character strings,
- * removed rewinddir() as it had a bug.
- *
- * Aug 20, 2006, Toni Ronkko
- * Removed all remarks about MSVC 1.0, which is antiqued now. Simplified
- * comments by removing SGML tags.
- *
- * May 14 2002, Toni Ronkko
- * Embedded the function definitions directly to the header so that no
- * source modules need to be included in the Visual Studio project. Removed
- * all the dependencies to other projects so that this very header can be
- * used independently.
- *
- * May 28 1998, Toni Ronkko
- * First version.
- *****************************************************************************/
-#ifndef DIRENT_H
-#define DIRENT_H
-
-#include <windows.h>
-#include <string.h>
-#include <assert.h>
-
-
-typedef struct dirent
-{
- char d_name[MAX_PATH + 1]; /* current dir entry (multi-byte char string) */
- WIN32_FIND_DATAA data; /* file attributes */
-} dirent;
-
-
-typedef struct DIR
-{
- dirent current; /* Current directory entry */
- int cached; /* Indicates un-processed entry in memory */
- HANDLE search_handle; /* File search handle */
- char patt[MAX_PATH + 3]; /* search pattern (3 = pattern + "\\*\0") */
-} DIR;
-
-
-/* Forward declarations */
-static DIR *opendir (const char *dirname);
-static struct dirent *readdir (DIR *dirp);
-static int closedir (DIR *dirp);
-static void rewinddir(DIR* dirp);
-
-
-/* Use the new safe string functions introduced in Visual Studio 2005 */
-#if defined(_MSC_VER) && _MSC_VER >= 1400
-# define STRNCPY(dest,src,size) strncpy_s((dest),(size),(src),_TRUNCATE)
-#else
-# define STRNCPY(dest,src,size) strncpy((dest),(src),(size))
-#endif
-
-
-/*****************************************************************************
- * Open directory stream DIRNAME for read and return a pointer to the
- * internal working area that is used to retrieve individual directory
- * entries.
- */
-static DIR *opendir(const char *dirname)
-{
- DIR *dirp;
- assert (dirname != NULL);
- assert (strlen (dirname) < MAX_PATH);
-
- /* construct new DIR structure */
- dirp = (DIR*) malloc (sizeof (struct DIR));
- if (dirp != NULL) {
- char *p;
-
- /* take directory name... */
- STRNCPY (dirp->patt, dirname, sizeof(dirp->patt));
- dirp->patt[MAX_PATH] = '\0';
-
- /* ... and append search pattern to it */
- p = strchr (dirp->patt, '\0');
- if (dirp->patt < p && *(p-1) != '\\' && *(p-1) != ':') {
- *p++ = '\\';
- }
- *p++ = '*';
- *p = '\0';
-
- /* open stream and retrieve first file */
- dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->current.data);
- if (dirp->search_handle == INVALID_HANDLE_VALUE) {
- /* invalid search pattern? */
- free (dirp);
- return NULL;
- }
-
- /* there is an un-processed directory entry in memory now */
- dirp->cached = 1;
- }
-
- return dirp;
-}
-
-
-/*****************************************************************************
- * Read a directory entry, and return a pointer to a dirent structure
- * containing the name of the entry in d_name field. Individual directory
- * entries returned by this very function include regular files,
- * sub-directories, pseudo-directories "." and "..", but also volume labels,
- * hidden files and system files may be returned.
- */
-static struct dirent *readdir(DIR *dirp)
-{
- assert (dirp != NULL);
-
- if (dirp->search_handle == INVALID_HANDLE_VALUE) {
- /* directory stream was opened/rewound incorrectly or ended normally */
- return NULL;
- }
-
- /* get next directory entry */
- if (dirp->cached != 0) {
- /* a valid directory entry already in memory */
- dirp->cached = 0;
- } else {
- /* read next directory entry from disk */
- if (FindNextFileA (dirp->search_handle, &dirp->current.data) == FALSE) {
- /* the very last file has been processed or an error occured */
- FindClose (dirp->search_handle);
- dirp->search_handle = INVALID_HANDLE_VALUE;
- return NULL;
- }
- }
-
- /* copy as a multibyte character string */
- STRNCPY ( dirp->current.d_name,
- dirp->current.data.cFileName,
- sizeof(dirp->current.d_name) );
- dirp->current.d_name[MAX_PATH] = '\0';
-
- return &dirp->current;
-}
-
-
-/*****************************************************************************
- * Close directory stream opened by opendir() function. Close of the
- * directory stream invalidates the DIR structure as well as any previously
- * read directory entry.
- */
-static int closedir(DIR *dirp)
-{
- assert (dirp != NULL);
-
- /* release search handle */
- if (dirp->search_handle != INVALID_HANDLE_VALUE) {
- FindClose (dirp->search_handle);
- dirp->search_handle = INVALID_HANDLE_VALUE;
- }
-
- /* release directory handle */
- free (dirp);
- return 0;
-}
-
-
-/*****************************************************************************
- * Resets the position of the directory stream to which dirp refers to the
- * beginning of the directory. It also causes the directory stream to refer
- * to the current state of the corresponding directory, as a call to opendir()
- * would have done. If dirp does not refer to a directory stream, the effect
- * is undefined.
- */
-static void rewinddir(DIR* dirp)
-{
- /* release search handle */
- if (dirp->search_handle != INVALID_HANDLE_VALUE) {
- FindClose (dirp->search_handle);
- dirp->search_handle = INVALID_HANDLE_VALUE;
- }
-
- /* open new search handle and retrieve first file */
- dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->current.data);
- if (dirp->search_handle == INVALID_HANDLE_VALUE) {
- /* invalid search pattern? */
- free (dirp);
- return;
- }
-
- /* there is an un-processed directory entry in memory now */
- dirp->cached = 1;
-}
-
-
-#endif /*DIRENT_H*/
diff --git a/dep/libmpq/win/stdint.h b/dep/libmpq/win/stdint.h
deleted file mode 100644
index d02608a5972..00000000000
--- a/dep/libmpq/win/stdint.h
+++ /dev/null
@@ -1,247 +0,0 @@
-// ISO C9x compliant stdint.h for Microsoft Visual Studio
-// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
-//
-// Copyright (c) 2006-2008 Alexander Chemeris
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright
-// notice, this list of conditions and the following disclaimer in the
-// documentation and/or other materials provided with the distribution.
-//
-// 3. The name of the author may be used to endorse or promote products
-// derived from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef _MSC_VER // [
-#error "Use this header only with Microsoft Visual C++ compilers!"
-#endif // _MSC_VER ]
-
-#ifndef _MSC_STDINT_H_ // [
-#define _MSC_STDINT_H_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif
-
-#include <limits.h>
-
-// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
-// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
-// or compiler give many errors like this:
-// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
-#ifdef __cplusplus
-extern "C" {
-#endif
-# include <wchar.h>
-#ifdef __cplusplus
-}
-#endif
-
-// Define _W64 macros to mark types changing their size, like intptr_t.
-#ifndef _W64
-# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
-# define _W64 __w64
-# else
-# define _W64
-# endif
-#endif
-
-
-// 7.18.1 Integer types
-
-// 7.18.1.1 Exact-width integer types
-
-// Visual Studio 6 and Embedded Visual C++ 4 doesn't
-// realize that, e.g. char has the same size as __int8
-// so we give up on __intX for them.
-#if (_MSC_VER < 1300)
- typedef signed char int8_t;
- typedef signed short int16_t;
- typedef signed int int32_t;
- typedef unsigned char uint8_t;
- typedef unsigned short uint16_t;
- typedef unsigned int uint32_t;
-#else
- typedef signed __int8 int8_t;
- typedef signed __int16 int16_t;
- typedef signed __int32 int32_t;
- typedef unsigned __int8 uint8_t;
- typedef unsigned __int16 uint16_t;
- typedef unsigned __int32 uint32_t;
-#endif
-typedef signed __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-
-
-// 7.18.1.2 Minimum-width integer types
-typedef int8_t int_least8_t;
-typedef int16_t int_least16_t;
-typedef int32_t int_least32_t;
-typedef int64_t int_least64_t;
-typedef uint8_t uint_least8_t;
-typedef uint16_t uint_least16_t;
-typedef uint32_t uint_least32_t;
-typedef uint64_t uint_least64_t;
-
-// 7.18.1.3 Fastest minimum-width integer types
-typedef int8_t int_fast8_t;
-typedef int16_t int_fast16_t;
-typedef int32_t int_fast32_t;
-typedef int64_t int_fast64_t;
-typedef uint8_t uint_fast8_t;
-typedef uint16_t uint_fast16_t;
-typedef uint32_t uint_fast32_t;
-typedef uint64_t uint_fast64_t;
-
-// 7.18.1.4 Integer types capable of holding object pointers
-#ifdef _WIN64 // [
- typedef signed __int64 intptr_t;
- typedef unsigned __int64 uintptr_t;
-#else // _WIN64 ][
- typedef _W64 signed int intptr_t;
- typedef _W64 unsigned int uintptr_t;
-#endif // _WIN64 ]
-
-// 7.18.1.5 Greatest-width integer types
-typedef int64_t intmax_t;
-typedef uint64_t uintmax_t;
-
-
-// 7.18.2 Limits of specified-width integer types
-
-#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
-
-// 7.18.2.1 Limits of exact-width integer types
-#define INT8_MIN ((int8_t)_I8_MIN)
-#define INT8_MAX _I8_MAX
-#define INT16_MIN ((int16_t)_I16_MIN)
-#define INT16_MAX _I16_MAX
-#define INT32_MIN ((int32_t)_I32_MIN)
-#define INT32_MAX _I32_MAX
-#define INT64_MIN ((int64_t)_I64_MIN)
-#define INT64_MAX _I64_MAX
-#define UINT8_MAX _UI8_MAX
-#define UINT16_MAX _UI16_MAX
-#define UINT32_MAX _UI32_MAX
-#define UINT64_MAX _UI64_MAX
-
-// 7.18.2.2 Limits of minimum-width integer types
-#define INT_LEAST8_MIN INT8_MIN
-#define INT_LEAST8_MAX INT8_MAX
-#define INT_LEAST16_MIN INT16_MIN
-#define INT_LEAST16_MAX INT16_MAX
-#define INT_LEAST32_MIN INT32_MIN
-#define INT_LEAST32_MAX INT32_MAX
-#define INT_LEAST64_MIN INT64_MIN
-#define INT_LEAST64_MAX INT64_MAX
-#define UINT_LEAST8_MAX UINT8_MAX
-#define UINT_LEAST16_MAX UINT16_MAX
-#define UINT_LEAST32_MAX UINT32_MAX
-#define UINT_LEAST64_MAX UINT64_MAX
-
-// 7.18.2.3 Limits of fastest minimum-width integer types
-#define INT_FAST8_MIN INT8_MIN
-#define INT_FAST8_MAX INT8_MAX
-#define INT_FAST16_MIN INT16_MIN
-#define INT_FAST16_MAX INT16_MAX
-#define INT_FAST32_MIN INT32_MIN
-#define INT_FAST32_MAX INT32_MAX
-#define INT_FAST64_MIN INT64_MIN
-#define INT_FAST64_MAX INT64_MAX
-#define UINT_FAST8_MAX UINT8_MAX
-#define UINT_FAST16_MAX UINT16_MAX
-#define UINT_FAST32_MAX UINT32_MAX
-#define UINT_FAST64_MAX UINT64_MAX
-
-// 7.18.2.4 Limits of integer types capable of holding object pointers
-#ifdef _WIN64 // [
-# define INTPTR_MIN INT64_MIN
-# define INTPTR_MAX INT64_MAX
-# define UINTPTR_MAX UINT64_MAX
-#else // _WIN64 ][
-# define INTPTR_MIN INT32_MIN
-# define INTPTR_MAX INT32_MAX
-# define UINTPTR_MAX UINT32_MAX
-#endif // _WIN64 ]
-
-// 7.18.2.5 Limits of greatest-width integer types
-#define INTMAX_MIN INT64_MIN
-#define INTMAX_MAX INT64_MAX
-#define UINTMAX_MAX UINT64_MAX
-
-// 7.18.3 Limits of other integer types
-
-#ifdef _WIN64 // [
-# define PTRDIFF_MIN _I64_MIN
-# define PTRDIFF_MAX _I64_MAX
-#else // _WIN64 ][
-# define PTRDIFF_MIN _I32_MIN
-# define PTRDIFF_MAX _I32_MAX
-#endif // _WIN64 ]
-
-#define SIG_ATOMIC_MIN INT_MIN
-#define SIG_ATOMIC_MAX INT_MAX
-
-#ifndef SIZE_MAX // [
-# ifdef _WIN64 // [
-# define SIZE_MAX _UI64_MAX
-# else // _WIN64 ][
-# define SIZE_MAX _UI32_MAX
-# endif // _WIN64 ]
-#endif // SIZE_MAX ]
-
-// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
-#ifndef WCHAR_MIN // [
-# define WCHAR_MIN 0
-#endif // WCHAR_MIN ]
-#ifndef WCHAR_MAX // [
-# define WCHAR_MAX _UI16_MAX
-#endif // WCHAR_MAX ]
-
-#define WINT_MIN 0
-#define WINT_MAX _UI16_MAX
-
-#endif // __STDC_LIMIT_MACROS ]
-
-
-// 7.18.4 Limits of other integer types
-
-#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
-
-// 7.18.4.1 Macros for minimum-width integer constants
-
-#define INT8_C(val) val##i8
-#define INT16_C(val) val##i16
-#define INT32_C(val) val##i32
-#define INT64_C(val) val##i64
-
-#define UINT8_C(val) val##ui8
-#define UINT16_C(val) val##ui16
-#define UINT32_C(val) val##ui32
-#define UINT64_C(val) val##ui64
-
-// 7.18.4.2 Macros for greatest-width integer constants
-#define INTMAX_C INT64_C
-#define UINTMAX_C UINT64_C
-
-#endif // __STDC_CONSTANT_MACROS ]
-
-
-#endif // _MSC_STDINT_H_ ]