mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 19:37:03 +00:00
Remove deps in prep for submodule
This commit is contained in:
parent
76889e9ad8
commit
5d25bdcc9f
2217 changed files with 0 additions and 591372 deletions
|
|
@ -1,39 +0,0 @@
|
||||||
# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
|
|
||||||
#
|
|
||||||
# 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
|
|
||||||
|
|
||||||
if(NOT ACE_USE_EXTERNAL)
|
|
||||||
add_subdirectory(acelite)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(SOAP)
|
|
||||||
add_subdirectory(gsoap)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(SCRIPT_LIB_ELUNA)
|
|
||||||
add_subdirectory(lualib)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(USE_STORMLIB)
|
|
||||||
add_subdirectory(StormLib)
|
|
||||||
else()
|
|
||||||
add_subdirectory(libmpq)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_subdirectory(recastnavigation)
|
|
||||||
add_subdirectory(g3dlite)
|
|
||||||
add_subdirectory(zlib)
|
|
||||||
add_subdirectory(loadlib)
|
|
||||||
add_subdirectory(bzip2)
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
[](http://www.getmangos.eu)
|
|
||||||
|
|
||||||
[](https://www.getmangos.eu/forum.php)
|
|
||||||
[](http://github.com/mangoswiki/wiki/wiki)
|
|
||||||
[](http://github.com/mangostools)
|
|
||||||
[](https://www.getmangos.eu/project.php)
|
|
||||||
|
|
||||||
Mangos Dependencies
|
|
||||||
------------
|
|
||||||
*Mangos* stands on the shoulders of well-known Open Source
|
|
||||||
libraries, and a few awesome, but less known libraries to prevent us from
|
|
||||||
inventing the wheel again.
|
|
||||||
|
|
||||||
*Please note that Linux and Mac OS X users should install packages using
|
|
||||||
their systems package management instead of source packages.*
|
|
||||||
|
|
||||||
* **MySQL** / **PostgreSQL**: to store content, and user data, we rely on
|
|
||||||
[MySQL][1]/[MariaDB][2] and [PostgreSQL][3] to handle data.
|
|
||||||
* **ACE**: the [ADAPTIVE Communication Environment][4] aka. *ACE* provides us
|
|
||||||
with a solid cross-platform framework for abstracting operating system
|
|
||||||
specific details.
|
|
||||||
* **Recast**: in order to create navigation data from the client's map files,
|
|
||||||
we use [Recast][5] to do the dirty work. It provides functions for
|
|
||||||
rendering, pathing, etc.
|
|
||||||
* **G3D**: the [G3D][6] engine provides the basic framework for handling 3D
|
|
||||||
data, and is used to handle basic map data.
|
|
||||||
* **libmpq**: [libmpq][7] provides an abstraction layer for reading from the
|
|
||||||
client's data files.
|
|
||||||
* **Zlib**: [Zlib][12] ([Zlib for Windows][10]) provides compression algorithms
|
|
||||||
used in both MPQ archive handling and the client/server protocol.
|
|
||||||
* **Bzip2**: [Bzip2][13] ([Bzip2 for Windows][11]) provides compression
|
|
||||||
algorithms used in MPQ archives.
|
|
||||||
* **OpenSSL**: [OpenSSL][8] ([OpenSSL for Windows][14]) provides encryption
|
|
||||||
algorithms used when authenticating clients.
|
|
||||||
* **Lua**: [Lua 5.2][15] ([Lua 5.2 for Windows][16]) provides a convenient, fast
|
|
||||||
scripting environment, which allows us to make live changes to scripted
|
|
||||||
content.
|
|
||||||
|
|
||||||
*Recast*, *G3D* and *libmpq* are included in the *Mangos* distribution as
|
|
||||||
we rely on specific versions. *libmpq* is to be replaced with *stormlib* shortly.
|
|
||||||
|
|
||||||
Optional dependencies
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
* **Doxygen**: if you want to export HTML or PDF formatted documentation for the
|
|
||||||
*Mangos* API, you should install [Doxygen][9].
|
|
||||||
|
|
||||||
[1]: http://www.mysql.com/ "MySQL · The world's most popular open source database"
|
|
||||||
[2]: http://www.mariadb.org/ "MariaDB · An enhanced, drop-in replacement for MySQL"
|
|
||||||
[3]: http://www.postgresql.org/ "PostgreSQL · The world's most advanced open source database"
|
|
||||||
[4]: http://www.cs.wustl.edu/~schmidt/ACE.html "ACE · The ADAPTIVE Communication Environment"
|
|
||||||
[5]: http://github.com/memononen/recastnavigation "Recast · Navigation-mesh Toolset for Games"
|
|
||||||
[6]: http://sourceforge.net/projects/g3d/ "G3D · G3D Innovation Engine"
|
|
||||||
[7]: http://github.com/ge0rg/libmpq "libmpq · A library for reading data from MPQ archives"
|
|
||||||
[8]: http://www.openssl.org/ "OpenSSL · The Open Source toolkit for SSL/TLS"
|
|
||||||
[9]: http://www.stack.nl/~dimitri/doxygen/ "Doxygen · API documentation generator"
|
|
||||||
[10]: http://gnuwin32.sourceforge.net/packages/zlib.htm "Zlib for Windows"
|
|
||||||
[11]: http://gnuwin32.sourceforge.net/packages/bzip2.htm "Bzip2 for Windows"
|
|
||||||
[12]: http://www.zlib.net/ "Zlib"
|
|
||||||
[13]: http://www.bzip.org/ "Bzip2"
|
|
||||||
[14]: http://slproweb.com/products/Win32OpenSSL.html "OpenSSL for Windows"
|
|
||||||
[15]: http://www.lua.org/ "Lua"
|
|
||||||
[16]: https://code.google.com/p/luaforwindows/ "Lua for Windows"
|
|
||||||
163
dep/StormLib/.gitignore
vendored
163
dep/StormLib/.gitignore
vendored
|
|
@ -1,163 +0,0 @@
|
||||||
#################
|
|
||||||
## Eclipse
|
|
||||||
#################
|
|
||||||
|
|
||||||
*.pydevproject
|
|
||||||
.project
|
|
||||||
.metadata
|
|
||||||
bin/
|
|
||||||
tmp/
|
|
||||||
*.tmp
|
|
||||||
*.bak
|
|
||||||
*.swp
|
|
||||||
*~.nib
|
|
||||||
local.properties
|
|
||||||
.classpath
|
|
||||||
.settings/
|
|
||||||
.loadpath
|
|
||||||
|
|
||||||
# External tool builders
|
|
||||||
.externalToolBuilders/
|
|
||||||
|
|
||||||
# Locally stored "Eclipse launch configurations"
|
|
||||||
*.launch
|
|
||||||
|
|
||||||
# CDT-specific
|
|
||||||
.cproject
|
|
||||||
|
|
||||||
# PDT-specific
|
|
||||||
.buildpath
|
|
||||||
|
|
||||||
|
|
||||||
#################
|
|
||||||
## Visual Studio
|
|
||||||
#################
|
|
||||||
|
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
|
||||||
## files generated by popular Visual Studio add-ons.
|
|
||||||
|
|
||||||
# User-specific files
|
|
||||||
*.suo
|
|
||||||
*.user
|
|
||||||
*.sln.docstates
|
|
||||||
|
|
||||||
# Build results
|
|
||||||
[Dd]ebug/
|
|
||||||
[Rr]elease/
|
|
||||||
*_i.c
|
|
||||||
*_p.c
|
|
||||||
*.ilk
|
|
||||||
*.meta
|
|
||||||
*.obj
|
|
||||||
*.pch
|
|
||||||
*.pdb
|
|
||||||
*.pgc
|
|
||||||
*.pgd
|
|
||||||
*.rsp
|
|
||||||
*.sbr
|
|
||||||
*.tlb
|
|
||||||
*.tli
|
|
||||||
*.tlh
|
|
||||||
*.tmp
|
|
||||||
*.vspscc
|
|
||||||
.builds
|
|
||||||
*.dotCover
|
|
||||||
|
|
||||||
## TODO: If you have NuGet Package Restore enabled, uncomment this
|
|
||||||
#packages/
|
|
||||||
|
|
||||||
# Visual C++ cache files
|
|
||||||
ipch/
|
|
||||||
*.aps
|
|
||||||
*.ncb
|
|
||||||
*.opensdf
|
|
||||||
*.sdf
|
|
||||||
|
|
||||||
# Visual Studio profiler
|
|
||||||
*.psess
|
|
||||||
*.vsp
|
|
||||||
|
|
||||||
# ReSharper is a .NET coding add-in
|
|
||||||
_ReSharper*
|
|
||||||
|
|
||||||
# Installshield output folder
|
|
||||||
[Ee]xpress
|
|
||||||
|
|
||||||
# DocProject is a documentation generator add-in
|
|
||||||
DocProject/buildhelp/
|
|
||||||
DocProject/Help/*.HxT
|
|
||||||
DocProject/Help/*.HxC
|
|
||||||
DocProject/Help/*.hhc
|
|
||||||
DocProject/Help/*.hhk
|
|
||||||
DocProject/Help/*.hhp
|
|
||||||
DocProject/Help/Html2
|
|
||||||
DocProject/Help/html
|
|
||||||
|
|
||||||
# Click-Once directory
|
|
||||||
publish
|
|
||||||
|
|
||||||
# Others
|
|
||||||
[Bb]in
|
|
||||||
[Oo]bj
|
|
||||||
sql
|
|
||||||
TestResults
|
|
||||||
*.Cache
|
|
||||||
ClientBin
|
|
||||||
stylecop.*
|
|
||||||
~$*
|
|
||||||
*.dbmdl
|
|
||||||
Generated_Code #added for RIA/Silverlight projects
|
|
||||||
|
|
||||||
# Backup & report files from converting an old project file to a newer
|
|
||||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
|
||||||
_UpgradeReport_Files/
|
|
||||||
Backup*/
|
|
||||||
UpgradeLog*.XML
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
############
|
|
||||||
## Windows
|
|
||||||
############
|
|
||||||
|
|
||||||
# Windows image file caches
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# Folder config file
|
|
||||||
Desktop.ini
|
|
||||||
|
|
||||||
|
|
||||||
#############
|
|
||||||
## Python
|
|
||||||
#############
|
|
||||||
|
|
||||||
*.py[co]
|
|
||||||
|
|
||||||
# Packages
|
|
||||||
*.egg
|
|
||||||
*.egg-info
|
|
||||||
dist
|
|
||||||
build
|
|
||||||
eggs
|
|
||||||
parts
|
|
||||||
bin
|
|
||||||
var
|
|
||||||
sdist
|
|
||||||
develop-eggs
|
|
||||||
.installed.cfg
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
.coverage
|
|
||||||
.tox
|
|
||||||
|
|
||||||
#Translations
|
|
||||||
*.mo
|
|
||||||
|
|
||||||
#Mr Developer
|
|
||||||
.mr.developer.cfg
|
|
||||||
|
|
||||||
# Mac crap
|
|
||||||
.DS_Store
|
|
||||||
|
|
@ -1,301 +0,0 @@
|
||||||
project(StormLib)
|
|
||||||
cmake_minimum_required(VERSION 2.6)
|
|
||||||
|
|
||||||
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/SBaseDumpData.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
|
|
||||||
src/libtomcrypt/src/pk/rsa/rsa_verify_simple.c
|
|
||||||
src/libtomcrypt/src/misc/crypt_libc.c
|
|
||||||
)
|
|
||||||
|
|
||||||
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_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_encode_bit_string.c
|
|
||||||
src/libtomcrypt/src/pk/asn1/der_encode_boolean.c
|
|
||||||
src/libtomcrypt/src/pk/asn1/der_encode_ia5_string.c
|
|
||||||
src/libtomcrypt/src/pk/asn1/der_encode_integer.c
|
|
||||||
src/libtomcrypt/src/pk/asn1/der_encode_object_identifier.c
|
|
||||||
src/libtomcrypt/src/pk/asn1/der_encode_octet_string.c
|
|
||||||
src/libtomcrypt/src/pk/asn1/der_encode_printable_string.c
|
|
||||||
src/libtomcrypt/src/pk/asn1/der_encode_sequence_ex.c
|
|
||||||
src/libtomcrypt/src/pk/asn1/der_encode_sequence_multi.c
|
|
||||||
src/libtomcrypt/src/pk/asn1/der_encode_set.c
|
|
||||||
src/libtomcrypt/src/pk/asn1/der_encode_setof.c
|
|
||||||
src/libtomcrypt/src/pk/asn1/der_encode_short_integer.c
|
|
||||||
src/libtomcrypt/src/pk/asn1/der_encode_utctime.c
|
|
||||||
src/libtomcrypt/src/pk/asn1/der_encode_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_pss_encode.c
|
|
||||||
src/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_decode.c
|
|
||||||
src/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_encode.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_sign_hash.c
|
|
||||||
src/libtomcrypt/src/pk/rsa/rsa_verify_hash.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/compress.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
|
|
||||||
)
|
|
||||||
|
|
||||||
add_definitions(-D_7ZIP_ST -DBZ_STRICT_ANSI)
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
if(MSVC)
|
|
||||||
message(STATUS "Using MSVC")
|
|
||||||
add_definitions(-D_7ZIP_ST -DWIN32)
|
|
||||||
else()
|
|
||||||
message(STATUS "Using mingw")
|
|
||||||
endif()
|
|
||||||
set(SRC_ADDITIONAL_FILES ${ZLIB_BZIP2_FILES} ${TOMCRYPT_FILES} ${TOMMATH_FILES})
|
|
||||||
set(LINK_LIBS wininet)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(APPLE)
|
|
||||||
message(STATUS "Using Mac OS X port")
|
|
||||||
set(LINK_LIBS z bz2)
|
|
||||||
set(SRC_ADDITIONAL_FILES ${TOMCRYPT_FILES} ${TOMMATH_FILES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (${CMAKE_SYSTEM_NAME} STREQUAL Linux)
|
|
||||||
message(STATUS "Using Linux port")
|
|
||||||
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(StormLib STATIC ${SRC_FILES} ${SRC_ADDITIONAL_FILES})
|
|
||||||
target_link_libraries(StormLib ${LINK_LIBS})
|
|
||||||
|
|
||||||
if(APPLE)
|
|
||||||
set_target_properties(StormLib PROPERTIES FRAMEWORK true)
|
|
||||||
set_target_properties(StormLib PROPERTIES PUBLIC_HEADER "src/StormLib.h src/StormPort.h")
|
|
||||||
set_target_properties(StormLib PROPERTIES LINK_FLAGS "-framework Carbon")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(UNIX)
|
|
||||||
set_target_properties(StormLib PROPERTIES VERSION 9.0.0)
|
|
||||||
set_target_properties(StormLib PROPERTIES SOVERSION 9)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# On Win32, build StormLib.dll since we don't want to clash with Storm.dll
|
|
||||||
if(WIN32)
|
|
||||||
set_target_properties(StormLib PROPERTIES OUTPUT_NAME StormLib)
|
|
||||||
endif()
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 1999-2013 Ladislav Zezula
|
|
||||||
|
|
||||||
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 THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS 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.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
This is official repository for the StomLib library, an open-source project that can work with Blizzard MPQ archives.
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
|
|
||||||
StormLib history
|
|
||||||
================
|
|
||||||
|
|
||||||
Version 9.11
|
|
||||||
|
|
||||||
- Fixed bug in processing HET table.
|
|
||||||
|
|
||||||
Version 9.10
|
|
||||||
|
|
||||||
- Support for weak-signing
|
|
||||||
- Anti-protector: New Spazzler
|
|
||||||
|
|
||||||
Version 9.00
|
|
||||||
|
|
||||||
- Support for streaming (master-mirror)
|
|
||||||
- Support for multi-file MPQs used by some WoW versions
|
|
||||||
- Opening maps protected by Spazzler protector
|
|
||||||
- Opening maps protected by BOBA protector
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
@ -1,318 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,433 +0,0 @@
|
||||||
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
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
UCMXF6EJY352EFH4XFRXCFH2XC9MQRZK
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
MMKVHY48RP7WXP4GHYBQ7SL9J9UNPHBP
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
8MXLWHQ7VGGLTZ9MQZQSFDCLJYET3CPP
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
EJ2R5TM6XFE2GUNG5QDGHKQ9UAKPWZSZ
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
PBGFBE42Z6LNK65UGJQ3WZVMCLP4HQQT
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
X7SEJJS9TSGCW5P28EBSC47AJPEY8VU2
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
5KVBQA8VYE6XRY3DLGC5ZDE4XS4P7YA2
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
478JD2K56EVNVVY4XX8TDWYT5B8KB254
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
8TS4VNFQRZTN6YWHE9CHVDH9NVWD474A
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
LJ52Z32DF4LZ4ZJJXVKK3AZQA6GABLJB
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
K6BDHY2ECUE2545YKNLBJPVYWHE7XYAG
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
6VWCQTN8V3ZZMRUCZXV8A8CGUX2TAA8H
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
S48B6CDTN5XEQAKQDJNDLJBJ73FDFM3U
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Y45MD3CAK4KXSSXHYD9VY64Z8EKJ4XFX
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
G8MN8UDG6NA2ANGY6A3DNY82HRGF29ZH
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
3DH5RE5NVM5GTFD85LXGWT6FK859ETR5
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
8WLKUAXE94PFQU4Y249PAZ24N4R4XKTQ
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
A34DXX3VHGGXSQBRFE5UFFDXMF9G4G54
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
ZG7J9K938HJEFWPQUA768MA2PFER6EAJ
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
NE7CUNNNTVAPXV7E3G2BSVBWGVMW8BL2
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
3V9E2FTMBM9QQWK7U6MAMWAZWQDB838F
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
2NSFB8MELULJ83U6YHA3UP6K4MQD48L6
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
QA2TZ9EWZ4CUU8BMB5WXCTY65F9CSW4E
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
VHB378W64BAT9SH7D68VV9NLQDK9YEGT
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
U3NFQJV4M6GC7KBN9XQJ3BRDN3PLD9NE
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,189 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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 * pByteOffset // Pointer to store current file position
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef bool (*STREAM_GETSIZE)(
|
|
||||||
struct TFileStream * pStream, // Pointer to an open stream
|
|
||||||
ULONGLONG * pFileSize // 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__
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,144 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
GetBits(pHetTable->pBetIndexes, i * pHetTable->dwIndexSizeTotal,
|
|
||||||
pHetTable->dwIndexSize,
|
|
||||||
&dwBetIndex,
|
|
||||||
4);
|
|
||||||
|
|
||||||
if(dwBetIndex < pHetTable->dwMaxFileCount)
|
|
||||||
{
|
|
||||||
DWORD dwEntryIndex = pBetTable->dwTableEntrySize * dwBetIndex;
|
|
||||||
|
|
||||||
GetBits(pBetTable->pBetHashes, dwBetIndex * pBetTable->dwBetHashSizeTotal,
|
|
||||||
pBetTable->dwBetHashSize,
|
|
||||||
&BetHash,
|
|
||||||
8);
|
|
||||||
|
|
||||||
GetBits(dwEntryIndex + pBetTable->dwBitIndex_FilePos,
|
|
||||||
pBetTable->dwBitCount_FilePos,
|
|
||||||
&ByteOffset,
|
|
||||||
8);
|
|
||||||
|
|
||||||
GetBits(dwEntryIndex + pBetTable->dwBitIndex_FileSize,
|
|
||||||
pBetTable->dwBitCount_FileSize,
|
|
||||||
&dwFileSize,
|
|
||||||
4);
|
|
||||||
|
|
||||||
GetBits(dwEntryIndex + pBetTable->dwBitIndex_CmpSize,
|
|
||||||
pBetTable->dwBitCount_CmpSize,
|
|
||||||
&dwCmpSize,
|
|
||||||
4);
|
|
||||||
|
|
||||||
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__
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,472 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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;
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
// 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), NULL);
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,765 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,255 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,446 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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, 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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,637 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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 bool FreeListFileCache(TListFileCache * pCache)
|
|
||||||
{
|
|
||||||
// Valid parameter check
|
|
||||||
if(pCache == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Free all allocated buffers
|
|
||||||
if(pCache->hFile != NULL)
|
|
||||||
SFileCloseFile(pCache->hFile);
|
|
||||||
if(pCache->szMask != NULL)
|
|
||||||
STORM_FREE(pCache->szMask);
|
|
||||||
STORM_FREE(pCache);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TListFileCache * CreateListFileCache(HANDLE hListFile, const char * szMask)
|
|
||||||
{
|
|
||||||
TListFileCache * pCache = NULL;
|
|
||||||
DWORD dwBytesRead = 0;
|
|
||||||
int nError = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
// Allocate cache for one file block
|
|
||||||
pCache = (TListFileCache *)STORM_ALLOC(TListFileCache, 1);
|
|
||||||
if(pCache == NULL)
|
|
||||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
|
|
||||||
// Clear the entire structure
|
|
||||||
if(nError == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
memset(pCache, 0, sizeof(TListFileCache));
|
|
||||||
pCache->hFile = hListFile;
|
|
||||||
|
|
||||||
// Shall we allocate a mask?
|
|
||||||
if(szMask != NULL)
|
|
||||||
{
|
|
||||||
pCache->szMask = STORM_ALLOC(char, strlen(szMask) + 1);
|
|
||||||
if(pCache->szMask != NULL)
|
|
||||||
strcpy(pCache->szMask, szMask);
|
|
||||||
else
|
|
||||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the file cache
|
|
||||||
if(nError == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
pCache->dwFileSize = SFileGetFileSize(pCache->hFile, NULL);
|
|
||||||
|
|
||||||
// Fill the cache
|
|
||||||
SFileReadFile(pCache->hFile, pCache->Buffer, CACHE_BUFFER_SIZE, &dwBytesRead, NULL);
|
|
||||||
if(dwBytesRead == 0)
|
|
||||||
nError = GetLastError();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate pointers
|
|
||||||
if(nError == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
pCache->pBegin =
|
|
||||||
pCache->pPos = &pCache->Buffer[0];
|
|
||||||
pCache->pEnd = pCache->pBegin + dwBytesRead;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FreeListFileCache(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.
|
|
||||||
static 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int SFileAddArbitraryListFile(
|
|
||||||
TMPQArchive * ha,
|
|
||||||
HANDLE hListFile)
|
|
||||||
{
|
|
||||||
TListFileCache * pCache = NULL;
|
|
||||||
size_t nLength;
|
|
||||||
char szFileName[MAX_PATH];
|
|
||||||
int nError = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
// Create the listfile cache for that file
|
|
||||||
pCache = CreateListFileCache(hListFile, NULL);
|
|
||||||
if(pCache == NULL)
|
|
||||||
nError = GetLastError();
|
|
||||||
|
|
||||||
// Load the node list. Add the node for every locale in the archive
|
|
||||||
if(nError == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
while((nLength = ReadListFileLine(pCache, szFileName, sizeof(szFileName))) > 0)
|
|
||||||
SListFileCreateNodeForAllLocales(ha, szFileName);
|
|
||||||
pCache->hFile = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the cache
|
|
||||||
if(pCache != NULL)
|
|
||||||
FreeListFileCache(pCache);
|
|
||||||
return nError;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int SFileAddExternalListFile(
|
|
||||||
TMPQArchive * ha,
|
|
||||||
HANDLE hMpq,
|
|
||||||
const char * szListFile)
|
|
||||||
{
|
|
||||||
HANDLE hListFile;
|
|
||||||
int nError = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
// Open the external list file
|
|
||||||
if(SFileOpenFileEx(hMpq, szListFile, SFILE_OPEN_LOCAL_FILE, &hListFile))
|
|
||||||
{
|
|
||||||
// Add the data from the listfile to MPQ
|
|
||||||
nError = SFileAddArbitraryListFile(ha, hListFile);
|
|
||||||
SFileCloseFile(hListFile);
|
|
||||||
}
|
|
||||||
return nError;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int SFileAddInternalListFile(
|
|
||||||
TMPQArchive * ha,
|
|
||||||
HANDLE hMpq)
|
|
||||||
{
|
|
||||||
TMPQArchive * haMpq = (TMPQArchive *)hMpq;
|
|
||||||
TMPQHash * pFirstHash;
|
|
||||||
TMPQHash * pHash;
|
|
||||||
HANDLE hListFile;
|
|
||||||
LCID lcSaveLocale = lcFileLocale;
|
|
||||||
int nError = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
// If there is hash table, we need to support multiple listfiles
|
|
||||||
// with different locales (BrooDat.mpq)
|
|
||||||
if(haMpq->pHashTable != NULL)
|
|
||||||
{
|
|
||||||
pFirstHash = pHash = GetFirstHashEntry(haMpq, LISTFILE_NAME);
|
|
||||||
while(nError == ERROR_SUCCESS && pHash != NULL)
|
|
||||||
{
|
|
||||||
// Set the prefered locale to that from list file
|
|
||||||
SFileSetLocale(pHash->lcLocale);
|
|
||||||
if(SFileOpenFileEx(hMpq, LISTFILE_NAME, 0, &hListFile))
|
|
||||||
{
|
|
||||||
// Add the data from the listfile to MPQ
|
|
||||||
nError = SFileAddArbitraryListFile(ha, hListFile);
|
|
||||||
SFileCloseFile(hListFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore the original locale
|
|
||||||
SFileSetLocale(lcSaveLocale);
|
|
||||||
|
|
||||||
// Move to the next hash
|
|
||||||
pHash = GetNextHashEntry(haMpq, pFirstHash, pHash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Open the external list file
|
|
||||||
if(SFileOpenFileEx(hMpq, LISTFILE_NAME, 0, &hListFile))
|
|
||||||
{
|
|
||||||
// Add the data from the listfile to MPQ
|
|
||||||
// The function also closes the listfile handle
|
|
||||||
nError = SFileAddArbitraryListFile(ha, hListFile);
|
|
||||||
SFileCloseFile(hListFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the result of the operation
|
|
||||||
return nError;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// File functions
|
|
||||||
|
|
||||||
// Adds a listfile into the MPQ archive.
|
|
||||||
int WINAPI SFileAddListFile(HANDLE hMpq, const char * szListFile)
|
|
||||||
{
|
|
||||||
TMPQArchive * ha = (TMPQArchive *)hMpq;
|
|
||||||
int nError = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
// Add the listfile for each MPQ in the patch chain
|
|
||||||
while(ha != NULL)
|
|
||||||
{
|
|
||||||
if(szListFile != NULL)
|
|
||||||
SFileAddExternalListFile(ha, hMpq, szListFile);
|
|
||||||
else
|
|
||||||
SFileAddInternalListFile(ha, hMpq);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Move to the next archive in the chain
|
|
||||||
ha = ha->haPatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nError;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Enumerating files in listfile
|
|
||||||
|
|
||||||
HANDLE WINAPI SListFileFindFirstFile(HANDLE hMpq, const char * szListFile, const char * szMask, SFILE_FIND_DATA * lpFindFileData)
|
|
||||||
{
|
|
||||||
TListFileCache * pCache = NULL;
|
|
||||||
HANDLE hListFile;
|
|
||||||
size_t nLength = 0;
|
|
||||||
DWORD dwSearchScope = SFILE_OPEN_LOCAL_FILE;
|
|
||||||
int nError = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
// Initialize the structure with zeros
|
|
||||||
memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA));
|
|
||||||
|
|
||||||
// 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))
|
|
||||||
nError = GetLastError();
|
|
||||||
|
|
||||||
// Load the listfile to cache
|
|
||||||
if(nError == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
pCache = CreateListFileCache(hListFile, szMask);
|
|
||||||
if(pCache == NULL)
|
|
||||||
nError = GetLastError();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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));
|
|
||||||
FreeListFileCache(pCache);
|
|
||||||
|
|
||||||
SetLastError(nError);
|
|
||||||
pCache = NULL;
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
return FreeListFileCache((TListFileCache *)hFind);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,480 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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
|
|
||||||
TFileEntry * pFileEntry;
|
|
||||||
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;
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
// Save the flags for (listfile)
|
|
||||||
pFileEntry = GetFileEntryLocale(ha, LISTFILE_NAME, LANG_NEUTRAL);
|
|
||||||
if(pFileEntry != NULL)
|
|
||||||
ha->dwFileFlags1 = pFileEntry->dwFlags;
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
// Save the flags for (attributes)
|
|
||||||
pFileEntry = GetFileEntryLocale(ha, ATTRIBUTES_NAME, LANG_NEUTRAL);
|
|
||||||
if(pFileEntry != NULL)
|
|
||||||
ha->dwFileFlags2 = pFileEntry->dwFlags;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,469 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,587 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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), NULL, NULL))
|
|
||||||
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, NULL);
|
|
||||||
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, NULL);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,921 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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, NULL);
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,274 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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__
|
|
||||||
|
|
||||||
|
|
@ -1,987 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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 */
|
|
||||||
/* 29.05.12 8.20 Lad C-only interface */
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
#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 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 0x0814 // Current version of StormLib (8.10)
|
|
||||||
#define STORMLIB_VERSION_STRING "8.20"
|
|
||||||
|
|
||||||
#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);
|
|
||||||
|
|
||||||
typedef struct TFileStream TFileStream;
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Structure for bit arrays used for HET and BET tables
|
|
||||||
|
|
||||||
typedef struct _TBitArray
|
|
||||||
{
|
|
||||||
|
|
||||||
DWORD NumberOfBits; // Total number of bits that are available
|
|
||||||
BYTE Elements[1]; // Array of elements (variable length)
|
|
||||||
} TBitArray;
|
|
||||||
|
|
||||||
void GetBits(TBitArray * array, unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, int nResultSize);
|
|
||||||
void SetBits(TBitArray * array, unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, int nResultSize);
|
|
||||||
|
|
||||||
// Structure for file bitmap. Used by SFileGetArchiveBitmap
|
|
||||||
typedef 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)
|
|
||||||
} TFileBitmap;
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// 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
|
|
||||||
|
|
||||||
typedef 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;
|
|
||||||
} TMPQUserData;
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
typedef 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
|
|
||||||
} TMPQHeader;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
|
|
||||||
// Hash entry. All files in the archive are searched by their hashes.
|
|
||||||
typedef 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;
|
|
||||||
} TMPQHash;
|
|
||||||
|
|
||||||
|
|
||||||
// File description block contains informations about the file
|
|
||||||
typedef 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;
|
|
||||||
} TMPQBlock;
|
|
||||||
|
|
||||||
// Patch file information, preceding the sector offset table
|
|
||||||
typedef 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)
|
|
||||||
} TPatchInfo;
|
|
||||||
|
|
||||||
// Header for PTCH files
|
|
||||||
typedef 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
|
|
||||||
} TPatchHeader;
|
|
||||||
|
|
||||||
#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).
|
|
||||||
typedef 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.
|
|
||||||
} TFileEntry;
|
|
||||||
|
|
||||||
// Common header for HET and BET tables
|
|
||||||
typedef 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
|
|
||||||
|
|
||||||
} TMPQExtTable;
|
|
||||||
|
|
||||||
//
|
|
||||||
// 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).
|
|
||||||
//
|
|
||||||
typedef 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)
|
|
||||||
} TMPQBitmap;
|
|
||||||
|
|
||||||
// Structure for parsed HET table
|
|
||||||
typedef 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
|
|
||||||
} TMPQHetTable;
|
|
||||||
|
|
||||||
// Structure for parsed BET table
|
|
||||||
typedef 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
|
|
||||||
} TMPQBetTable;
|
|
||||||
|
|
||||||
// Archive handle structure
|
|
||||||
typedef 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)
|
|
||||||
|
|
||||||
struct _TMPQArchive * haPatch; // Pointer to patch archive, if any
|
|
||||||
struct _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
|
|
||||||
} TMPQArchive;
|
|
||||||
|
|
||||||
// File handle structure
|
|
||||||
typedef 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'
|
|
||||||
|
|
||||||
struct _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
|
|
||||||
} TMPQFile;
|
|
||||||
|
|
||||||
// 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 * pByteOffset);
|
|
||||||
bool FileStream_SetPos(TFileStream * pStream, ULONGLONG ByteOffset);
|
|
||||||
bool FileStream_GetSize(TFileStream * pStream, ULONGLONG * pFileSize);
|
|
||||||
bool FileStream_SetSize(TFileStream * pStream, ULONGLONG NewFileSize);
|
|
||||||
bool FileStream_GetTime(TFileStream * pStream, ULONGLONG * pFT);
|
|
||||||
bool FileStream_GetFlags(TFileStream * pStream, LPDWORD pdwStreamFlags);
|
|
||||||
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, bool bReserved);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHigh, DWORD dwMoveMethod);
|
|
||||||
bool WINAPI SFileReadFile(HANDLE hFile, void * lpBuffer, DWORD dwToRead, LPDWORD pdwRead, LPOVERLAPPED lpOverlapped);
|
|
||||||
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);
|
|
||||||
|
|
||||||
// High-level extract function
|
|
||||||
bool WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const TCHAR * szExtracted, DWORD dwSearchScope);
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// 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);
|
|
||||||
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);
|
|
||||||
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__
|
|
||||||
|
|
@ -1,241 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
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);
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#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__
|
|
||||||
|
|
@ -1,358 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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__
|
|
||||||
|
|
@ -1,358 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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__
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,282 +0,0 @@
|
||||||
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
/*--- 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 ---*/
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
|
|
@ -1,509 +0,0 @@
|
||||||
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
/*--- 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 ---*/
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
|
|
@ -1,672 +0,0 @@
|
||||||
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
/*--- 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 ---*/
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
/*--- 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 ---*/
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
|
|
@ -1,626 +0,0 @@
|
||||||
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
/*--- 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 ---*/
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
|
|
@ -1,205 +0,0 @@
|
||||||
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
/*--- 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 ---*/
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
/*--- 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 ---*/
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,142 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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__
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,145 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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__
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
#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__
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,69 +0,0 @@
|
||||||
/* 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 $ */
|
|
||||||
|
|
@ -1,368 +0,0 @@
|
||||||
/* 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 $ */
|
|
||||||
|
|
@ -1,288 +0,0 @@
|
||||||
/* 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 $ */
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
#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 $ */
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
/* 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 $ */
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
/* 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 $ */
|
|
||||||
|
|
@ -1,891 +0,0 @@
|
||||||
/* ---- 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 $ */
|
|
||||||
|
|
@ -1,424 +0,0 @@
|
||||||
#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 $ */
|
|
||||||
|
|
@ -1,378 +0,0 @@
|
||||||
/* ---- 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 $ */
|
|
||||||
|
|
@ -1,384 +0,0 @@
|
||||||
#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 $ */
|
|
||||||
|
|
@ -1,424 +0,0 @@
|
||||||
/* 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 $ */
|
|
||||||
|
|
@ -1,500 +0,0 @@
|
||||||
/** 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 $ */
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
/* ---- 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 $ */
|
|
||||||
|
|
@ -1,558 +0,0 @@
|
||||||
/* ---- 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 $ */
|
|
||||||
|
|
@ -1,89 +0,0 @@
|
||||||
/* 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 $ */
|
|
||||||
|
|
@ -1,199 +0,0 @@
|
||||||
/* ---- 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 $ */
|
|
||||||
|
|
@ -1,483 +0,0 @@
|
||||||
/* 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,
|
|
||||||
©,
|
|
||||||
|
|
||||||
&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,
|
|
||||||
÷,
|
|
||||||
&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
|
|
||||||
<c_ecc_fp_mulmod,
|
|
||||||
#else
|
|
||||||
<c_ecc_mulmod,
|
|
||||||
#endif
|
|
||||||
<c_ecc_projective_add_point,
|
|
||||||
<c_ecc_projective_dbl_point,
|
|
||||||
<c_ecc_map,
|
|
||||||
#ifdef LTC_ECC_SHAMIR
|
|
||||||
#ifdef LTC_MECC_FP
|
|
||||||
<c_ecc_fp_mul2add,
|
|
||||||
#else
|
|
||||||
<c_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 $ */
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
/* 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 $ */
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
/* 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 $ */
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
/* 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 $ */
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
/* 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 $ */
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
/* 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(<c_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(<c_hash_mutex);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LTC_MUTEX_UNLOCK(<c_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 $ */
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
/* 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(<c_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(<c_prng_mutex);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LTC_MUTEX_UNLOCK(<c_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 $ */
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
/* 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 $ */
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
/* 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(<c_hash_mutex);
|
|
||||||
if (idx < 0 || idx >= TAB_SIZE || hash_descriptor[idx].name == NULL) {
|
|
||||||
LTC_MUTEX_UNLOCK(<c_hash_mutex);
|
|
||||||
return CRYPT_INVALID_HASH;
|
|
||||||
}
|
|
||||||
LTC_MUTEX_UNLOCK(<c_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 $ */
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
/*****************************************************************************/
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue