diff --git a/.gitignore b/.gitignore
index 7fc5529b..e67c91df 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,18 +1,18 @@
-/dist/rhash.spec
-/dist/rhash.1.*
-/dist/librhash.pc
-/librhash/exports.sym
-po/*.gmo
-/rhash
-/rhash_shared
-/rhash_static
-/librhash/test_shared
-/librhash/test_static
-config.mak
-*.[ao]
-*.exe
-*.dll
-*.def
-*.so
-*.so.0
-*.log
+/dist/rhash.spec
+/dist/rhash.1.*
+/dist/librhash.pc
+/librhash/exports.sym
+po/*.gmo
+/rhash
+/rhash_shared
+/rhash_static
+/librhash/test_shared
+/librhash/test_static
+config.mak
+*.[ao]
+*.exe
+*.dll
+*.def
+*.so
+*.so.0
+*.log
diff --git a/COPYING b/COPYING
index bf65ee1a..e5f1d30a 100644
--- a/COPYING
+++ b/COPYING
@@ -1,15 +1,15 @@
-
- RHash License
-
-Copyright (c) 2005-2014 Aleksey Kravchenko
-
-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.
-
-The Software 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. Use this program at your own risk!
+
+ RHash License
+
+Copyright (c) 2005-2014 Aleksey Kravchenko
+
+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.
+
+The Software 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. Use this program at your own risk!
diff --git a/ChangeLog b/ChangeLog
index f383eccb..5f108072 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,724 +1,724 @@
-Mon 04 Feb 2019 Aleksey
- * === Version 1.3.8 ===
-
-Wed Jan 30 2019 Aleksey
- * rename Windows encoding options: --ansi to --win, --oem to --dos
-
-Mon Jan 28 2019 Aleksey
- * support GOST R 34.11-2012 hash function
- * changed the short option `-G' to be alias of --gost12-256
- * changed printf format token `%g' to be alias of %{gost12-256}
-
-Sat Dec 22 2018 Aleksey
- * === Version 1.3.7 ===
- * new option `--message==' to calculate a hash for string
- * changed magnet link short option from '-m' to '-g'
-
-Sat Sep 29 2018 Aleksey
- * Bugfix: `--file-list=-' shall read a file list from stdin
-
-Tue Sep 11 2018 Aleksey
- * CRC32C hash function supported, option --crc32c
- * speedup CRC32 hash function
-
-Wed Mar 14 2018 Aleksey
- * === Version 1.3.6 ===
- * support --file-list option
-
-Sun Mar 11 2018 And Sch
- * librhash: speedup sha3
-
-Sun Feb 18 2018 Aleksey
- * Bugfix: fix --follow option
-
-Mon Jan 29 2018 J. Peter Mugaas
- * better MSYS and CygWin support
-
-Fri Jan 26 2018 Aleksey
- * configuration script
-
-Mon Sep 4 2017 Aleksey
- * Bugfix: broken binary hash output
-
-Mon Aug 28 2017 Aleksey
- * Bugfix: fix running on WinXP
-
-Mon Aug 14 2017 Aleksey
- * === Version 1.3.5 ===
- * look for locales directory at PROGRAM_DIRECTORY\locale on Windows
- * look for config at PROGRAM_DIRECTORY\rhashrc on Windows
-
-Fri Aug 4 2017 Aleksey
- * support LibRhash bindings to PHP7
-
-Sun Jul 30 2017 Aleksey
- * Bugfix: illegal instruction error on macOS
-
-Sat Jul 29 2017 Aleksey
- * improve utf-8 support on Windows
-
-Thu Jul 27 2017 Aleksey
- * Bugfix: fix access to long paths on Windows
-
-Mon Jul 17 2017 Aleksey
- * add ca, fr, ro translations
-
-Sun Jul 16 2017 Darío Hereñú
- * full Spanish translation
-
-Mon Jul 10 2017 James Le Cuirot
- * correct build/install command for freebsd
-
-Mon Jul 10 2017 Przemyslaw Pawelczyk
- * compilation fixes for aarch64 and musl
-
-Mon Jul 10 2017 Aleksey
- * improve support of clang on macOS
-
-Sun Nov 6 2016 Aleksey
- * === Version 1.3.4 ===
-
-Tue Nov 17 2015 Alexey Dokuchaev, Kurt Jaeger
- * compilation fixes for FreeBSD
-
-Sat Aug 9 2014 Aleksey
- * return non zero exit code if a file was not found
-
-Tue Aug 5 2014 Aleksey
- * === Version 1.3.3 ===
-
-Mon Aug 4 2014 And Sch, Aleksey
- * librhash: small optimization of Whirlpool
-
-Sat Aug 2 2014 Aleksey
- * option --exclude for skipping some files during recursive scanning
-
-Fri Aug 1 2014 Aleksey
- * update the SHA3 algorithm to follow the changes of the FIPS 202 draft
-
-Wed Jul 30 2014 Aleksey
- * support torrents with more than one announce url
-
-Tue Jul 29 2014 Aleksey
- * LibRHash now exports torrent functions
-
-Mon Jul 21 2014 Tsukasa Oi
- * fixed test_rhash.sh script failing on the en_US.UTF-8 locale
-
-Wed Jul 16 2014 Aleksey
- * changed the `-p' format names of sha* families, see manpage
- * set a boolean in config to true by a string `true', `on' or `yes'
-
-Sun Jul 13 2014 Aleksey
- * Ctrl-C now interrupts benchmarking
-
-Wed Jul 2 2014 Aleksey
- * === Version 1.3.2 ===
-
-Sat Jun 21 2014 Aleksey
- * report warnings on files locked by some processes
-
-Thu Jun 19 2014 Brad Campbell
- * ignore non-regular files while scanning directories recursively
-
-Wed Jun 18 2014 Aleksey
- * option --follow for following symlinks to directories
-
-Sun Apr 13 2014 ZinnKid
- * BTIH piece length calculation updated to follow the uTorrent algorithm change
-
-Wed Jan 8 2014 Aleksey
- * === Version 1.3.1 ===
- * Exclude the files specified by -o and -l from processing
-
-Sat Jan 4 2014 Aleksey
- * Improved directory scanning
-
-Sat Dec 28 2013 Aleksey
- * Bugfix: suppress the R6034 error popup on Windows
-
-Fri Oct 25 2013 Aleksey
- * Fixed 'value too large' error on 32-bit Linux
-
-Thu Sep 19 2013 Aleksey
- * Bugfix: corrected sha3-224 for big-endian processors
-
-Tue Sep 17 2013 Aleksey
- * === Version 1.3.0 ===
-
-Tue May 21 2013 Aleksey
- * Fixed output of percents when two or more files are hashed
-
-Mon Apr 29 2013 Aleksey
- * Supported SHA3 (Keccak) hash function
-
-Sat Apr 27 2013 Aleksey
- * Fixed memory leaks
-
-Tue Apr 23 2013 Aleksey
- * Bugfix: %{mtime} formatting option was broken
-
-Mon Dec 31 2012 Aleksey
- * imported translations from Launchpad: de, es, gl, it
-
-Tue Dec 25 2012 Aleksey
- * === Version 1.2.10 ===
-
-Mon Nov 5 2012 Aleksey
- * Bugfix: incorrect GOST hash for ("\FF" x 64) on non-x86 CPU
-
-Mon Oct 8 2012 Aleksey
- * Shortcut -k for --check-embedded
-
-Thu Sep 27 2012 Aleksey
- * Bugfix: non-zero exit code if some files were not found
- * improved Ctrl-C processing
-
-Sat Aug 4 2012 Aleksey
- * Bugfix: path issue with verification of hash files
-
-Mon Jun 25 2012 Aleksey
- * Bugfix: different BTIH were generated for the same file
-
-Sun May 13 2012 Aleksey
- * BugFix: python crashed on ia64
-
-Tue Apr 17 2012 Aleksey
- * PHP bindings for librhash
-
-Sat Apr 14 2012 Aleksey
- * === Version 1.2.9 ===
-
-Fri Apr 13 2012 Aleksey, Sergey Basalaev
- * translations: de, en_AU, es, gl, it
-
-Sun Apr 08 2012 Aleksey
- * Bugfix: handling UNC filenames on Windows
- * option --bt-batch for batch torrents
-
-Sat Jan 7 2012 Aleksey
- * librhash: rhash_print_magnet function
-
-Sun Nov 06 2011 Sergey Basalaev
- * .NET/Mono bindings to librhash
-
-Wed Sep 14 2011 Aleksey
- * === Version 1.2.8 ===
-
-Wed Sep 14 2011 Aleksey, SBasalaev
- * LibRHash bindings to Java, Perl, Python, Ruby
-
-Tue Sep 6 2011 Aleksey
- * librhash: implemented auto-final feature, turned on by default
-
-Tue Sep 6 2011 Aleksey, SBasalaev
- * Russian translation
-
-Sat Sep 3 2011 Aleksey
- * Bugfix: not enough trailing '=' in a base64-encoded hash
-
-Sat Aug 20 2011 Aleksey
- * Bugfix: fix broken --openssl option parsing
- * Bugfix: buffer overflow when using --embed-crc-delimiter
- * Bugfix: segmentation fault on SUSE Linux
-
-Sun Aug 14 2011 Aleksey
- * === Version 1.2.7 ===
-
-Sun Aug 7 2011 Aleksey
- * Bugfix: percents option was broken in v1.2.6
-
-Fri Aug 5 2011 Aleksey
- * supported verification of sha256, sha512 and other hash sums
-
-Mon Jul 11 2011 Aleksey
- * librhash: rhash_cancel() macro to cancel hashing from another thread
-
-Fri Jun 24 2011 Aleksey
- * Bugfix: repaired default output encoding to be UTF-8 on Windows
-
-Wed Jun 22 2011 Aleksey
- * Bugfix: crash on WinXP
-
-Thu Jun 16 2011 Aleksey
- * === Version 1.2.6 ===
-
-Sat Jun 11 2011 Aleksey
- * allowed options to be intermixed with file names in arbitrary order
- * switched option -G and the '%G' printf pattern to print GOST hash
- * Bugfix: --output failed for cyrillic file name
-
-Wed Jun 8 2011 Aleksey
- * librhash: better shared library compilation/testing support
-
-Mon Jun 6 2011 Aleksey
- * librhash: exported benchmarking functions in the shared library
- * librhash: added prefix to all functions to avoid poluting linker namespace
- * librhash: fixed rare alignment bugs in rhash_print and EDON-R 512
-
-Sat May 28 2011 Aleksey
- * librhash: loading openssl at runtime if it is present
- * Bugfix: LLVM GOST amd64 asm compilation error
-
-Wed May 18 2011 Aleksey
- * === Version 1.2.5 ===
- * option --openssl allows to replace some algorithms by the OpenSSL ones
- * Bugfix: incorrect recursive traversing of very long UTF-8 filepaths
-
-Wed Apr 27 2011 Aleksey
- * Bugfix: corrected calculation of BTIH hash and torrent files
-
-Fri Apr 15 2011 Aleksey
- * === Version 1.2.4 ===
- * option --benchmark-raw for machine-readable benchmark output format
- * on Intel/AMD CPUs benchmark now prints the clocks-per-byte value
-
-Tue Apr 5 2011 Aleksey
- * changed config file locations
-
-Fri Apr 1 2011 Aleksey
- * Bugfix: repaired --path-separator on linux/unix
-
-Sun Mar 27 2011 Aleksey
- * === Version 1.2.3 ===
-
-Fri Mar 25 2011 Aleksey
- * one-line percent for linux/unix
-
-Mon Mar 14 2011 Aleksey
- * added printf modificator %{mtime} to print the last modified date of a file
-
-Thu Feb 17 2011 Aleksey
- * Bugfix: verification of base2-like formatted md5 hash sums
-
-Fri Jan 14 2011 Aleksey
- * === Version 1.2.2 ===
- * one-line percents (windows only)
-
-Tue Jan 11 2011 Aleksey
- * supported EDON-R 256/512 hash sums
-
-Sun Dec 19 2010 Aleksey
- * increased process priority when benchmarking on windows
-
-Thu Dec 16 2010 Aleksey
- * Bugfix: eight hash sums were broken on PowerPC
- * Bugfix: --accept/--crc-accept were not working since 1.1.9
-
-Tue Dec 14 2010 Aleksey
- * === Version 1.2.1 ===
- * Bugfix: GOST broken on OpenSolaris since 1.2.0
- * option --list-hashes: list names of all supported hashes, one per line
-
-Mon Nov 29 2010 Aleksey
- * SHA 224/256/384/512 hash functions supported
- * Bugfix: broken asm compilation on openbsd and freebsd
-
-Wed Nov 24 2010 Aleksey
- * option --path-separator= for directories scanning
-
-Sun Nov 14 2010 Aleksey
- * === Version 1.2.0 ===
- * --gost-cryptopro option: calculate GOST with CryptoPro parameters
- * --gost-reverse option: reverse bytes in GOST hash sum
- * Bugfix: btih/gost/ripemd/has160/snefru were not verified correctly in bsd and magnet formats
-
-Fri Oct 29 2010 Aleksey
- * Bugfix: rhash compiled by MS VC skipped files of size >4Gb
-
-Fri Oct 15 2010 Aleksey
- * === Version 1.1.9 ===
- * new interface for internal library librhash
-
-Mon Jul 5 2010 Ruslan Nikolaev
- * GOST algorithm x86-64 assembler optimization
-
-Sun Apr 25 2010 Aleksey
- * new options --uppercase and --lowercase
- * Bugfix: GOST worked incorrectly when compiled by GCC with `-O0'
-
-Wed Apr 21 2010 Aleksey
- * windows distribution updated
-
-Fri Apr 16 2010 Aleksey
- * BugFix: options with string values were incorrectly loaded from config
-
-Wed Apr 14 2010 Aleksey
- * === Version 1.1.8 ===
- * option --template= to read printf-like template from
-
-Mon Apr 12 2010 Xiangli Huang
- * BugFix: `--recursive *' traversed parent directory .. under windows
- * BugFix: `--check ' reported strange warning for dirs
-
-Mon Apr 12 2010 Aleksey
- * printf-directives starting with capital letter print upper-cased hashes, e.g. %{Gost}
- * %u directive switched to print url-encoded filename (alias for %{urlname})
- * ed2k links verification supported
-
-Fri Apr 9 2010 Aleksey
- * BugFix: linking problem on OpenSolaris
- * filenames in urls are now always utf8-encoded (Windows only fix)
-
-Wed Apr 7 2010 Aleksey
- * '%B','%@' modifiers to print base64/raw representation of any hash (e.g. '%BM')
-
-Wed Mar 31 2010 Aleksey
- * === Version 1.1.7 ===
- * option --btih to print BitTorrent infohash
- * option --torrent to create torrent file
- * option --bt-private for private torrents
- * option --bt-piece-length to change torrent piece length
- * option --bt-announce to set torrent announcement url
-
-Tue Mar 30 2010 Aleksey
- * the -m option made to be an alias for --magnet
-
-Mon Mar 29 2010 Xiangli Huang
- * print program version, when benchmarking
-
-Fri Mar 26 2010 Aleksey
- * Bugfix: infite loop while recursively updating hash files under Windows
-
-Thu Mar 4 2010 Aleksey
- * maxdepth parameter now is checked to be a number
-
-Thu Feb 25 2010 Aleksey
- * output tiger hash in the big-endian order
-
-Wed Feb 24 2010 Aleksey
- * === Version 1.1.6 ===
- * man page updated
- * now all supported hashes are verified when cheking magnet links
- * benchmark now reports the size of the hashed message
-
-Fri Feb 19 2010 Aleksey
- * Bugfix: fixed GOST for big-endian systems
-
-Wed Feb 17 2010 Aleksey
- * Bugfix: buffer owerflow while parsing long command line under Windows
-
-Sun Feb 14 2010 Aleksey
- * Bugfix: fixed HAS-160 for big-endian systems
-
-Wed Feb 3 2010 Aleksey
- * Bugfix: crash while printing sfv header for files modified before 1970
-
-Fri Jan 29 2010 Aleksey
- * Bugfix: sfv-hash symlink now sets default print format to SFV
- * Bugfix: ed2k-link symlink did not work as expected
-
-Thu Jan 28 2010 Aleksey
- * === Version 1.1.5 ===
- * option --utf8 under Windows, also UTF8 now is the default encoding
- * Bugfix: non-existing files were reported twice in `-r --sfv' mode
-
-Wed Jan 27 2010 Aleksey
- * option --embed-crc-delimiter= to insert before a crc sum in -e mode
- * alias -e for --embed-crc
- * alias -B for --benchmark
-
-Mon Jan 11 2010 Aleksey
- * Bugfix: percents output fixed for files of more than 4Gb of data
-
-Fri Dec 18 2009 Aleksey
- * AICH algorithm has been re-written to process files of unknown size like stdin, pipes, sockets
- * ED2K switched to use eMule algorithm when filesize is an exact multiple of 9728000 bytes
-
-Thu Dec 17 2009 Aleksey
- * Bugfix: buffer overflow when printing eDonkey links for 0-sized files
- * Bugfix: --ripemd160 and --md4 option were broken
- * added `%R' printf entity for RIPEMD-160
-
-Mon Dec 14 2009 Aleksey
- * === Version 1.1.4 ===
- * supported algorithms: RIPEMD-160, HAS-160, GOST, MD4, SNEFRU-128, SNEFRU-256
- * long printf format entities, e.g. %{md4}, %{has160}, %{gost}, %{snefru256}
- * `u' printf modifier for uppercase hashes, e.g. %u{gost}
- * switched to %{urlname} printf-entity for url-encoded file name
- * useful symlinks are installed by `make install-symlinks'
-
-Sun Dec 6 2009 Aleksey
- * WHIRLPOOL hash function supported, option --whirlpool
-
-Wed Dec 2 2009 Aleksey
- * print file checking statistics when --check-embedded specified
-
-Sun Nov 29 2009 Aleksey
- * === Version 1.1.3 ===
- * forbid simultaneous usage of --check, --update and --check-embedded options
-
-Sun Nov 22 2009 Aleksey
- * Bugfix: Checking of md5 file always reported OK
- * --check-embedded option to verify files by crc32 sum embedded in their names.
- * --embed-crc option to rename processed files by embedding crc32 sum into name.
-
-Mon Nov 9 2009 Aleksey
- * --benchmark option now prints names of tested hash sums
- * use magnet format as default if the program name contains 'magnet'
-
-Wed Jun 24 2009 Aleksey
- * supported checking of files containing a single hash sum without a filename
-
-Mon Jun 15 2009 Aleksey
- * === Version 1.1.2 ===
- * verification of files with magnet links supported
-
-Wed May 20 2009 Aleksey
- * Bugfix: --skip-ok was broken since 1.1.0
-
-Fri May 15 2009 Aleksey
- * Bugfix: checking of ed2k hashes was broken since version 1.1.0
- * Bugfix: --verbose lead to crash under OpenSolaris when config file not present
-
-Mon Mar 23 2009 Aleksey
- * === Version 1.1.1 ===
- * config file described in the man page
- * Bugfix: buffer owerflow when printing tiger hash
-
-Sat Mar 21 2009 Aleksey
- * Bugfix: some options couldn't be read from config file
-
-Sat Mar 14 2009 Aleksey
- * === Version 1.1.0 ===
- * various small changes and refactoring
-
-Tue Mar 10 2009 Aleksey
- * option --speed to print per-file and total speed statistics
-
-Thu Mar 5 2009 Aleksey
- * option --output to write calculation and check results to a file
- * option --log to log percents, speed and verbose messages
-
-Wed Mar 4 2009 Aleksey
- * option --percents to show wget-like percents
-
-Tue Feb 26 2009 Aleksey
- * Bugfix: fixed processing of unaligned messages in the get_crc32() function
-
-Sat Feb 14 2009 Aleksey
- * === Version 1.0.8 ===
- * --magnet option supported to format sums as a magnet link
- * Bugfix: printf option from config conflicted with command line
-
-Sun Dec 14 2008 Aleksey
- * === Version 1.0.7 ===
- * config file supported to load default options values
- * if --verbose, report verification errors as "sum is XXXXXXXX, should be YYYYYYYY"
- * '%h' modifier changed to '%x'
-
-Fri Nov 14 2008 Aleksey
- * === Version 1.0.6 ===
- * reg-file for FAR user menu
-
-Thu Oct 9 2008 Aleksey
- * interpret '#' symbol as a comment
-
-Sat Sep 20 2008 ivan386
- * under windows skip files openned for writing
- * Bugfix: printf arguments %p and %f corrected
-
-Sun Sep 14 2008 Aleksey
- * === Version 1.0.5 ===
-
-Wed Aug 6 2008 Aleksey
- * '%b','%h' modifiers to print base32/hex representation of any hash (e.g. '%bH')
- * supported -p '\0' symbol
- * supported setting width for filesizes (e.g. -p '%12s')
-
-Tue Jul 22 2008 Aleksey
- * --verbose prints read speed statistics to stderr after each file
- * read buffer increased to 2 MiB
-
-Wed Jul 9 2008 Aleksey
- * === Version 1.0.4 ===
- * '%u' prints URL-encoded filename
- * EDonkey links now have URL-encoded filename and contain AICH hash
-
-Mon Jul 7 2008 Aleksey
- * AICH hashsums supported, option --aich
-
-Sat Jun 28 2008 Aleksey
- * === Version 1.0.3 ===
- * ed2k calculation fixed for files with 9728000 < filesize <= 9732096
- * Big-endian processors supported for all sums
-
-Sat Jun 14 2008 Aleksey
- * === Version 1.0.2 ===
-
-Fri Jun 6 2008 Aleksey
- * --benchmark option added
- * skip locked files under win32 when calculating 'em sums
-
-Tue May 20 2008 Aleksey
- * Bugfix: updating of md5 files was broken
- * Bugfix: more rigid parsing of base32/hex hash sums
-
-Wed May 15 2008 Aleksey
- * === Version 1.0.1 ===
- * Bugfix: last line without '\n' couldn't be parsed
-
-Wed May 14 2008 Aleksey
- * Bugfix: empty lines were not skipped, when verifying a crc file
- * option '--skip-ok' to skip OK messages for successfuly verified files
-
-Tue Jan 22 2008 Aleksey
- * option '-a' to print all supported hash sums
- * Changed default behavior: if no formatting option are set, sfv header is printed only for --crc32
-
-Wed Dec 19 2007 Aleksey
- * Bugfix: fixed buffer overflow for command line -p '%%%%d'
- * Bugfix: fixed size calculation for stdin (rhash -p '%s' - = 56
- * Tiger hash optimised to be 5% faster
-
-Wed May 02 2007 Aleksey
- * === Version 0.8.8 ===
-
-Sun Apr 22 2007 Aleksey
- * added options --accept and --crc-accept
- * added --verbose option
- * added --maxdepth option
- * added check before verifying a crc file that it isn't a binary file
-
-Mon Apr 16 2007 Aleksey
- * === Version 0.8.7 ===
- * Tiger hash sum optimised for IA32
-
-Tue Apr 10 2007 Aleksey
- * Bugfix: --update of sfv files worked incorrectly under windows
-
-Mon Apr 09 2007 Aleksey
- * implemented Tiger hash function
-
-Sun Apr 01 2007 Aleksey
- * added check before updating a crc file that it isn't a binary file
-
-Mon Mar 26 2007 Aleksey
- * === Version 0.8.6 ===
- * Ctrl+C now prints a message and partitial statistics
-
-Sat Mar 24 2007 Aleksey
- * default format changed to SFV
-
-Mon Mar 19 2007 Aleksey
- * updating of crc files supported
-
-Wed Jan 31 2007 Aleksey
- * === Version 0.8.5 ===
- * supported many short options as one argument, e.g. '-MCEr'
- * option -S (--sha1) changed to -H
- * Bugfix: program crashed under BSD while printing SFV file header
-
-Sun Nov 05 2006 Aleksey
- * === Version 0.8.4 ===
- * Bugfix: errors/miss stats calculation corrected
-
-Sun Oct 29 2006 Aleksey
- * supported "-c -" option to check hash sums from stdin
- * added stdout flushing after each processed file
- * the program returns exit code 0 on success and 1 if an error occurred
-
-Fri Sep 08 2006 Aleksey
- * corrected parsing of md5-like files with star-prepended filenames
-
-Wed Apr 19 2006 Aleksey
- * checking of md5/sha1 files in *BSD format supported
- * improved I/O errors handling
-
-Mon Apr 10 2006 Aleksey
- * === Version 0.8.3 ===
- * cheking of files in standard md5sum/sha1sum format supported
- * default output format for md5/sha1/ed2k sums changed
- * man page rewrited
-
-Thu Mar 30 2006 Aleksey
- * === Version 0.8.2 ===
- * GCC 2.96 supported
-
-Thu Feb 23 2006 Aleksey
- * Bugfix: files with .SFV extension (in uppercase) were skiped while recursive checking
-
-Wed Jan 25 2006 Aleksey
- * === Version 0.8.1 ===
- * option --check now works with --recursive
- * Bugfix: corrected output format when checking files
- * Bugfix: files wasn't opened as binary on Windows when checking sums
-
-Mon Jan 23 2006 Aleksey
- * === Version 0.8 ===
- * documentation now distributed with windows version
- * some *.bat files added to windows version
-
-Sun Jan 22 2006 Aleksey
- * --check option added, to check hash sums files
- * --ansi option added (for Windows version only)
- * program name is parsed now to specify default sums to compute
-
-Sat Jan 14 2006 Aleksey
- * Bugfix: console windows version now uses OEM (DOS) character set for output
-
- * === Version 0.7 ===
- * some fixes in sfv format output
-
-Fri Sep 16 2005 Aleksey
- * --recursive option added
- * --ed2k-link option added
-
-Fri Sep 02 2005 Aleksey
- * === Version 0.6 ===
-
-Sun Aug 28 2005 Aleksey
- * Bugfix: files wasn't opened as binary on win32
- * --sfv format now implies uppercase hashes
-
-Wed Aug 24 2005 Aleksey
- * added .spec file and Makefile 'rpm' target
-
-Sun Aug 14 2005 Aleksey
- * === Version 0.5 ===
- * the first public version
- * win32 platform supported
-
-Mon Aug 08 2005 Aleksey
- * Bugfix: fixed calculation of md5/ed2k hashes for AMD64
-
-Fri Aug 05 2005 Aleksey
- * === Version 0.06 ===
- * initial linux version supporting crc32, md5, ed2k and sha1
+Mon 04 Feb 2019 Aleksey
+ * === Version 1.3.8 ===
+
+Wed Jan 30 2019 Aleksey
+ * rename Windows encoding options: --ansi to --win, --oem to --dos
+
+Mon Jan 28 2019 Aleksey
+ * support GOST R 34.11-2012 hash function
+ * changed the short option `-G' to be alias of --gost12-256
+ * changed printf format token `%g' to be alias of %{gost12-256}
+
+Sat Dec 22 2018 Aleksey
+ * === Version 1.3.7 ===
+ * new option `--message==' to calculate a hash for string
+ * changed magnet link short option from '-m' to '-g'
+
+Sat Sep 29 2018 Aleksey
+ * Bugfix: `--file-list=-' shall read a file list from stdin
+
+Tue Sep 11 2018 Aleksey
+ * CRC32C hash function supported, option --crc32c
+ * speedup CRC32 hash function
+
+Wed Mar 14 2018 Aleksey
+ * === Version 1.3.6 ===
+ * support --file-list option
+
+Sun Mar 11 2018 And Sch
+ * librhash: speedup sha3
+
+Sun Feb 18 2018 Aleksey
+ * Bugfix: fix --follow option
+
+Mon Jan 29 2018 J. Peter Mugaas
+ * better MSYS and CygWin support
+
+Fri Jan 26 2018 Aleksey
+ * configuration script
+
+Mon Sep 4 2017 Aleksey
+ * Bugfix: broken binary hash output
+
+Mon Aug 28 2017 Aleksey
+ * Bugfix: fix running on WinXP
+
+Mon Aug 14 2017 Aleksey
+ * === Version 1.3.5 ===
+ * look for locales directory at PROGRAM_DIRECTORY\locale on Windows
+ * look for config at PROGRAM_DIRECTORY\rhashrc on Windows
+
+Fri Aug 4 2017 Aleksey
+ * support LibRhash bindings to PHP7
+
+Sun Jul 30 2017 Aleksey
+ * Bugfix: illegal instruction error on macOS
+
+Sat Jul 29 2017 Aleksey
+ * improve utf-8 support on Windows
+
+Thu Jul 27 2017 Aleksey
+ * Bugfix: fix access to long paths on Windows
+
+Mon Jul 17 2017 Aleksey
+ * add ca, fr, ro translations
+
+Sun Jul 16 2017 Darío Hereñú
+ * full Spanish translation
+
+Mon Jul 10 2017 James Le Cuirot
+ * correct build/install command for freebsd
+
+Mon Jul 10 2017 Przemyslaw Pawelczyk
+ * compilation fixes for aarch64 and musl
+
+Mon Jul 10 2017 Aleksey
+ * improve support of clang on macOS
+
+Sun Nov 6 2016 Aleksey
+ * === Version 1.3.4 ===
+
+Tue Nov 17 2015 Alexey Dokuchaev, Kurt Jaeger
+ * compilation fixes for FreeBSD
+
+Sat Aug 9 2014 Aleksey
+ * return non zero exit code if a file was not found
+
+Tue Aug 5 2014 Aleksey
+ * === Version 1.3.3 ===
+
+Mon Aug 4 2014 And Sch, Aleksey
+ * librhash: small optimization of Whirlpool
+
+Sat Aug 2 2014 Aleksey
+ * option --exclude for skipping some files during recursive scanning
+
+Fri Aug 1 2014 Aleksey
+ * update the SHA3 algorithm to follow the changes of the FIPS 202 draft
+
+Wed Jul 30 2014 Aleksey
+ * support torrents with more than one announce url
+
+Tue Jul 29 2014 Aleksey
+ * LibRHash now exports torrent functions
+
+Mon Jul 21 2014 Tsukasa Oi
+ * fixed test_rhash.sh script failing on the en_US.UTF-8 locale
+
+Wed Jul 16 2014 Aleksey
+ * changed the `-p' format names of sha* families, see manpage
+ * set a boolean in config to true by a string `true', `on' or `yes'
+
+Sun Jul 13 2014 Aleksey
+ * Ctrl-C now interrupts benchmarking
+
+Wed Jul 2 2014 Aleksey
+ * === Version 1.3.2 ===
+
+Sat Jun 21 2014 Aleksey
+ * report warnings on files locked by some processes
+
+Thu Jun 19 2014 Brad Campbell
+ * ignore non-regular files while scanning directories recursively
+
+Wed Jun 18 2014 Aleksey
+ * option --follow for following symlinks to directories
+
+Sun Apr 13 2014 ZinnKid
+ * BTIH piece length calculation updated to follow the uTorrent algorithm change
+
+Wed Jan 8 2014 Aleksey
+ * === Version 1.3.1 ===
+ * Exclude the files specified by -o and -l from processing
+
+Sat Jan 4 2014 Aleksey
+ * Improved directory scanning
+
+Sat Dec 28 2013 Aleksey
+ * Bugfix: suppress the R6034 error popup on Windows
+
+Fri Oct 25 2013 Aleksey
+ * Fixed 'value too large' error on 32-bit Linux
+
+Thu Sep 19 2013 Aleksey
+ * Bugfix: corrected sha3-224 for big-endian processors
+
+Tue Sep 17 2013 Aleksey
+ * === Version 1.3.0 ===
+
+Tue May 21 2013 Aleksey
+ * Fixed output of percents when two or more files are hashed
+
+Mon Apr 29 2013 Aleksey
+ * Supported SHA3 (Keccak) hash function
+
+Sat Apr 27 2013 Aleksey
+ * Fixed memory leaks
+
+Tue Apr 23 2013 Aleksey
+ * Bugfix: %{mtime} formatting option was broken
+
+Mon Dec 31 2012 Aleksey
+ * imported translations from Launchpad: de, es, gl, it
+
+Tue Dec 25 2012 Aleksey
+ * === Version 1.2.10 ===
+
+Mon Nov 5 2012 Aleksey
+ * Bugfix: incorrect GOST hash for ("\FF" x 64) on non-x86 CPU
+
+Mon Oct 8 2012 Aleksey
+ * Shortcut -k for --check-embedded
+
+Thu Sep 27 2012 Aleksey
+ * Bugfix: non-zero exit code if some files were not found
+ * improved Ctrl-C processing
+
+Sat Aug 4 2012 Aleksey
+ * Bugfix: path issue with verification of hash files
+
+Mon Jun 25 2012 Aleksey
+ * Bugfix: different BTIH were generated for the same file
+
+Sun May 13 2012 Aleksey
+ * BugFix: python crashed on ia64
+
+Tue Apr 17 2012 Aleksey
+ * PHP bindings for librhash
+
+Sat Apr 14 2012 Aleksey
+ * === Version 1.2.9 ===
+
+Fri Apr 13 2012 Aleksey, Sergey Basalaev
+ * translations: de, en_AU, es, gl, it
+
+Sun Apr 08 2012 Aleksey
+ * Bugfix: handling UNC filenames on Windows
+ * option --bt-batch for batch torrents
+
+Sat Jan 7 2012 Aleksey
+ * librhash: rhash_print_magnet function
+
+Sun Nov 06 2011 Sergey Basalaev
+ * .NET/Mono bindings to librhash
+
+Wed Sep 14 2011 Aleksey
+ * === Version 1.2.8 ===
+
+Wed Sep 14 2011 Aleksey, SBasalaev
+ * LibRHash bindings to Java, Perl, Python, Ruby
+
+Tue Sep 6 2011 Aleksey
+ * librhash: implemented auto-final feature, turned on by default
+
+Tue Sep 6 2011 Aleksey, SBasalaev
+ * Russian translation
+
+Sat Sep 3 2011 Aleksey
+ * Bugfix: not enough trailing '=' in a base64-encoded hash
+
+Sat Aug 20 2011 Aleksey
+ * Bugfix: fix broken --openssl option parsing
+ * Bugfix: buffer overflow when using --embed-crc-delimiter
+ * Bugfix: segmentation fault on SUSE Linux
+
+Sun Aug 14 2011 Aleksey
+ * === Version 1.2.7 ===
+
+Sun Aug 7 2011 Aleksey
+ * Bugfix: percents option was broken in v1.2.6
+
+Fri Aug 5 2011 Aleksey
+ * supported verification of sha256, sha512 and other hash sums
+
+Mon Jul 11 2011 Aleksey
+ * librhash: rhash_cancel() macro to cancel hashing from another thread
+
+Fri Jun 24 2011 Aleksey
+ * Bugfix: repaired default output encoding to be UTF-8 on Windows
+
+Wed Jun 22 2011 Aleksey
+ * Bugfix: crash on WinXP
+
+Thu Jun 16 2011 Aleksey
+ * === Version 1.2.6 ===
+
+Sat Jun 11 2011 Aleksey
+ * allowed options to be intermixed with file names in arbitrary order
+ * switched option -G and the '%G' printf pattern to print GOST hash
+ * Bugfix: --output failed for cyrillic file name
+
+Wed Jun 8 2011 Aleksey
+ * librhash: better shared library compilation/testing support
+
+Mon Jun 6 2011 Aleksey
+ * librhash: exported benchmarking functions in the shared library
+ * librhash: added prefix to all functions to avoid poluting linker namespace
+ * librhash: fixed rare alignment bugs in rhash_print and EDON-R 512
+
+Sat May 28 2011 Aleksey
+ * librhash: loading openssl at runtime if it is present
+ * Bugfix: LLVM GOST amd64 asm compilation error
+
+Wed May 18 2011 Aleksey
+ * === Version 1.2.5 ===
+ * option --openssl allows to replace some algorithms by the OpenSSL ones
+ * Bugfix: incorrect recursive traversing of very long UTF-8 filepaths
+
+Wed Apr 27 2011 Aleksey
+ * Bugfix: corrected calculation of BTIH hash and torrent files
+
+Fri Apr 15 2011 Aleksey
+ * === Version 1.2.4 ===
+ * option --benchmark-raw for machine-readable benchmark output format
+ * on Intel/AMD CPUs benchmark now prints the clocks-per-byte value
+
+Tue Apr 5 2011 Aleksey
+ * changed config file locations
+
+Fri Apr 1 2011 Aleksey
+ * Bugfix: repaired --path-separator on linux/unix
+
+Sun Mar 27 2011 Aleksey
+ * === Version 1.2.3 ===
+
+Fri Mar 25 2011 Aleksey
+ * one-line percent for linux/unix
+
+Mon Mar 14 2011 Aleksey
+ * added printf modificator %{mtime} to print the last modified date of a file
+
+Thu Feb 17 2011 Aleksey
+ * Bugfix: verification of base2-like formatted md5 hash sums
+
+Fri Jan 14 2011 Aleksey
+ * === Version 1.2.2 ===
+ * one-line percents (windows only)
+
+Tue Jan 11 2011 Aleksey
+ * supported EDON-R 256/512 hash sums
+
+Sun Dec 19 2010 Aleksey
+ * increased process priority when benchmarking on windows
+
+Thu Dec 16 2010 Aleksey
+ * Bugfix: eight hash sums were broken on PowerPC
+ * Bugfix: --accept/--crc-accept were not working since 1.1.9
+
+Tue Dec 14 2010 Aleksey
+ * === Version 1.2.1 ===
+ * Bugfix: GOST broken on OpenSolaris since 1.2.0
+ * option --list-hashes: list names of all supported hashes, one per line
+
+Mon Nov 29 2010 Aleksey
+ * SHA 224/256/384/512 hash functions supported
+ * Bugfix: broken asm compilation on openbsd and freebsd
+
+Wed Nov 24 2010 Aleksey
+ * option --path-separator= for directories scanning
+
+Sun Nov 14 2010 Aleksey
+ * === Version 1.2.0 ===
+ * --gost-cryptopro option: calculate GOST with CryptoPro parameters
+ * --gost-reverse option: reverse bytes in GOST hash sum
+ * Bugfix: btih/gost/ripemd/has160/snefru were not verified correctly in bsd and magnet formats
+
+Fri Oct 29 2010 Aleksey
+ * Bugfix: rhash compiled by MS VC skipped files of size >4Gb
+
+Fri Oct 15 2010 Aleksey
+ * === Version 1.1.9 ===
+ * new interface for internal library librhash
+
+Mon Jul 5 2010 Ruslan Nikolaev
+ * GOST algorithm x86-64 assembler optimization
+
+Sun Apr 25 2010 Aleksey
+ * new options --uppercase and --lowercase
+ * Bugfix: GOST worked incorrectly when compiled by GCC with `-O0'
+
+Wed Apr 21 2010 Aleksey
+ * windows distribution updated
+
+Fri Apr 16 2010 Aleksey
+ * BugFix: options with string values were incorrectly loaded from config
+
+Wed Apr 14 2010 Aleksey
+ * === Version 1.1.8 ===
+ * option --template= to read printf-like template from
+
+Mon Apr 12 2010 Xiangli Huang
+ * BugFix: `--recursive *' traversed parent directory .. under windows
+ * BugFix: `--check ' reported strange warning for dirs
+
+Mon Apr 12 2010 Aleksey
+ * printf-directives starting with capital letter print upper-cased hashes, e.g. %{Gost}
+ * %u directive switched to print url-encoded filename (alias for %{urlname})
+ * ed2k links verification supported
+
+Fri Apr 9 2010 Aleksey
+ * BugFix: linking problem on OpenSolaris
+ * filenames in urls are now always utf8-encoded (Windows only fix)
+
+Wed Apr 7 2010 Aleksey
+ * '%B','%@' modifiers to print base64/raw representation of any hash (e.g. '%BM')
+
+Wed Mar 31 2010 Aleksey
+ * === Version 1.1.7 ===
+ * option --btih to print BitTorrent infohash
+ * option --torrent to create torrent file
+ * option --bt-private for private torrents
+ * option --bt-piece-length to change torrent piece length
+ * option --bt-announce to set torrent announcement url
+
+Tue Mar 30 2010 Aleksey
+ * the -m option made to be an alias for --magnet
+
+Mon Mar 29 2010 Xiangli Huang
+ * print program version, when benchmarking
+
+Fri Mar 26 2010 Aleksey
+ * Bugfix: infite loop while recursively updating hash files under Windows
+
+Thu Mar 4 2010 Aleksey
+ * maxdepth parameter now is checked to be a number
+
+Thu Feb 25 2010 Aleksey
+ * output tiger hash in the big-endian order
+
+Wed Feb 24 2010 Aleksey
+ * === Version 1.1.6 ===
+ * man page updated
+ * now all supported hashes are verified when cheking magnet links
+ * benchmark now reports the size of the hashed message
+
+Fri Feb 19 2010 Aleksey
+ * Bugfix: fixed GOST for big-endian systems
+
+Wed Feb 17 2010 Aleksey
+ * Bugfix: buffer owerflow while parsing long command line under Windows
+
+Sun Feb 14 2010 Aleksey
+ * Bugfix: fixed HAS-160 for big-endian systems
+
+Wed Feb 3 2010 Aleksey
+ * Bugfix: crash while printing sfv header for files modified before 1970
+
+Fri Jan 29 2010 Aleksey
+ * Bugfix: sfv-hash symlink now sets default print format to SFV
+ * Bugfix: ed2k-link symlink did not work as expected
+
+Thu Jan 28 2010 Aleksey
+ * === Version 1.1.5 ===
+ * option --utf8 under Windows, also UTF8 now is the default encoding
+ * Bugfix: non-existing files were reported twice in `-r --sfv' mode
+
+Wed Jan 27 2010 Aleksey
+ * option --embed-crc-delimiter= to insert before a crc sum in -e mode
+ * alias -e for --embed-crc
+ * alias -B for --benchmark
+
+Mon Jan 11 2010 Aleksey
+ * Bugfix: percents output fixed for files of more than 4Gb of data
+
+Fri Dec 18 2009 Aleksey
+ * AICH algorithm has been re-written to process files of unknown size like stdin, pipes, sockets
+ * ED2K switched to use eMule algorithm when filesize is an exact multiple of 9728000 bytes
+
+Thu Dec 17 2009 Aleksey
+ * Bugfix: buffer overflow when printing eDonkey links for 0-sized files
+ * Bugfix: --ripemd160 and --md4 option were broken
+ * added `%R' printf entity for RIPEMD-160
+
+Mon Dec 14 2009 Aleksey
+ * === Version 1.1.4 ===
+ * supported algorithms: RIPEMD-160, HAS-160, GOST, MD4, SNEFRU-128, SNEFRU-256
+ * long printf format entities, e.g. %{md4}, %{has160}, %{gost}, %{snefru256}
+ * `u' printf modifier for uppercase hashes, e.g. %u{gost}
+ * switched to %{urlname} printf-entity for url-encoded file name
+ * useful symlinks are installed by `make install-symlinks'
+
+Sun Dec 6 2009 Aleksey
+ * WHIRLPOOL hash function supported, option --whirlpool
+
+Wed Dec 2 2009 Aleksey
+ * print file checking statistics when --check-embedded specified
+
+Sun Nov 29 2009 Aleksey
+ * === Version 1.1.3 ===
+ * forbid simultaneous usage of --check, --update and --check-embedded options
+
+Sun Nov 22 2009 Aleksey
+ * Bugfix: Checking of md5 file always reported OK
+ * --check-embedded option to verify files by crc32 sum embedded in their names.
+ * --embed-crc option to rename processed files by embedding crc32 sum into name.
+
+Mon Nov 9 2009 Aleksey
+ * --benchmark option now prints names of tested hash sums
+ * use magnet format as default if the program name contains 'magnet'
+
+Wed Jun 24 2009 Aleksey
+ * supported checking of files containing a single hash sum without a filename
+
+Mon Jun 15 2009 Aleksey
+ * === Version 1.1.2 ===
+ * verification of files with magnet links supported
+
+Wed May 20 2009 Aleksey
+ * Bugfix: --skip-ok was broken since 1.1.0
+
+Fri May 15 2009 Aleksey
+ * Bugfix: checking of ed2k hashes was broken since version 1.1.0
+ * Bugfix: --verbose lead to crash under OpenSolaris when config file not present
+
+Mon Mar 23 2009 Aleksey
+ * === Version 1.1.1 ===
+ * config file described in the man page
+ * Bugfix: buffer owerflow when printing tiger hash
+
+Sat Mar 21 2009 Aleksey
+ * Bugfix: some options couldn't be read from config file
+
+Sat Mar 14 2009 Aleksey
+ * === Version 1.1.0 ===
+ * various small changes and refactoring
+
+Tue Mar 10 2009 Aleksey
+ * option --speed to print per-file and total speed statistics
+
+Thu Mar 5 2009 Aleksey
+ * option --output to write calculation and check results to a file
+ * option --log to log percents, speed and verbose messages
+
+Wed Mar 4 2009 Aleksey
+ * option --percents to show wget-like percents
+
+Tue Feb 26 2009 Aleksey
+ * Bugfix: fixed processing of unaligned messages in the get_crc32() function
+
+Sat Feb 14 2009 Aleksey
+ * === Version 1.0.8 ===
+ * --magnet option supported to format sums as a magnet link
+ * Bugfix: printf option from config conflicted with command line
+
+Sun Dec 14 2008 Aleksey
+ * === Version 1.0.7 ===
+ * config file supported to load default options values
+ * if --verbose, report verification errors as "sum is XXXXXXXX, should be YYYYYYYY"
+ * '%h' modifier changed to '%x'
+
+Fri Nov 14 2008 Aleksey
+ * === Version 1.0.6 ===
+ * reg-file for FAR user menu
+
+Thu Oct 9 2008 Aleksey
+ * interpret '#' symbol as a comment
+
+Sat Sep 20 2008 ivan386
+ * under windows skip files openned for writing
+ * Bugfix: printf arguments %p and %f corrected
+
+Sun Sep 14 2008 Aleksey
+ * === Version 1.0.5 ===
+
+Wed Aug 6 2008 Aleksey
+ * '%b','%h' modifiers to print base32/hex representation of any hash (e.g. '%bH')
+ * supported -p '\0' symbol
+ * supported setting width for filesizes (e.g. -p '%12s')
+
+Tue Jul 22 2008 Aleksey
+ * --verbose prints read speed statistics to stderr after each file
+ * read buffer increased to 2 MiB
+
+Wed Jul 9 2008 Aleksey
+ * === Version 1.0.4 ===
+ * '%u' prints URL-encoded filename
+ * EDonkey links now have URL-encoded filename and contain AICH hash
+
+Mon Jul 7 2008 Aleksey
+ * AICH hashsums supported, option --aich
+
+Sat Jun 28 2008 Aleksey
+ * === Version 1.0.3 ===
+ * ed2k calculation fixed for files with 9728000 < filesize <= 9732096
+ * Big-endian processors supported for all sums
+
+Sat Jun 14 2008 Aleksey
+ * === Version 1.0.2 ===
+
+Fri Jun 6 2008 Aleksey
+ * --benchmark option added
+ * skip locked files under win32 when calculating 'em sums
+
+Tue May 20 2008 Aleksey
+ * Bugfix: updating of md5 files was broken
+ * Bugfix: more rigid parsing of base32/hex hash sums
+
+Wed May 15 2008 Aleksey
+ * === Version 1.0.1 ===
+ * Bugfix: last line without '\n' couldn't be parsed
+
+Wed May 14 2008 Aleksey
+ * Bugfix: empty lines were not skipped, when verifying a crc file
+ * option '--skip-ok' to skip OK messages for successfuly verified files
+
+Tue Jan 22 2008 Aleksey
+ * option '-a' to print all supported hash sums
+ * Changed default behavior: if no formatting option are set, sfv header is printed only for --crc32
+
+Wed Dec 19 2007 Aleksey
+ * Bugfix: fixed buffer overflow for command line -p '%%%%d'
+ * Bugfix: fixed size calculation for stdin (rhash -p '%s' - = 56
+ * Tiger hash optimised to be 5% faster
+
+Wed May 02 2007 Aleksey
+ * === Version 0.8.8 ===
+
+Sun Apr 22 2007 Aleksey
+ * added options --accept and --crc-accept
+ * added --verbose option
+ * added --maxdepth option
+ * added check before verifying a crc file that it isn't a binary file
+
+Mon Apr 16 2007 Aleksey
+ * === Version 0.8.7 ===
+ * Tiger hash sum optimised for IA32
+
+Tue Apr 10 2007 Aleksey
+ * Bugfix: --update of sfv files worked incorrectly under windows
+
+Mon Apr 09 2007 Aleksey
+ * implemented Tiger hash function
+
+Sun Apr 01 2007 Aleksey
+ * added check before updating a crc file that it isn't a binary file
+
+Mon Mar 26 2007 Aleksey
+ * === Version 0.8.6 ===
+ * Ctrl+C now prints a message and partitial statistics
+
+Sat Mar 24 2007 Aleksey
+ * default format changed to SFV
+
+Mon Mar 19 2007 Aleksey
+ * updating of crc files supported
+
+Wed Jan 31 2007 Aleksey
+ * === Version 0.8.5 ===
+ * supported many short options as one argument, e.g. '-MCEr'
+ * option -S (--sha1) changed to -H
+ * Bugfix: program crashed under BSD while printing SFV file header
+
+Sun Nov 05 2006 Aleksey
+ * === Version 0.8.4 ===
+ * Bugfix: errors/miss stats calculation corrected
+
+Sun Oct 29 2006 Aleksey
+ * supported "-c -" option to check hash sums from stdin
+ * added stdout flushing after each processed file
+ * the program returns exit code 0 on success and 1 if an error occurred
+
+Fri Sep 08 2006 Aleksey
+ * corrected parsing of md5-like files with star-prepended filenames
+
+Wed Apr 19 2006 Aleksey
+ * checking of md5/sha1 files in *BSD format supported
+ * improved I/O errors handling
+
+Mon Apr 10 2006 Aleksey
+ * === Version 0.8.3 ===
+ * cheking of files in standard md5sum/sha1sum format supported
+ * default output format for md5/sha1/ed2k sums changed
+ * man page rewrited
+
+Thu Mar 30 2006 Aleksey
+ * === Version 0.8.2 ===
+ * GCC 2.96 supported
+
+Thu Feb 23 2006 Aleksey
+ * Bugfix: files with .SFV extension (in uppercase) were skiped while recursive checking
+
+Wed Jan 25 2006 Aleksey
+ * === Version 0.8.1 ===
+ * option --check now works with --recursive
+ * Bugfix: corrected output format when checking files
+ * Bugfix: files wasn't opened as binary on Windows when checking sums
+
+Mon Jan 23 2006 Aleksey
+ * === Version 0.8 ===
+ * documentation now distributed with windows version
+ * some *.bat files added to windows version
+
+Sun Jan 22 2006 Aleksey
+ * --check option added, to check hash sums files
+ * --ansi option added (for Windows version only)
+ * program name is parsed now to specify default sums to compute
+
+Sat Jan 14 2006 Aleksey
+ * Bugfix: console windows version now uses OEM (DOS) character set for output
+
+ * === Version 0.7 ===
+ * some fixes in sfv format output
+
+Fri Sep 16 2005 Aleksey
+ * --recursive option added
+ * --ed2k-link option added
+
+Fri Sep 02 2005 Aleksey
+ * === Version 0.6 ===
+
+Sun Aug 28 2005 Aleksey
+ * Bugfix: files wasn't opened as binary on win32
+ * --sfv format now implies uppercase hashes
+
+Wed Aug 24 2005 Aleksey
+ * added .spec file and Makefile 'rpm' target
+
+Sun Aug 14 2005 Aleksey
+ * === Version 0.5 ===
+ * the first public version
+ * win32 platform supported
+
+Mon Aug 08 2005 Aleksey
+ * Bugfix: fixed calculation of md5/ed2k hashes for AMD64
+
+Fri Aug 05 2005 Aleksey
+ * === Version 0.06 ===
+ * initial linux version supporting crc32, md5, ed2k and sha1
diff --git a/INSTALL.md b/INSTALL.md
index ce6d4d9f..892b9656 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -1,54 +1,54 @@
-
-Installation
-============
-
-Build Prerequisites
--------------------
- - GCC or Intel Compiler for Linux / macOS / Unix.
- - MinGW or MS VC++ for Windows.
- - (optionally) gettext library for internationalization
- - (optionally) OpenSSL for optimized algorithms
-
-Build and install
------------------
-To compile and install the program use command
-```sh
-./configure && make && make install
-```
-
-The compiled program and library can be tested by command `make test test-lib`
-
-To compile using MS VC++, take the project file from /win32/vc-2010/ directory.
-
-Enabling features
------------------
-RHash can use optimized algorithms of MD5, SHA1, SHA2 from the OpenSSL library.
-To link OpenSSL at run-time (preffered way), configure RHash as
-```sh
-./configure --enable-openssl-runtime
-```
-To link it at load-time, use options
-```sh
-./configure --enable-openssl --disable-openssl-runtime
-```
-
-Internationalization support can be compiled and installed by commands
-```sh
-./configure --enable-gettext
-make install install-gmo
-```
-
-Run `./configure --help` for a full list of configuration options.
-
-Building an OS native package
------------------------------
-When building a package for an OS Repository, one should correctly specify system directories, e.g.:
-```sh
-./configure --sysconfdir=/etc --exec-prefix=/usr
-```
-
-Example of installing RHash with shared and static LibRHash library:
-```sh
-./configure --enable-lib-static
-make install install-lib-so-link
-```
+
+Installation
+============
+
+Build Prerequisites
+-------------------
+ - GCC or Intel Compiler for Linux / macOS / Unix.
+ - MinGW or MS VC++ for Windows.
+ - (optionally) gettext library for internationalization
+ - (optionally) OpenSSL for optimized algorithms
+
+Build and install
+-----------------
+To compile and install the program use command
+```sh
+./configure && make && make install
+```
+
+The compiled program and library can be tested by command `make test test-lib`
+
+To compile using MS VC++, take the project file from /win32/vc-2010/ directory.
+
+Enabling features
+-----------------
+RHash can use optimized algorithms of MD5, SHA1, SHA2 from the OpenSSL library.
+To link OpenSSL at run-time (preffered way), configure RHash as
+```sh
+./configure --enable-openssl-runtime
+```
+To link it at load-time, use options
+```sh
+./configure --enable-openssl --disable-openssl-runtime
+```
+
+Internationalization support can be compiled and installed by commands
+```sh
+./configure --enable-gettext
+make install install-gmo
+```
+
+Run `./configure --help` for a full list of configuration options.
+
+Building an OS native package
+-----------------------------
+When building a package for an OS Repository, one should correctly specify system directories, e.g.:
+```sh
+./configure --sysconfdir=/etc --exec-prefix=/usr
+```
+
+Example of installing RHash with shared and static LibRHash library:
+```sh
+./configure --enable-lib-static
+make install install-lib-so-link
+```
diff --git a/Makefile b/Makefile
index b722f78c..6526c9b8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,339 +1,339 @@
-
-include config.mak
-
-HEADERS = calc_sums.h hash_print.h common_func.h hash_update.h file.h file_mask.h file_set.h find_file.h hash_check.h output.h parse_cmdline.h rhash_main.h win_utils.h platform.h version.h
-SOURCES = calc_sums.c hash_print.c common_func.c hash_update.c file.c file_mask.c file_set.c find_file.c hash_check.c output.c parse_cmdline.c rhash_main.c win_utils.c
-OBJECTS = $(SOURCES:.c=.o)
-WIN_DIST_FILES = dist/MD5.bat dist/magnet.bat dist/rhashrc.sample
-OTHER_FILES = configure Makefile ChangeLog INSTALL.md COPYING README.md \
- build/vc-2010/rhash.vcxproj dist/rhash.spec.in dist/rhash.1 dist/rhash.1.win.sed \
- docs/CONTRIBUTING.md docs/LIBRHASH.md librhash/Doxyfile po/rhash.pot \
- tests/test_rhash.sh tests/test1K.data
-LIBRHASH_FILES = librhash/algorithms.c librhash/algorithms.h \
- librhash/byte_order.c librhash/byte_order.h librhash/plug_openssl.c librhash/plug_openssl.h \
- librhash/rhash.c librhash/rhash.h librhash/rhash_torrent.c librhash/rhash_torrent.h \
- librhash/rhash_timing.c librhash/rhash_timing.h \
- librhash/aich.c librhash/aich.h librhash/crc32.c librhash/crc32.h \
- librhash/ed2k.c librhash/ed2k.h librhash/edonr.c librhash/edonr.h \
- librhash/gost12.c librhash/gost12.h librhash/gost94.c librhash/gost94.h \
- librhash/has160.c librhash/has160.h librhash/hex.c librhash/hex.h librhash/md4.c \
- librhash/md4.h librhash/md5.c librhash/md5.h librhash/ripemd-160.c librhash/ripemd-160.h \
- librhash/sha1.c librhash/sha1.h librhash/sha3.c librhash/sha3.h \
- librhash/sha256.c librhash/sha256.h librhash/sha512.c librhash/sha512.h \
- librhash/snefru.c librhash/snefru.h librhash/tiger.c librhash/tiger.h \
- librhash/tiger_sbox.c librhash/tth.c librhash/tth.h librhash/whirlpool.c \
- librhash/whirlpool.h librhash/whirlpool_sbox.c librhash/test_hashes.c \
- librhash/test_hashes.h librhash/torrent.h librhash/torrent.c librhash/ustd.h \
- librhash/util.h librhash/Makefile
-I18N_FILES = po/ca.po po/de.po po/en_AU.po po/es.po po/fr.po po/gl.po po/it.po po/ro.po po/ru.po
-ALL_FILES = $(SOURCES) $(HEADERS) $(LIBRHASH_FILES) $(OTHER_FILES) $(WIN_DIST_FILES) $(I18N_FILES)
-SPECFILE = dist/rhash.spec
-LIBRHASH_PC = dist/librhash.pc
-RHASH_NAME = rhash
-RHASH_BINARY = rhash$(EXEC_EXT)
-CONFDIR_MACRO = -DSYSCONFDIR=\"$(SYSCONFDIR)\"
-TEST_OPTIONS =
-RPMTOP = rpms
-RPMDIRS = SOURCES SPECS BUILD SRPMS RPMS
-INSTALL_PROGRAM = $(INSTALL) -m 755
-INSTALL_DATA = $(INSTALL) -m 644
-
-all: $(BUILD_TARGETS)
-install: build-install-binary install-data install-symlinks $(EXTRA_INSTALL)
-build-static: $(RHASH_STATIC)
-build-shared: $(RHASH_SHARED)
-lib-shared: $(LIBRHASH_SHARED)
-lib-static: $(LIBRHASH_STATIC)
-install-data: install-man install-conf
-uninstall: uninstall-binary uninstall-data uninstall-symlinks uninstall-lib uninstall-gmo uninstall-pkg-config
-
-config.mak:
- echo "Run the ./configure script first" && false
-
-# creating archives
-WIN_SUFFIX = win32
-PACKAGE_NAME = $(RHASH_NAME)-$(VERSION)
-ARCHIVE_BZIP = $(PACKAGE_NAME)-src.tar.bz2
-ARCHIVE_GZIP = $(PACKAGE_NAME)-src.tar.gz
-ARCHIVE_FULL = $(PACKAGE_NAME)-full-src.tar.gz
-ARCHIVE_DEB_GZ = $(RHASH_NAME)_$(VERSION).orig.tar.gz
-ARCHIVE_7Z = $(PACKAGE_NAME)-src.tar.7z
-ARCHIVE_ZIP = $(PACKAGE_NAME)-$(WIN_SUFFIX).zip
-WIN_ZIP_DIR = RHash-$(VERSION)-$(WIN_SUFFIX)
-dist: gzip gzip-bindings
-dist-full: gzip-full
-win-dist: zip
-zip: $(ARCHIVE_ZIP)
-dgz: check $(ARCHIVE_DEB_GZ)
-
-build-install-binary: $(BUILD_TARGETS)
- +$(MAKE) install-binary
-
-mkdir-bin:
- $(INSTALL) -d $(BINDIR)
-
-# install binary without (re-)compilation
-install-binary: mkdir-bin
- $(INSTALL_PROGRAM) $(RHASH_BINARY) $(BINDIR)/$(RHASH_BINARY)
-
-install-man:
- $(INSTALL) -d $(MANDIR)/man1
- $(INSTALL_DATA) dist/rhash.1 $(MANDIR)/man1/rhash.1
-
-install-conf:
- $(INSTALL) -d $(SYSCONFDIR)
- tr -d \\r < dist/rhashrc.sample > rc.tmp && $(INSTALL_DATA) rc.tmp $(SYSCONFDIR)/rhashrc
- rm -f rc.tmp
-
-# dependencies should be properly set, otherwise 'make -j' can fail
-install-symlinks: mkdir-bin install-man install-binary
- cd $(BINDIR) && for f in $(SYMLINKS); do $(LN_S) $(RHASH_BINARY) $$f$(EXEC_EXT); done
- cd $(MANDIR)/man1 && for f in $(SYMLINKS); do $(LN_S) rhash.1 $$f.1; done
-
-install-pkg-config:
- $(INSTALL) -d $(PKGCONFIGDIR)
- $(INSTALL_DATA) $(LIBRHASH_PC) $(PKGCONFIGDIR)/
-
-uninstall-binary:
- rm -f $(BINDIR)/$(RHASH_BINARY)
-
-uninstall-data:
- rm -f $(MANDIR)/man1/rhash.1
-
-uninstall-symlinks:
- for f in $(SYMLINKS); do rm -f $(BINDIR)/$$f$(EXEC_EXT) $(MANDIR)/man1/$$f.1; done
-
-uninstall-pkg-config:
- rm -f $(PKGCONFIGDIR)/librhash.pc
-
-uninstall-lib:
- +cd librhash && $(MAKE) uninstall-lib
-
-install-lib-static: $(LIBRHASH_STATIC) install-lib-headers
- +cd librhash && $(MAKE) install-lib-static
-
-install-lib-shared: $(LIBRHASH_SHARED)
- +cd librhash && $(MAKE) install-lib-shared
-
-install-lib-headers:
- +cd librhash && $(MAKE) install-lib-headers
-
-install-lib-so-link:
- +cd librhash && $(MAKE) install-so-link
-
-$(LIBRHASH_SHARED): $(LIBRHASH_FILES)
- +cd librhash && $(MAKE) lib-shared
-
-$(LIBRHASH_STATIC): $(LIBRHASH_FILES)
- +cd librhash && $(MAKE) lib-static
-
-test-lib: test-lib-$(BUILD_TYPE)
-test-lib-static: $(LIBRHASH_STATIC)
- +cd librhash && $(MAKE) test-static
-
-test-lib-shared: $(LIBRHASH_SHARED)
- +cd librhash && $(MAKE) test-shared
-
-test-libs: $(LIBRHASH_STATIC) $(LIBRHASH_SHARED)
- +cd librhash && $(MAKE) test-static test-shared
-
-test-full:
- +$(MAKE) TEST_OPTIONS=--full test
-
-test: test-$(BUILD_TYPE)
-test-static: $(RHASH_STATIC)
- chmod +x tests/test_rhash.sh
- tests/test_rhash.sh $(TEST_OPTIONS) ./$(RHASH_STATIC)
-
-test-shared: $(RHASH_SHARED)
- chmod +x tests/test_rhash.sh
- tests/test_rhash.sh --shared $(TEST_OPTIONS) ./$(RHASH_SHARED)
-
-print-info: lib-$(BUILD_TYPE)
- +cd librhash && $(MAKE) print-info
-
-# check that source tree is consistent
-check:
- grep -q '\* === Version $(VERSION) ===' ChangeLog
- grep -q '^#define VERSION "$(VERSION)"' version.h
- test ! -f bindings/version.properties || grep -q '^version=$(VERSION)$$' bindings/version.properties
-
-$(RHASH_STATIC): $(OBJECTS) $(LIBRHASH_STATIC)
- $(CC) $(OBJECTS) $(LIBRHASH_STATIC) $(BIN_STATIC_LDFLAGS) -o $@
-
-$(RHASH_SHARED): $(OBJECTS) $(LIBRHASH_SHARED)
- $(CC) $(OBJECTS) $(LIBRHASH_SHARED) $(LDFLAGS) -o $@
-
-# NOTE: dependences were generated by 'gcc -Ilibrhash -MM *.c'
-# we are using plain old makefile style to support BSD make
-calc_sums.o: calc_sums.c platform.h calc_sums.h common_func.h \
- hash_check.h file.h hash_print.h output.h parse_cmdline.h rhash_main.h \
- win_utils.h librhash/rhash.h librhash/rhash_torrent.h
- $(CC) -c $(CFLAGS) $< -o $@
-
-common_func.o: common_func.c common_func.h parse_cmdline.h version.h \
- win_utils.h
- $(CC) -c $(CFLAGS) $< -o $@
-
-file.o: file.c file.h common_func.h win_utils.h
- $(CC) -c $(CFLAGS) $< -o $@
-
-file_mask.o: file_mask.c file_mask.h common_func.h
- $(CC) -c $(CFLAGS) $< -o $@
-
-file_set.o: file_set.c file_set.h calc_sums.h common_func.h hash_check.h \
- hash_print.h output.h parse_cmdline.h rhash_main.h librhash/rhash.h
- $(CC) -c $(CFLAGS) $< -o $@
-
-find_file.o: find_file.c platform.h find_file.h common_func.h file.h \
- output.h win_utils.h
- $(CC) -c $(CFLAGS) $< -o $@
-
-hash_check.o: hash_check.c hash_check.h hash_print.h common_func.h \
- output.h parse_cmdline.h librhash/rhash.h
- $(CC) -c $(CFLAGS) $< -o $@
-
-hash_print.o: hash_print.c hash_print.h calc_sums.h common_func.h \
- hash_check.h file.h parse_cmdline.h win_utils.h librhash/rhash.h
- $(CC) -c $(CFLAGS) $< -o $@
-
-hash_update.o: hash_update.c common_func.h calc_sums.h hash_check.h \
- file.h file_set.h file_mask.h hash_print.h hash_update.h output.h \
- parse_cmdline.h rhash_main.h win_utils.h
- $(CC) -c $(CFLAGS) $< -o $@
-
-output.o: output.c platform.h output.h calc_sums.h common_func.h \
- hash_check.h parse_cmdline.h rhash_main.h win_utils.h librhash/rhash.h
- $(CC) -c $(CFLAGS) $< -o $@
-
-parse_cmdline.o: parse_cmdline.c parse_cmdline.h common_func.h \
- file_mask.h find_file.h file.h hash_print.h output.h rhash_main.h \
- win_utils.h librhash/rhash.h
- $(CC) -c $(CFLAGS) $< -o $@
-
-rhash_main.o: rhash_main.c rhash_main.h calc_sums.h common_func.h \
- hash_check.h file_mask.h find_file.h file.h hash_print.h hash_update.h \
- parse_cmdline.h output.h win_utils.h librhash/rhash.h
- $(CC) -c $(CFLAGS) $< -o $@
-
-win_utils.o: win_utils.c win_utils.h common_func.h file.h parse_cmdline.h \
- rhash_main.h
- $(CC) -c $(CFLAGS) $< -o $@
-
-dist/rhash.1.win.html: dist/rhash.1 dist/rhash.1.win.sed
- sed -f dist/rhash.1.win.sed dist/rhash.1 | rman -fHTML -roff | \
- sed -e '/ dist/rhash.1.win.html
-# verify the result
- grep -q "utf8" dist/rhash.1.win.html
- grep -q "APPDATA" dist/rhash.1.win.html
-
-dist/rhash.1.html: dist/rhash.1
- -which rman 2>/dev/null && (rman -fHTML -roff dist/rhash.1 | sed -e '/ $@)
-
-dist/rhash.1.txt: dist/rhash.1
- -which groff &>/dev/null && (groff -t -e -mandoc -Tascii dist/rhash.1 | sed -e 's/.\[[0-9]*m//g' > $@)
-
-permissions:
- find . build dist docs librhash po tests -maxdepth 1 -type f -exec chmod -x '{}' \;
- chmod +x configure tests/test_rhash.sh
-
-copy-dist: $(ALL_FILES) permissions
- rm -rf $(PACKAGE_NAME)
- mkdir $(PACKAGE_NAME)
- cp -rl --parents $(ALL_FILES) $(PACKAGE_NAME)/
-
-gzip: check
- +$(MAKE) copy-dist
- tar czf $(ARCHIVE_GZIP) --owner=root --group=root $(PACKAGE_NAME)/
- rm -rf $(PACKAGE_NAME)
-
-gzip-bindings:
- +cd bindings && $(MAKE) gzip ARCHIVE_GZIP=../rhash-bindings-$(VERSION)-src.tar.gz
-
-gzip-full: check clean-bindings
- +$(MAKE) copy-dist
- +cd bindings && $(MAKE) copy-dist COPYDIR=../$(PACKAGE_NAME)/bindings
- tar czf $(ARCHIVE_FULL) --owner=root:0 --group=root:0 $(PACKAGE_NAME)/
- rm -rf $(PACKAGE_NAME)
-
-bzip: check
- +$(MAKE) copy-dist
- tar cjf $(ARCHIVE_BZIP) --owner=root:0 --group=root:0 $(PACKAGE_NAME)/
- rm -rf $(PACKAGE_NAME)
-
-7z: check
- +$(MAKE) copy-dist
- tar cf - --owner=root:0 --group=root:0 $(PACKAGE_NAME)/ | 7zr a -si $(ARCHIVE_7Z)
- rm -rf $(PACKAGE_NAME)
-
-$(ARCHIVE_ZIP): $(WIN_DIST_FILES) dist/rhash.1.win.html
- test -s dist/rhash.1.win.html && test -x $(RHASH_BINARY)
- -rm -rf $(WIN_ZIP_DIR)
- mkdir $(WIN_ZIP_DIR)
- cp $(RHASH_BINARY) ChangeLog $(WIN_DIST_FILES) $(WIN_ZIP_DIR)/
- cp dist/rhash.1.win.html $(WIN_ZIP_DIR)/rhash-doc.html
- zip -9r $(ARCHIVE_ZIP) $(WIN_ZIP_DIR)
- rm -rf $(WIN_ZIP_DIR)
-
-$(ARCHIVE_DEB_GZ) : $(ALL_FILES)
- +$(MAKE) $(ARCHIVE_GZIP)
- mv -f $(ARCHIVE_GZIP) $(ARCHIVE_DEB_GZ)
-
-# rpm packaging
-$(SPECFILE): $(SPECFILE).in config.mak
- sed -e 's/@VERSION@/$(VERSION)/' $(SPECFILE).in > $(SPECFILE)
-
-rpm: gzip
- -for i in $(RPMDIRS); do mkdir -p $(RPMTOP)/$$i; done
- cp -f $(ARCHIVE_GZIP) $(RPMTOP)/SOURCES
- rpmbuild -ba --clean --define "_topdir `pwd`/$(RPMTOP)" $(SPECFILE)
- mv -f `find $(RPMTOP) -name "*rhash*-$(VERSION)*.rpm"` .
- rm -rf $(RPMTOP)
-
-clean-bindings:
- +cd bindings && $(MAKE) clean
-
-clean-local:
- rm -f *.o $(RHASH_SHARED) $(RHASH_STATIC)
- rm -f po/*.gmo po/*.po~
-
-distclean: clean-local
- rm -f config.log config.mak $(SPECFILE) $(LIBRHASH_PC)
- +cd librhash && $(MAKE) distclean
-
-clean: clean-local
- +cd librhash && $(MAKE) clean
-
-update-po:
- xgettext *.c -k_ -cTRANSLATORS -o po/rhash.pot \
- --msgid-bugs-address='Aleksey ' --package-name='RHash'
- for f in $(I18N_FILES); do \
- msgmerge -U $$f po/rhash.pot; \
- done
-
-compile-gmo:
- for f in $(I18N_FILES); do \
- g=`basename $$f .po`; \
- msgfmt -o po/$$g.gmo $$f; \
- done
-
-install-gmo: compile-gmo
- for f in $(I18N_FILES); do \
- l=`basename $$f .po`; \
- $(INSTALL) -d $(LOCALEDIR)/$$l/LC_MESSAGES; \
- $(INSTALL_DATA) po/$$l.gmo $(LOCALEDIR)/$$l/LC_MESSAGES/rhash.mo; \
- done
-
-uninstall-gmo:
- for f in $(I18N_FILES); do \
- rm -f $(LOCALEDIR)/`basename $$f .po`/LC_MESSAGES/rhash.mo; \
- done
-
-.PHONY: all build-shared build-static lib-shared lib-static clean clean-bindings distclean clean-local \
- test test-shared test-static test-full test-lib test-libs test-lib-shared test-lib-static \
- install build-install-binary install-binary install-lib-shared install-lib-static \
- install-lib-headers install-lib-so-link install-conf install-data install-gmo install-man \
- install-symlinks install-pkg-config uninstall-gmo uninstall-pkg-config \
- uninstall uninstall-binary uninstall-data uninstall-lib uninstall-symlinks \
- print-info check copy-dist update-po compile-gmo mkdir-bin permissions \
- bzip dgz dist dist-full gzip gzip-bindings gzip-full rpm win-dist zip
+
+include config.mak
+
+HEADERS = calc_sums.h hash_print.h common_func.h hash_update.h file.h file_mask.h file_set.h find_file.h hash_check.h output.h parse_cmdline.h rhash_main.h win_utils.h platform.h version.h
+SOURCES = calc_sums.c hash_print.c common_func.c hash_update.c file.c file_mask.c file_set.c find_file.c hash_check.c output.c parse_cmdline.c rhash_main.c win_utils.c
+OBJECTS = $(SOURCES:.c=.o)
+WIN_DIST_FILES = dist/MD5.bat dist/magnet.bat dist/rhashrc.sample
+OTHER_FILES = configure Makefile ChangeLog INSTALL.md COPYING README.md \
+ build/vc-2010/rhash.vcxproj dist/rhash.spec.in dist/rhash.1 dist/rhash.1.win.sed \
+ docs/CONTRIBUTING.md docs/LIBRHASH.md librhash/Doxyfile po/rhash.pot \
+ tests/test_rhash.sh tests/test1K.data
+LIBRHASH_FILES = librhash/algorithms.c librhash/algorithms.h \
+ librhash/byte_order.c librhash/byte_order.h librhash/plug_openssl.c librhash/plug_openssl.h \
+ librhash/rhash.c librhash/rhash.h librhash/rhash_torrent.c librhash/rhash_torrent.h \
+ librhash/rhash_timing.c librhash/rhash_timing.h \
+ librhash/aich.c librhash/aich.h librhash/crc32.c librhash/crc32.h \
+ librhash/ed2k.c librhash/ed2k.h librhash/edonr.c librhash/edonr.h \
+ librhash/gost12.c librhash/gost12.h librhash/gost94.c librhash/gost94.h \
+ librhash/has160.c librhash/has160.h librhash/hex.c librhash/hex.h librhash/md4.c \
+ librhash/md4.h librhash/md5.c librhash/md5.h librhash/ripemd-160.c librhash/ripemd-160.h \
+ librhash/sha1.c librhash/sha1.h librhash/sha3.c librhash/sha3.h \
+ librhash/sha256.c librhash/sha256.h librhash/sha512.c librhash/sha512.h \
+ librhash/snefru.c librhash/snefru.h librhash/tiger.c librhash/tiger.h \
+ librhash/tiger_sbox.c librhash/tth.c librhash/tth.h librhash/whirlpool.c \
+ librhash/whirlpool.h librhash/whirlpool_sbox.c librhash/test_hashes.c \
+ librhash/test_hashes.h librhash/torrent.h librhash/torrent.c librhash/ustd.h \
+ librhash/util.h librhash/Makefile
+I18N_FILES = po/ca.po po/de.po po/en_AU.po po/es.po po/fr.po po/gl.po po/it.po po/ro.po po/ru.po
+ALL_FILES = $(SOURCES) $(HEADERS) $(LIBRHASH_FILES) $(OTHER_FILES) $(WIN_DIST_FILES) $(I18N_FILES)
+SPECFILE = dist/rhash.spec
+LIBRHASH_PC = dist/librhash.pc
+RHASH_NAME = rhash
+RHASH_BINARY = rhash$(EXEC_EXT)
+CONFDIR_MACRO = -DSYSCONFDIR=\"$(SYSCONFDIR)\"
+TEST_OPTIONS =
+RPMTOP = rpms
+RPMDIRS = SOURCES SPECS BUILD SRPMS RPMS
+INSTALL_PROGRAM = $(INSTALL) -m 755
+INSTALL_DATA = $(INSTALL) -m 644
+
+all: $(BUILD_TARGETS)
+install: build-install-binary install-data install-symlinks $(EXTRA_INSTALL)
+build-static: $(RHASH_STATIC)
+build-shared: $(RHASH_SHARED)
+lib-shared: $(LIBRHASH_SHARED)
+lib-static: $(LIBRHASH_STATIC)
+install-data: install-man install-conf
+uninstall: uninstall-binary uninstall-data uninstall-symlinks uninstall-lib uninstall-gmo uninstall-pkg-config
+
+config.mak:
+ echo "Run the ./configure script first" && false
+
+# creating archives
+WIN_SUFFIX = win32
+PACKAGE_NAME = $(RHASH_NAME)-$(VERSION)
+ARCHIVE_BZIP = $(PACKAGE_NAME)-src.tar.bz2
+ARCHIVE_GZIP = $(PACKAGE_NAME)-src.tar.gz
+ARCHIVE_FULL = $(PACKAGE_NAME)-full-src.tar.gz
+ARCHIVE_DEB_GZ = $(RHASH_NAME)_$(VERSION).orig.tar.gz
+ARCHIVE_7Z = $(PACKAGE_NAME)-src.tar.7z
+ARCHIVE_ZIP = $(PACKAGE_NAME)-$(WIN_SUFFIX).zip
+WIN_ZIP_DIR = RHash-$(VERSION)-$(WIN_SUFFIX)
+dist: gzip gzip-bindings
+dist-full: gzip-full
+win-dist: zip
+zip: $(ARCHIVE_ZIP)
+dgz: check $(ARCHIVE_DEB_GZ)
+
+build-install-binary: $(BUILD_TARGETS)
+ +$(MAKE) install-binary
+
+mkdir-bin:
+ $(INSTALL) -d $(BINDIR)
+
+# install binary without (re-)compilation
+install-binary: mkdir-bin
+ $(INSTALL_PROGRAM) $(RHASH_BINARY) $(BINDIR)/$(RHASH_BINARY)
+
+install-man:
+ $(INSTALL) -d $(MANDIR)/man1
+ $(INSTALL_DATA) dist/rhash.1 $(MANDIR)/man1/rhash.1
+
+install-conf:
+ $(INSTALL) -d $(SYSCONFDIR)
+ tr -d \\r < dist/rhashrc.sample > rc.tmp && $(INSTALL_DATA) rc.tmp $(SYSCONFDIR)/rhashrc
+ rm -f rc.tmp
+
+# dependencies should be properly set, otherwise 'make -j' can fail
+install-symlinks: mkdir-bin install-man install-binary
+ cd $(BINDIR) && for f in $(SYMLINKS); do $(LN_S) $(RHASH_BINARY) $$f$(EXEC_EXT); done
+ cd $(MANDIR)/man1 && for f in $(SYMLINKS); do $(LN_S) rhash.1 $$f.1; done
+
+install-pkg-config:
+ $(INSTALL) -d $(PKGCONFIGDIR)
+ $(INSTALL_DATA) $(LIBRHASH_PC) $(PKGCONFIGDIR)/
+
+uninstall-binary:
+ rm -f $(BINDIR)/$(RHASH_BINARY)
+
+uninstall-data:
+ rm -f $(MANDIR)/man1/rhash.1
+
+uninstall-symlinks:
+ for f in $(SYMLINKS); do rm -f $(BINDIR)/$$f$(EXEC_EXT) $(MANDIR)/man1/$$f.1; done
+
+uninstall-pkg-config:
+ rm -f $(PKGCONFIGDIR)/librhash.pc
+
+uninstall-lib:
+ +cd librhash && $(MAKE) uninstall-lib
+
+install-lib-static: $(LIBRHASH_STATIC) install-lib-headers
+ +cd librhash && $(MAKE) install-lib-static
+
+install-lib-shared: $(LIBRHASH_SHARED)
+ +cd librhash && $(MAKE) install-lib-shared
+
+install-lib-headers:
+ +cd librhash && $(MAKE) install-lib-headers
+
+install-lib-so-link:
+ +cd librhash && $(MAKE) install-so-link
+
+$(LIBRHASH_SHARED): $(LIBRHASH_FILES)
+ +cd librhash && $(MAKE) lib-shared
+
+$(LIBRHASH_STATIC): $(LIBRHASH_FILES)
+ +cd librhash && $(MAKE) lib-static
+
+test-lib: test-lib-$(BUILD_TYPE)
+test-lib-static: $(LIBRHASH_STATIC)
+ +cd librhash && $(MAKE) test-static
+
+test-lib-shared: $(LIBRHASH_SHARED)
+ +cd librhash && $(MAKE) test-shared
+
+test-libs: $(LIBRHASH_STATIC) $(LIBRHASH_SHARED)
+ +cd librhash && $(MAKE) test-static test-shared
+
+test-full:
+ +$(MAKE) TEST_OPTIONS=--full test
+
+test: test-$(BUILD_TYPE)
+test-static: $(RHASH_STATIC)
+ chmod +x tests/test_rhash.sh
+ tests/test_rhash.sh $(TEST_OPTIONS) ./$(RHASH_STATIC)
+
+test-shared: $(RHASH_SHARED)
+ chmod +x tests/test_rhash.sh
+ tests/test_rhash.sh --shared $(TEST_OPTIONS) ./$(RHASH_SHARED)
+
+print-info: lib-$(BUILD_TYPE)
+ +cd librhash && $(MAKE) print-info
+
+# check that source tree is consistent
+check:
+ grep -q '\* === Version $(VERSION) ===' ChangeLog
+ grep -q '^#define VERSION "$(VERSION)"' version.h
+ test ! -f bindings/version.properties || grep -q '^version=$(VERSION)$$' bindings/version.properties
+
+$(RHASH_STATIC): $(OBJECTS) $(LIBRHASH_STATIC)
+ $(CC) $(OBJECTS) $(LIBRHASH_STATIC) $(BIN_STATIC_LDFLAGS) -o $@
+
+$(RHASH_SHARED): $(OBJECTS) $(LIBRHASH_SHARED)
+ $(CC) $(OBJECTS) $(LIBRHASH_SHARED) $(LDFLAGS) -o $@
+
+# NOTE: dependences were generated by 'gcc -Ilibrhash -MM *.c'
+# we are using plain old makefile style to support BSD make
+calc_sums.o: calc_sums.c platform.h calc_sums.h common_func.h \
+ hash_check.h file.h hash_print.h output.h parse_cmdline.h rhash_main.h \
+ win_utils.h librhash/rhash.h librhash/rhash_torrent.h
+ $(CC) -c $(CFLAGS) $< -o $@
+
+common_func.o: common_func.c common_func.h parse_cmdline.h version.h \
+ win_utils.h
+ $(CC) -c $(CFLAGS) $< -o $@
+
+file.o: file.c file.h common_func.h win_utils.h
+ $(CC) -c $(CFLAGS) $< -o $@
+
+file_mask.o: file_mask.c file_mask.h common_func.h
+ $(CC) -c $(CFLAGS) $< -o $@
+
+file_set.o: file_set.c file_set.h calc_sums.h common_func.h hash_check.h \
+ hash_print.h output.h parse_cmdline.h rhash_main.h librhash/rhash.h
+ $(CC) -c $(CFLAGS) $< -o $@
+
+find_file.o: find_file.c platform.h find_file.h common_func.h file.h \
+ output.h win_utils.h
+ $(CC) -c $(CFLAGS) $< -o $@
+
+hash_check.o: hash_check.c hash_check.h hash_print.h common_func.h \
+ output.h parse_cmdline.h librhash/rhash.h
+ $(CC) -c $(CFLAGS) $< -o $@
+
+hash_print.o: hash_print.c hash_print.h calc_sums.h common_func.h \
+ hash_check.h file.h parse_cmdline.h win_utils.h librhash/rhash.h
+ $(CC) -c $(CFLAGS) $< -o $@
+
+hash_update.o: hash_update.c common_func.h calc_sums.h hash_check.h \
+ file.h file_set.h file_mask.h hash_print.h hash_update.h output.h \
+ parse_cmdline.h rhash_main.h win_utils.h
+ $(CC) -c $(CFLAGS) $< -o $@
+
+output.o: output.c platform.h output.h calc_sums.h common_func.h \
+ hash_check.h parse_cmdline.h rhash_main.h win_utils.h librhash/rhash.h
+ $(CC) -c $(CFLAGS) $< -o $@
+
+parse_cmdline.o: parse_cmdline.c parse_cmdline.h common_func.h \
+ file_mask.h find_file.h file.h hash_print.h output.h rhash_main.h \
+ win_utils.h librhash/rhash.h
+ $(CC) -c $(CFLAGS) $< -o $@
+
+rhash_main.o: rhash_main.c rhash_main.h calc_sums.h common_func.h \
+ hash_check.h file_mask.h find_file.h file.h hash_print.h hash_update.h \
+ parse_cmdline.h output.h win_utils.h librhash/rhash.h
+ $(CC) -c $(CFLAGS) $< -o $@
+
+win_utils.o: win_utils.c win_utils.h common_func.h file.h parse_cmdline.h \
+ rhash_main.h
+ $(CC) -c $(CFLAGS) $< -o $@
+
+dist/rhash.1.win.html: dist/rhash.1 dist/rhash.1.win.sed
+ sed -f dist/rhash.1.win.sed dist/rhash.1 | rman -fHTML -roff | \
+ sed -e '/ dist/rhash.1.win.html
+# verify the result
+ grep -q "utf8" dist/rhash.1.win.html
+ grep -q "APPDATA" dist/rhash.1.win.html
+
+dist/rhash.1.html: dist/rhash.1
+ -which rman 2>/dev/null && (rman -fHTML -roff dist/rhash.1 | sed -e '/ $@)
+
+dist/rhash.1.txt: dist/rhash.1
+ -which groff &>/dev/null && (groff -t -e -mandoc -Tascii dist/rhash.1 | sed -e 's/.\[[0-9]*m//g' > $@)
+
+permissions:
+ find . build dist docs librhash po tests -maxdepth 1 -type f -exec chmod -x '{}' \;
+ chmod +x configure tests/test_rhash.sh
+
+copy-dist: $(ALL_FILES) permissions
+ rm -rf $(PACKAGE_NAME)
+ mkdir $(PACKAGE_NAME)
+ cp -rl --parents $(ALL_FILES) $(PACKAGE_NAME)/
+
+gzip: check
+ +$(MAKE) copy-dist
+ tar czf $(ARCHIVE_GZIP) --owner=root --group=root $(PACKAGE_NAME)/
+ rm -rf $(PACKAGE_NAME)
+
+gzip-bindings:
+ +cd bindings && $(MAKE) gzip ARCHIVE_GZIP=../rhash-bindings-$(VERSION)-src.tar.gz
+
+gzip-full: check clean-bindings
+ +$(MAKE) copy-dist
+ +cd bindings && $(MAKE) copy-dist COPYDIR=../$(PACKAGE_NAME)/bindings
+ tar czf $(ARCHIVE_FULL) --owner=root:0 --group=root:0 $(PACKAGE_NAME)/
+ rm -rf $(PACKAGE_NAME)
+
+bzip: check
+ +$(MAKE) copy-dist
+ tar cjf $(ARCHIVE_BZIP) --owner=root:0 --group=root:0 $(PACKAGE_NAME)/
+ rm -rf $(PACKAGE_NAME)
+
+7z: check
+ +$(MAKE) copy-dist
+ tar cf - --owner=root:0 --group=root:0 $(PACKAGE_NAME)/ | 7zr a -si $(ARCHIVE_7Z)
+ rm -rf $(PACKAGE_NAME)
+
+$(ARCHIVE_ZIP): $(WIN_DIST_FILES) dist/rhash.1.win.html
+ test -s dist/rhash.1.win.html && test -x $(RHASH_BINARY)
+ -rm -rf $(WIN_ZIP_DIR)
+ mkdir $(WIN_ZIP_DIR)
+ cp $(RHASH_BINARY) ChangeLog $(WIN_DIST_FILES) $(WIN_ZIP_DIR)/
+ cp dist/rhash.1.win.html $(WIN_ZIP_DIR)/rhash-doc.html
+ zip -9r $(ARCHIVE_ZIP) $(WIN_ZIP_DIR)
+ rm -rf $(WIN_ZIP_DIR)
+
+$(ARCHIVE_DEB_GZ) : $(ALL_FILES)
+ +$(MAKE) $(ARCHIVE_GZIP)
+ mv -f $(ARCHIVE_GZIP) $(ARCHIVE_DEB_GZ)
+
+# rpm packaging
+$(SPECFILE): $(SPECFILE).in config.mak
+ sed -e 's/@VERSION@/$(VERSION)/' $(SPECFILE).in > $(SPECFILE)
+
+rpm: gzip
+ -for i in $(RPMDIRS); do mkdir -p $(RPMTOP)/$$i; done
+ cp -f $(ARCHIVE_GZIP) $(RPMTOP)/SOURCES
+ rpmbuild -ba --clean --define "_topdir `pwd`/$(RPMTOP)" $(SPECFILE)
+ mv -f `find $(RPMTOP) -name "*rhash*-$(VERSION)*.rpm"` .
+ rm -rf $(RPMTOP)
+
+clean-bindings:
+ +cd bindings && $(MAKE) clean
+
+clean-local:
+ rm -f *.o $(RHASH_SHARED) $(RHASH_STATIC)
+ rm -f po/*.gmo po/*.po~
+
+distclean: clean-local
+ rm -f config.log config.mak $(SPECFILE) $(LIBRHASH_PC)
+ +cd librhash && $(MAKE) distclean
+
+clean: clean-local
+ +cd librhash && $(MAKE) clean
+
+update-po:
+ xgettext *.c -k_ -cTRANSLATORS -o po/rhash.pot \
+ --msgid-bugs-address='Aleksey ' --package-name='RHash'
+ for f in $(I18N_FILES); do \
+ msgmerge -U $$f po/rhash.pot; \
+ done
+
+compile-gmo:
+ for f in $(I18N_FILES); do \
+ g=`basename $$f .po`; \
+ msgfmt -o po/$$g.gmo $$f; \
+ done
+
+install-gmo: compile-gmo
+ for f in $(I18N_FILES); do \
+ l=`basename $$f .po`; \
+ $(INSTALL) -d $(LOCALEDIR)/$$l/LC_MESSAGES; \
+ $(INSTALL_DATA) po/$$l.gmo $(LOCALEDIR)/$$l/LC_MESSAGES/rhash.mo; \
+ done
+
+uninstall-gmo:
+ for f in $(I18N_FILES); do \
+ rm -f $(LOCALEDIR)/`basename $$f .po`/LC_MESSAGES/rhash.mo; \
+ done
+
+.PHONY: all build-shared build-static lib-shared lib-static clean clean-bindings distclean clean-local \
+ test test-shared test-static test-full test-lib test-libs test-lib-shared test-lib-static \
+ install build-install-binary install-binary install-lib-shared install-lib-static \
+ install-lib-headers install-lib-so-link install-conf install-data install-gmo install-man \
+ install-symlinks install-pkg-config uninstall-gmo uninstall-pkg-config \
+ uninstall uninstall-binary uninstall-data uninstall-lib uninstall-symlinks \
+ print-info check copy-dist update-po compile-gmo mkdir-bin permissions \
+ bzip dgz dist dist-full gzip gzip-bindings gzip-full rpm win-dist zip
diff --git a/README.md b/README.md
index 546dbb29..491cd604 100644
--- a/README.md
+++ b/README.md
@@ -1,52 +1,52 @@
-# RHash
-
-RHash (Recursive Hasher) is a console utility for calculation and
-verification of magnet links and various hash sums, including CRC32, CRC32C,
-MD4, MD5, SHA1, SHA256, SHA512, SHA3, AICH, ED2K, DC++ TTH, BitTorrent BTIH,
-Tiger, GOST R 34.11-94, GOST R 34.11-2012, RIPEMD-160, HAS-160, EDON-R, and
-Whirlpool.
-
-Hash sums are used to ensure and verify integrity of large volumes of data
-for a long-term storing or transferring.
-
-### Program features:
- * Ability to process directories recursively.
- * Output in a predefined (SFV, BSD-like) or a user-defined format.
- * Calculation of Magnet links.
- * Updating hash files (adding hash sums of files missing in the hash file).
- * Calculates several hash sums in one pass.
- * Portability: the program works the same on Linux, Unix, macOS or Windows.
-
-## Installation
-```shell
-./configure && make install
-```
-For more complicated cases of installation see the [INSTALL.md] file.
-
-## Documentation
-
-* RHash [ChangeLog]
-* [The LibRHash Library] documentation
-
-## Links
-* Project Home Page: http://rhash.sourceforge.net/
-* Official Releases: https://github.com/rhash/RHash/releases/
-* Binary Windows Releases: https://sf.net/projects/rhash/files/rhash/
-* The table of the supported by RHash [hash functions](http://sf.net/p/rhash/wiki/HashFunctions/)
-* ECRYPT [The Hash Function Zoo](http://ehash.iaik.tugraz.at/wiki/The_Hash_Function_Zoo)
-* ECRYPT [Benchmarking of hash functions](https://bench.cr.yp.to/results-hash.html)
-
-## Contribution
-Please read the [Contribution guidelines](docs/CONTRIBUTING.md) document.
-
-## Notes on RHash License
-The code is distributed under [RHash License](COPYING). Basically,
-the program, the library and source code can be used free of charge under
-the MIT, BSD, GPL, a commercial or a freeware license without additional
-restrictions. In the case an OSI-approved license is required the
-[MIT license] should be used.
-
-[INSTALL.md]: INSTALL.md
-[The LibRHash Library]: docs/LIBRHASH.md
-[ChangeLog]: ChangeLog
-[MIT license]: http://www.opensource.org/licenses/MIT
+# RHash
+
+RHash (Recursive Hasher) is a console utility for calculation and
+verification of magnet links and various hash sums, including CRC32, CRC32C,
+MD4, MD5, SHA1, SHA256, SHA512, SHA3, AICH, ED2K, DC++ TTH, BitTorrent BTIH,
+Tiger, GOST R 34.11-94, GOST R 34.11-2012, RIPEMD-160, HAS-160, EDON-R, and
+Whirlpool.
+
+Hash sums are used to ensure and verify integrity of large volumes of data
+for a long-term storing or transferring.
+
+### Program features:
+ * Ability to process directories recursively.
+ * Output in a predefined (SFV, BSD-like) or a user-defined format.
+ * Calculation of Magnet links.
+ * Updating hash files (adding hash sums of files missing in the hash file).
+ * Calculates several hash sums in one pass.
+ * Portability: the program works the same on Linux, Unix, macOS or Windows.
+
+## Installation
+```shell
+./configure && make install
+```
+For more complicated cases of installation see the [INSTALL.md] file.
+
+## Documentation
+
+* RHash [ChangeLog]
+* [The LibRHash Library] documentation
+
+## Links
+* Project Home Page: http://rhash.sourceforge.net/
+* Official Releases: https://github.com/rhash/RHash/releases/
+* Binary Windows Releases: https://sf.net/projects/rhash/files/rhash/
+* The table of the supported by RHash [hash functions](http://sf.net/p/rhash/wiki/HashFunctions/)
+* ECRYPT [The Hash Function Zoo](http://ehash.iaik.tugraz.at/wiki/The_Hash_Function_Zoo)
+* ECRYPT [Benchmarking of hash functions](https://bench.cr.yp.to/results-hash.html)
+
+## Contribution
+Please read the [Contribution guidelines](docs/CONTRIBUTING.md) document.
+
+## Notes on RHash License
+The code is distributed under [RHash License](COPYING). Basically,
+the program, the library and source code can be used free of charge under
+the MIT, BSD, GPL, a commercial or a freeware license without additional
+restrictions. In the case an OSI-approved license is required the
+[MIT license] should be used.
+
+[INSTALL.md]: INSTALL.md
+[The LibRHash Library]: docs/LIBRHASH.md
+[ChangeLog]: ChangeLog
+[MIT license]: http://www.opensource.org/licenses/MIT
diff --git a/bindings/COPYING b/bindings/COPYING
index 847d032e..039aefb9 100644
--- a/bindings/COPYING
+++ b/bindings/COPYING
@@ -1,16 +1,16 @@
-
- RHash License
-
-Copyright (c) 2011-2014 Aleksey Kravchenko
-Copyright (c) 2011-2012 Sergey Basalaev
-
-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.
-
-The Software 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. Use this program at your own risk!
+
+ RHash License
+
+Copyright (c) 2011-2014 Aleksey Kravchenko
+Copyright (c) 2011-2012 Sergey Basalaev
+
+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.
+
+The Software 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. Use this program at your own risk!
diff --git a/bindings/ChangeLog b/bindings/ChangeLog
index 5bf9b703..48a16ae5 100644
--- a/bindings/ChangeLog
+++ b/bindings/ChangeLog
@@ -1,39 +1,39 @@
-Fri Aug 1 2014 Aleksey
- * python 3 support
- * update SHA3 test vectors to follow the changes of the spec
-
-Sun Jan 19 2014 Aleksey
- * renamed perl module to the Crypt::Rhash
-
-Tue Sep 17 2013 Aleksey
- * === Version 1.3.0 ===
-
-Tue Dec 25 2012 Aleksey
- * === Version 1.2.10 ===
-
-Sun May 13 2012 Aleksey
- * BugFix: python crashed on ia64
-
-Tue Apr 17 2012 Aleksey
- * PHP bindings for librhash
-
-Sat Apr 14 2012 Aleksey
- * === Version 1.2.9 ===
-
-Sun Nov 06 2011 Sergey Basalaev
- * .NET/Mono bindings to librhash
-
-Wed Sep 14 2011 Aleksey
- * === Version 1.2.8 ===
-
-Wed Sep 14 2011 Aleksey
- * Perl bindings
-
-Sat Jul 9 2011 Sergey Basalaev
- * Ruby bindings
-
-Thu Jun 16 2011 Sergey Basalaev
- * Python bindings
-
-Sun Jun 12 2011 Sergey Basalaev
- * LibRHash Java bindings
+Fri Aug 1 2014 Aleksey
+ * python 3 support
+ * update SHA3 test vectors to follow the changes of the spec
+
+Sun Jan 19 2014 Aleksey
+ * renamed perl module to the Crypt::Rhash
+
+Tue Sep 17 2013 Aleksey
+ * === Version 1.3.0 ===
+
+Tue Dec 25 2012 Aleksey
+ * === Version 1.2.10 ===
+
+Sun May 13 2012 Aleksey
+ * BugFix: python crashed on ia64
+
+Tue Apr 17 2012 Aleksey
+ * PHP bindings for librhash
+
+Sat Apr 14 2012 Aleksey
+ * === Version 1.2.9 ===
+
+Sun Nov 06 2011 Sergey Basalaev
+ * .NET/Mono bindings to librhash
+
+Wed Sep 14 2011 Aleksey
+ * === Version 1.2.8 ===
+
+Wed Sep 14 2011 Aleksey
+ * Perl bindings
+
+Sat Jul 9 2011 Sergey Basalaev
+ * Ruby bindings
+
+Thu Jun 16 2011 Sergey Basalaev
+ * Python bindings
+
+Sun Jun 12 2011 Sergey Basalaev
+ * LibRHash Java bindings
diff --git a/bindings/Makefile b/bindings/Makefile
index 61d58688..9886633f 100644
--- a/bindings/Makefile
+++ b/bindings/Makefile
@@ -1,125 +1,125 @@
-VERSION := $(shell sed -ne 's/^version=\(.*\)/\1/p' version.properties)
-BINDINGS = java mono perl python ruby php
-FILES = Makefile version.properties ChangeLog COPYING
-DESTDIR =
-PREFIX = /usr/local
-RUBY ?= ruby
-PYTHON ?= python
-PERL ?= perl
-PERL_LIBRHASH_TYPE ?= auto
-PERL_OPTIMIZE ?= -O2 -g -Wall
-ARCHIVE_GZIP = rhash-bindings-$(VERSION)-src.tar.gz
-COPYDIR = rhash-bindings-$(VERSION)
-CP = cp -l --parents
-
-all: configure build test
-clean: distclean
-
-configure: $(patsubst %, configure-%, $(filter perl ruby php, $(BINDINGS)))
-build: $(patsubst %, build-%, $(BINDINGS))
-test: $(patsubst %, test-%, $(BINDINGS))
-install: $(patsubst %, install-%, $(filter perl ruby php, $(BINDINGS)))
-distclean: $(patsubst %, clean-%, $(BINDINGS))
-
-configure-perl: perl/Makefile
-configure-ruby: ruby/Makefile
-configure-php: php/Makefile
-
-perl/Makefile: perl/Makefile.PL
- cd perl && LIBRHASH="$(PERL_LIBRHASH_TYPE)" $(PERL) Makefile.PL INSTALLDIRS=vendor
-
-php/Makefile: php/config.m4
- cd php && phpize && ./configure --with-rhash
-
-ruby/Makefile: ruby/extconf.rb
- $(RUBY) -C ruby extconf.rb
-
-build-java:
- +$(MAKE) -C java build-binary
-
-build-perl: configure-perl
- +$(MAKE) -C perl OPTIMIZE="$(PERL_OPTIMIZE)"
-
-build-php: configure-php
- +$(MAKE) -C php
-
-build-python:
-# not required
-
-build-ruby: configure-ruby
- +$(MAKE) -C ruby
-
-build-mono:
- +$(MAKE) -C mono
-
-test-java:
- +$(MAKE) -C java test
-
-test-perl:
- +$(MAKE) -C perl test
-
-test-php:
- +$(MAKE) -C php test TEST_PHP_ARGS=-q
-
-test-ruby:
- $(RUBY) -C ruby -I. test_rhash.rb
-
-test-mono:
- +$(MAKE) -C mono test
-
-test-python:
- $(PYTHON) python/test_rhash.py
-
-install-ruby:
-# clear MAKEFLAGS to overcome ruby1.8 mkmf concurrency bug
- +MAKEFLAGS= $(MAKE) -C ruby install DESTDIR=$(DESTDIR) sitedir=$(DESTDIR)/usr/lib/ruby
-
-install-perl:
- +$(MAKE) -C perl install DESTDIR=$(DESTDIR)
-
-install-php:
- +$(MAKE) -C php install INSTALL_ROOT=$(DESTDIR)
-
-copy-dist:
- mkdir -p $(COPYDIR)
- find java ruby python -type f -regex '.*\(\.\([hc]\|java\|py\|rb\|txt\)\|Makefile\)' -exec $(CP) '{}' $(COPYDIR)/ \;
- find mono -type f -regex '.*\(\.\([hc]\|cs\|xml\|txt\|snk\|sln\|csproj\|config\)\|Makefile\)' -exec $(CP) '{}' "$(COPYDIR)/" \;
- $(CP) $(shell sed -e 's/\([^ ]*\).*/perl\/\1/' perl/MANIFEST) "$(COPYDIR)/"
- find php -type f -regex '.*\.\(m4\|c\|h\|phpt\)' -exec $(CP) '{}' "$(COPYDIR)/" \;
- $(CP) $(FILES) "$(COPYDIR)/"
-
-gzip: distclean
- rm -rf "$(COPYDIR)" $(ARCHIVE_GZIP)
- +$(MAKE) copy-dist
- tar -czf $(ARCHIVE_GZIP) --owner=root:0 --group=root:0 "$(COPYDIR)"
- rm -rf "$(COPYDIR)"
-
-PERL_PKG_VER = $(shell [ -f perl/Rhash.pm ] && sed -ne "s/^our \+.VERSION *= *'\([0-9\.]*\)';/\1/p;" perl/Rhash.pm)
-PERL_PKG = Crypt-RHash-$(PERL_PKG_VER)
-
-cpan:
- [ -f ../librhash/rhash.h ]
- echo "$(PERL_PKG_VER)" | grep -q '^[0-9\.]\+$$'
- rm -rf $(PERL_PKG)/ $(PERL_PKG).tar.gz
- mkdir -p $(PERL_PKG)/librhash/
- grep -q / perl/MANIFEST && mkdir -p `sed -ne '/\//s/\([^\/]*\/\).*/$(PERL_PKG)\/\1/p' perl/MANIFEST | sort -u`
- sed -e 's/^\([^ ]*\)\( .*\)\?/cp perl\/\1 $(PERL_PKG)\/\1/' perl/MANIFEST > _cpy.sh
- sh _cpy.sh && rm -f _cpy.sh
- cp ../librhash/*.[hc] $(PERL_PKG)/librhash/
- cp perl/MANIFEST $(PERL_PKG)/
- find $(PERL_PKG)/librhash/ -type f -printf "librhash/%f\n" | sort >> $(PERL_PKG)/MANIFEST
- tar -czf $(PERL_PKG).tar.gz --owner=root:0 --group=root:0 $(PERL_PKG)/
- rm -rf $(PERL_PKG)/
-
-clean-java:
- +$(MAKE) -C java distclean
-clean-mono:
- +$(MAKE) -C mono clean
-clean-ruby:
- +[ ! -f ruby/Makefile ] || $(MAKE) -C ruby distclean
-clean-perl:
- +[ ! -f perl/Makefile ] || $(MAKE) -C perl distclean
-clean-php:
- [ ! -f php/configure ] || (cd php && phpize --clean)
-clean-python:
- rm -f python/*.pyc
+VERSION := $(shell sed -ne 's/^version=\(.*\)/\1/p' version.properties)
+BINDINGS = java mono perl python ruby php
+FILES = Makefile version.properties ChangeLog COPYING
+DESTDIR =
+PREFIX = /usr/local
+RUBY ?= ruby
+PYTHON ?= python
+PERL ?= perl
+PERL_LIBRHASH_TYPE ?= auto
+PERL_OPTIMIZE ?= -O2 -g -Wall
+ARCHIVE_GZIP = rhash-bindings-$(VERSION)-src.tar.gz
+COPYDIR = rhash-bindings-$(VERSION)
+CP = cp -l --parents
+
+all: configure build test
+clean: distclean
+
+configure: $(patsubst %, configure-%, $(filter perl ruby php, $(BINDINGS)))
+build: $(patsubst %, build-%, $(BINDINGS))
+test: $(patsubst %, test-%, $(BINDINGS))
+install: $(patsubst %, install-%, $(filter perl ruby php, $(BINDINGS)))
+distclean: $(patsubst %, clean-%, $(BINDINGS))
+
+configure-perl: perl/Makefile
+configure-ruby: ruby/Makefile
+configure-php: php/Makefile
+
+perl/Makefile: perl/Makefile.PL
+ cd perl && LIBRHASH="$(PERL_LIBRHASH_TYPE)" $(PERL) Makefile.PL INSTALLDIRS=vendor
+
+php/Makefile: php/config.m4
+ cd php && phpize && ./configure --with-rhash
+
+ruby/Makefile: ruby/extconf.rb
+ $(RUBY) -C ruby extconf.rb
+
+build-java:
+ +$(MAKE) -C java build-binary
+
+build-perl: configure-perl
+ +$(MAKE) -C perl OPTIMIZE="$(PERL_OPTIMIZE)"
+
+build-php: configure-php
+ +$(MAKE) -C php
+
+build-python:
+# not required
+
+build-ruby: configure-ruby
+ +$(MAKE) -C ruby
+
+build-mono:
+ +$(MAKE) -C mono
+
+test-java:
+ +$(MAKE) -C java test
+
+test-perl:
+ +$(MAKE) -C perl test
+
+test-php:
+ +$(MAKE) -C php test TEST_PHP_ARGS=-q
+
+test-ruby:
+ $(RUBY) -C ruby -I. test_rhash.rb
+
+test-mono:
+ +$(MAKE) -C mono test
+
+test-python:
+ $(PYTHON) python/test_rhash.py
+
+install-ruby:
+# clear MAKEFLAGS to overcome ruby1.8 mkmf concurrency bug
+ +MAKEFLAGS= $(MAKE) -C ruby install DESTDIR=$(DESTDIR) sitedir=$(DESTDIR)/usr/lib/ruby
+
+install-perl:
+ +$(MAKE) -C perl install DESTDIR=$(DESTDIR)
+
+install-php:
+ +$(MAKE) -C php install INSTALL_ROOT=$(DESTDIR)
+
+copy-dist:
+ mkdir -p $(COPYDIR)
+ find java ruby python -type f -regex '.*\(\.\([hc]\|java\|py\|rb\|txt\)\|Makefile\)' -exec $(CP) '{}' $(COPYDIR)/ \;
+ find mono -type f -regex '.*\(\.\([hc]\|cs\|xml\|txt\|snk\|sln\|csproj\|config\)\|Makefile\)' -exec $(CP) '{}' "$(COPYDIR)/" \;
+ $(CP) $(shell sed -e 's/\([^ ]*\).*/perl\/\1/' perl/MANIFEST) "$(COPYDIR)/"
+ find php -type f -regex '.*\.\(m4\|c\|h\|phpt\)' -exec $(CP) '{}' "$(COPYDIR)/" \;
+ $(CP) $(FILES) "$(COPYDIR)/"
+
+gzip: distclean
+ rm -rf "$(COPYDIR)" $(ARCHIVE_GZIP)
+ +$(MAKE) copy-dist
+ tar -czf $(ARCHIVE_GZIP) --owner=root:0 --group=root:0 "$(COPYDIR)"
+ rm -rf "$(COPYDIR)"
+
+PERL_PKG_VER = $(shell [ -f perl/Rhash.pm ] && sed -ne "s/^our \+.VERSION *= *'\([0-9\.]*\)';/\1/p;" perl/Rhash.pm)
+PERL_PKG = Crypt-RHash-$(PERL_PKG_VER)
+
+cpan:
+ [ -f ../librhash/rhash.h ]
+ echo "$(PERL_PKG_VER)" | grep -q '^[0-9\.]\+$$'
+ rm -rf $(PERL_PKG)/ $(PERL_PKG).tar.gz
+ mkdir -p $(PERL_PKG)/librhash/
+ grep -q / perl/MANIFEST && mkdir -p `sed -ne '/\//s/\([^\/]*\/\).*/$(PERL_PKG)\/\1/p' perl/MANIFEST | sort -u`
+ sed -e 's/^\([^ ]*\)\( .*\)\?/cp perl\/\1 $(PERL_PKG)\/\1/' perl/MANIFEST > _cpy.sh
+ sh _cpy.sh && rm -f _cpy.sh
+ cp ../librhash/*.[hc] $(PERL_PKG)/librhash/
+ cp perl/MANIFEST $(PERL_PKG)/
+ find $(PERL_PKG)/librhash/ -type f -printf "librhash/%f\n" | sort >> $(PERL_PKG)/MANIFEST
+ tar -czf $(PERL_PKG).tar.gz --owner=root:0 --group=root:0 $(PERL_PKG)/
+ rm -rf $(PERL_PKG)/
+
+clean-java:
+ +$(MAKE) -C java distclean
+clean-mono:
+ +$(MAKE) -C mono clean
+clean-ruby:
+ +[ ! -f ruby/Makefile ] || $(MAKE) -C ruby distclean
+clean-perl:
+ +[ ! -f perl/Makefile ] || $(MAKE) -C perl distclean
+clean-php:
+ [ ! -f php/configure ] || (cd php && phpize --clean)
+clean-python:
+ rm -f python/*.pyc
diff --git a/bindings/java/.gitignore b/bindings/java/.gitignore
index c80ee191..53ec1ad4 100644
--- a/bindings/java/.gitignore
+++ b/bindings/java/.gitignore
@@ -1,4 +1,4 @@
-classes/*
-dist/*
-*.so
-*.class
+classes/*
+dist/*
+*.so
+*.class
diff --git a/bindings/java/Makefile b/bindings/java/Makefile
index 3f786b97..2ee711a2 100644
--- a/bindings/java/Makefile
+++ b/bindings/java/Makefile
@@ -1,106 +1,106 @@
-#!/usr/bin/make -f
-
-# This file is a part of Java Bindings for Librhash
-# Copyright (c) 2011-2012, Sergey Basalaev
-# Librhash is (c) 2011-2012, Aleksey Kravchenko
-#
-# 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.
-#
-# This library 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. Use it at your own risk!
-
-
-JAVA = java
-JAVAC = javac
-JAVADOC = javadoc
-JAVAH = javah
-JAR = jar
-JUNIT_CLASSPATH = /usr/share/java/junit4.jar
-
-VERSION = $(shell sed -ne 's/^version=\(.*\)/\1/p' ../version.properties)
-
-JAVASRC_DIR = src
-CSRC_DIR = native
-DEST_DIR = dist
-CLASSES_DIR = classes
-JAVADOC_DIR = javadoc
-TEST_DIR = test
-
-JAVA_FILES := $(shell find $(JAVASRC_DIR) -name '*.java')
-JNI_FILES := $(shell find $(CSRC_DIR) -name '*.c' -o -name '*.h')
-LIB_PREFIX = lib
-LIB_SUFFIX = .so
-JNI_LIBRARY = $(LIB_PREFIX)rhash-jni$(LIB_SUFFIX)
-JARFILE = $(DEST_DIR)/rhash-$(VERSION).jar
-JAVADOC_FILE = $(DEST_DIR)/rhash-$(VERSION)-javadoc.zip
-JAVADOC_API_URL = http://download.oracle.com/javase/6/docs/api/
-
-
-all: build-binary javadoc
-build-binary: jar jar-symlink jni
-jar: $(JARFILE)
-jni: $(DEST_DIR)/$(JNI_LIBRARY)
-zip-javadoc: $(JAVADOC_FILE)
-
-jar-symlink:
- mkdir -p $(DEST_DIR)
- ln -fs rhash-$(VERSION).jar $(DEST_DIR)/rhash.jar
-
-$(JARFILE): $(JAVA_FILES)
- +$(MAKE) compile-classes
- mkdir -p $(DEST_DIR)
- $(JAR) cf $(JARFILE) -C $(CLASSES_DIR) org/
-
-compile-classes:
- mkdir -p $(CLASSES_DIR)
- $(JAVAC) -d $(CLASSES_DIR) -sourcepath $(JAVASRC_DIR) $(JAVA_FILES)
-
-update-header: compile-classes
- $(JAVAH) -o $(CSRC_DIR)/bindings.h -classpath $(CLASSES_DIR) org.sf.rhash.Bindings
-
-$(DEST_DIR)/$(JNI_LIBRARY): $(JNI_FILES)
- +$(MAKE) -C $(CSRC_DIR)
- mkdir -p $(DEST_DIR)
- cp $(CSRC_DIR)/$(JNI_LIBRARY) $(DEST_DIR)
-
-javadoc: clean-javadoc
- $(JAVADOC) -windowtitle 'RHash' \
- -sourcepath $(JAVASRC_DIR) \
- -subpackages org \
- -d $(JAVADOC_DIR) \
- -link $(JAVADOC_API_URL)
-
-$(JAVADOC_FILE): $(JAVA_FILES)
- +$(MAKE) javadoc
- jar -cMf $(JAVADOC_FILE) $(JAVADOC_DIR)
-
-$(TEST_DIR)/RHashTest.class: $(JARFILE) $(TEST_DIR)/RHashTest.java
- $(JAVAC) -classpath $(JARFILE):$(JUNIT_CLASSPATH) $(TEST_DIR)/RHashTest.java
-
-test: $(TEST_DIR)/RHashTest.class jni
- $(JAVA) -classpath $(TEST_DIR):$(JARFILE):$(JUNIT_CLASSPATH) -Djava.library.path=$(DEST_DIR) junit.textui.TestRunner RHashTest
-
-clean: clean-javadoc clean-jni clean-classes clean-test
-
-clean-javadoc:
- rm -rf $(JAVADOC_DIR)
-
-clean-classes:
- rm -rf $(CLASSES_DIR)
-
-clean-jni:
- +$(MAKE) -C $(CSRC_DIR) clean
-
-clean-test:
- rm -f $(TEST_DIR)/*.class
-
-distclean: clean
- rm -rf $(DEST_DIR)
-
-.PHONY: jar jni javadoc test clean clean-javadoc distclean
+#!/usr/bin/make -f
+
+# This file is a part of Java Bindings for Librhash
+# Copyright (c) 2011-2012, Sergey Basalaev
+# Librhash is (c) 2011-2012, Aleksey Kravchenko
+#
+# 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.
+#
+# This library 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. Use it at your own risk!
+
+
+JAVA = java
+JAVAC = javac
+JAVADOC = javadoc
+JAVAH = javah
+JAR = jar
+JUNIT_CLASSPATH = /usr/share/java/junit4.jar
+
+VERSION = $(shell sed -ne 's/^version=\(.*\)/\1/p' ../version.properties)
+
+JAVASRC_DIR = src
+CSRC_DIR = native
+DEST_DIR = dist
+CLASSES_DIR = classes
+JAVADOC_DIR = javadoc
+TEST_DIR = test
+
+JAVA_FILES := $(shell find $(JAVASRC_DIR) -name '*.java')
+JNI_FILES := $(shell find $(CSRC_DIR) -name '*.c' -o -name '*.h')
+LIB_PREFIX = lib
+LIB_SUFFIX = .so
+JNI_LIBRARY = $(LIB_PREFIX)rhash-jni$(LIB_SUFFIX)
+JARFILE = $(DEST_DIR)/rhash-$(VERSION).jar
+JAVADOC_FILE = $(DEST_DIR)/rhash-$(VERSION)-javadoc.zip
+JAVADOC_API_URL = http://download.oracle.com/javase/6/docs/api/
+
+
+all: build-binary javadoc
+build-binary: jar jar-symlink jni
+jar: $(JARFILE)
+jni: $(DEST_DIR)/$(JNI_LIBRARY)
+zip-javadoc: $(JAVADOC_FILE)
+
+jar-symlink:
+ mkdir -p $(DEST_DIR)
+ ln -fs rhash-$(VERSION).jar $(DEST_DIR)/rhash.jar
+
+$(JARFILE): $(JAVA_FILES)
+ +$(MAKE) compile-classes
+ mkdir -p $(DEST_DIR)
+ $(JAR) cf $(JARFILE) -C $(CLASSES_DIR) org/
+
+compile-classes:
+ mkdir -p $(CLASSES_DIR)
+ $(JAVAC) -d $(CLASSES_DIR) -sourcepath $(JAVASRC_DIR) $(JAVA_FILES)
+
+update-header: compile-classes
+ $(JAVAH) -o $(CSRC_DIR)/bindings.h -classpath $(CLASSES_DIR) org.sf.rhash.Bindings
+
+$(DEST_DIR)/$(JNI_LIBRARY): $(JNI_FILES)
+ +$(MAKE) -C $(CSRC_DIR)
+ mkdir -p $(DEST_DIR)
+ cp $(CSRC_DIR)/$(JNI_LIBRARY) $(DEST_DIR)
+
+javadoc: clean-javadoc
+ $(JAVADOC) -windowtitle 'RHash' \
+ -sourcepath $(JAVASRC_DIR) \
+ -subpackages org \
+ -d $(JAVADOC_DIR) \
+ -link $(JAVADOC_API_URL)
+
+$(JAVADOC_FILE): $(JAVA_FILES)
+ +$(MAKE) javadoc
+ jar -cMf $(JAVADOC_FILE) $(JAVADOC_DIR)
+
+$(TEST_DIR)/RHashTest.class: $(JARFILE) $(TEST_DIR)/RHashTest.java
+ $(JAVAC) -classpath $(JARFILE):$(JUNIT_CLASSPATH) $(TEST_DIR)/RHashTest.java
+
+test: $(TEST_DIR)/RHashTest.class jni
+ $(JAVA) -classpath $(TEST_DIR):$(JARFILE):$(JUNIT_CLASSPATH) -Djava.library.path=$(DEST_DIR) junit.textui.TestRunner RHashTest
+
+clean: clean-javadoc clean-jni clean-classes clean-test
+
+clean-javadoc:
+ rm -rf $(JAVADOC_DIR)
+
+clean-classes:
+ rm -rf $(CLASSES_DIR)
+
+clean-jni:
+ +$(MAKE) -C $(CSRC_DIR) clean
+
+clean-test:
+ rm -f $(TEST_DIR)/*.class
+
+distclean: clean
+ rm -rf $(DEST_DIR)
+
+.PHONY: jar jni javadoc test clean clean-javadoc distclean
diff --git a/bindings/java/native/Makefile b/bindings/java/native/Makefile
index 2897ceb1..702d9e0e 100644
--- a/bindings/java/native/Makefile
+++ b/bindings/java/native/Makefile
@@ -1,48 +1,48 @@
-#!/usr/bin/make -f
-
-# This file is a part of Java Bindings for Librhash
-# Copyright (c) 2011-2012, Sergey Basalaev
-# Librhash is (c) 2011-2012, Aleksey Kravchenko
-#
-# 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.
-#
-# This library 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. Use it at your own risk!
-
-
-CC = gcc
-CFLAGS = -g -O2
-LDFLAGS =
-LIBRHASH_INC =
-LIBRHASH_LD =
-ALLLDFLAGS = $(LDFLAGS) -lrhash $(LIBRHASH_LD)
-ALLCFLAGS = $(CFLAGS) $(LIBRHASH_INC) -fPIC
-
-#Platform dependent
-JNI_CFLAGS = -I/usr/lib/jvm/default-java/include
-LIB_PREFIX = lib
-LIB_SUFFIX = .so
-
-OBJECTS = bindings.o digest.o
-LIBRARY = $(LIB_PREFIX)rhash-jni$(LIB_SUFFIX)
-
-all: $(LIBRARY)
-
-bindings.o: bindings.c bindings.h
- $(CC) $(ALLCFLAGS) $(JNI_CFLAGS) -c $< -o $@
-
-digest.o: digest.c digest.h
- $(CC) $(ALLCFLAGS) -c $< -o $@
-
-$(LIBRARY): $(OBJECTS)
- $(CC) -shared -o $@ $(OBJECTS) $(ALLLDFLAGS)
-
-clean:
- rm -f *.o $(LIBRARY)
-
+#!/usr/bin/make -f
+
+# This file is a part of Java Bindings for Librhash
+# Copyright (c) 2011-2012, Sergey Basalaev
+# Librhash is (c) 2011-2012, Aleksey Kravchenko
+#
+# 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.
+#
+# This library 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. Use it at your own risk!
+
+
+CC = gcc
+CFLAGS = -g -O2
+LDFLAGS =
+LIBRHASH_INC =
+LIBRHASH_LD =
+ALLLDFLAGS = $(LDFLAGS) -lrhash $(LIBRHASH_LD)
+ALLCFLAGS = $(CFLAGS) $(LIBRHASH_INC) -fPIC
+
+#Platform dependent
+JNI_CFLAGS = -I/usr/lib/jvm/default-java/include
+LIB_PREFIX = lib
+LIB_SUFFIX = .so
+
+OBJECTS = bindings.o digest.o
+LIBRARY = $(LIB_PREFIX)rhash-jni$(LIB_SUFFIX)
+
+all: $(LIBRARY)
+
+bindings.o: bindings.c bindings.h
+ $(CC) $(ALLCFLAGS) $(JNI_CFLAGS) -c $< -o $@
+
+digest.o: digest.c digest.h
+ $(CC) $(ALLCFLAGS) -c $< -o $@
+
+$(LIBRARY): $(OBJECTS)
+ $(CC) -shared -o $@ $(OBJECTS) $(ALLLDFLAGS)
+
+clean:
+ rm -f *.o $(LIBRARY)
+
diff --git a/bindings/java/native/bindings.c b/bindings/java/native/bindings.c
index 89fa83ac..9f804146 100644
--- a/bindings/java/native/bindings.c
+++ b/bindings/java/native/bindings.c
@@ -1,231 +1,231 @@
-/*
- * This file is a part of Java Bindings for Librhash
- * Copyright (c) 2011-2012, Sergey Basalaev
- * Librhash is (c) 2011-2012, Aleksey Kravchenko
- *
- * 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.
- *
- * This library 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. Use it at your own risk!
- */
-
-#include
-#include
-
-#ifdef __GNUC__
-#include
-#define TO_RHASH(a) ((rhash)(intptr_t)(a))
-#define TO_DIGEST(a) ((Digest)(intptr_t)(a))
-#define TO_JLONG(a) ((jlong)(intptr_t)(a))
-#else
-#define TO_RHASH(a) ((rhash)(a))
-#define TO_DIGEST(a) ((Digest)(a))
-#define TO_JLONG(a) ((jlong)(a))
-#endif /* __GNUC__ */
-
-
-#include "bindings.h"
-#include "digest.h"
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_library_init
- * Signature: ()V
- */
-JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1library_1init
-(JNIEnv *env, jclass clz) {
- rhash_library_init();
-}
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_count
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_org_sf_rhash_Bindings_rhash_1count
-(JNIEnv *env, jclass clz) {
- return rhash_count();
-}
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_msg
- * Signature: (I[BII)J
- */
-JNIEXPORT jlong JNICALL Java_org_sf_rhash_Bindings_rhash_1msg
-(JNIEnv *env, jclass clz, jint hash_id, jbyteArray buf, jint ofs, jint len) {
- // reading data
- void* msg = malloc(len);
- (*env)->GetByteArrayRegion(env, buf, ofs, len, msg);
- // creating and populating Digest
- Digest obj = malloc(sizeof(DigestStruct));
- obj->hash_len = rhash_get_digest_size(hash_id);
- obj->hash_data = calloc(obj->hash_len, sizeof(unsigned char));
- rhash_msg(hash_id, msg, len, obj->hash_data);
- //cleaning
- free(msg);
- //returning
- return TO_JLONG(obj);
-}
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_print_bytes
- * Signature: (JI)[B
- */
-JNIEXPORT jbyteArray JNICALL Java_org_sf_rhash_Bindings_rhash_1print_1bytes
-(JNIEnv *env, jclass clz, jlong ptr, jint flags) {
- Digest obj = TO_DIGEST(ptr);
- char output[130];
- int len = rhash_print_bytes(output, obj->hash_data, obj->hash_len, flags);
- jbyteArray arr = (*env)->NewByteArray(env, len);
- (*env)->SetByteArrayRegion(env, arr, 0, len, (jbyte*)output);
- return arr;
-}
-
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_print_magnet
- * Signature: (JLjava/lang/String;I)Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL Java_org_sf_rhash_Bindings_rhash_1print_1magnet
-(JNIEnv *env, jclass clz, jlong context, jstring filepath, jint flags) {
- const char* fpath = (filepath != NULL) ?
- (*env)->GetStringUTFChars(env, filepath, NULL) : NULL;
- size_t len = rhash_print_magnet(NULL, fpath, TO_RHASH(context), flags, RHPR_FILESIZE);
- char *buf = (char*)malloc(len);
- rhash_print_magnet(buf, fpath, TO_RHASH(context), flags, RHPR_FILESIZE);
- if (filepath != NULL) {
- (*env)->ReleaseStringUTFChars(env, filepath, fpath);
- }
- jstring str = (*env)->NewStringUTF(env, buf);
- free(buf);
- return str;
-}
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_is_base32
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL Java_org_sf_rhash_Bindings_rhash_1is_1base32
-(JNIEnv *env, jclass clz, jint hash_id) {
- return rhash_is_base32(hash_id);
-}
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_get_digest_size
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL Java_org_sf_rhash_Bindings_rhash_1get_1digest_1size
-(JNIEnv *env, jclass clz, jint hash_id) {
- return rhash_get_digest_size(hash_id);
-}
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_init
- * Signature: (I)J
- */
-JNIEXPORT jlong JNICALL Java_org_sf_rhash_Bindings_rhash_1init
-(JNIEnv *env, jclass clz, jint hash_flags) {
- rhash ctx = rhash_init(hash_flags);
- rhash_set_autofinal(ctx, 0);
- return TO_JLONG(ctx);
-}
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_update
- * Signature: (J[BII)V
- */
-JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1update
-(JNIEnv *env, jclass clz, jlong context, jbyteArray data, jint ofs, jint len) {
- void* msg = malloc(len);
- (*env)->GetByteArrayRegion(env, data, ofs, len, msg);
- rhash_update(TO_RHASH(context), msg, len);
- free(msg);
-}
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_final
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1final
-(JNIEnv *env, jclass clz, jlong context) {
- rhash_final(TO_RHASH(context), NULL);
-}
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_reset
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1reset
-(JNIEnv *env, jclass clz, jlong context) {
- rhash_reset(TO_RHASH(context));
-}
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_print
- * Signature: (JI)J
- */
-JNIEXPORT jlong JNICALL Java_org_sf_rhash_Bindings_rhash_1print
-(JNIEnv *env, jclass clz, jlong context, jint hash_id) {
- Digest obj = malloc(sizeof(DigestStruct));
- obj->hash_len = rhash_get_digest_size(hash_id);
- obj->hash_data = calloc(obj->hash_len, sizeof(unsigned char));
- rhash_print((char*)obj->hash_data, TO_RHASH(context), hash_id, RHPR_RAW);
- return TO_JLONG(obj);
-}
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_free
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1free
-(JNIEnv *env, jclass clz, jlong context) {
- rhash_free(TO_RHASH(context));
-}
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: compareDigests
- * Signature: (JJ)Z
- */
-JNIEXPORT jboolean JNICALL Java_org_sf_rhash_Bindings_compareDigests
-(JNIEnv *env, jclass clz, jlong ptr1, jlong ptr2) {
- return compareDigests(TO_DIGEST(ptr1), TO_DIGEST(ptr2));
-}
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: hashcodeForDigest
- * Signature: (J)I
- */
-JNIEXPORT jint JNICALL Java_org_sf_rhash_Bindings_hashcodeForDigest
-(JNIEnv *env, jclass clz, jlong ptr) {
- return hashcodeForDigest(TO_DIGEST(ptr));
-}
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: freeDigest
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_freeDigest
-(JNIEnv *env, jclass clz, jlong ptr) {
- freeDigest(TO_DIGEST(ptr));
-}
-
+/*
+ * This file is a part of Java Bindings for Librhash
+ * Copyright (c) 2011-2012, Sergey Basalaev
+ * Librhash is (c) 2011-2012, Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This library 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. Use it at your own risk!
+ */
+
+#include
+#include
+
+#ifdef __GNUC__
+#include
+#define TO_RHASH(a) ((rhash)(intptr_t)(a))
+#define TO_DIGEST(a) ((Digest)(intptr_t)(a))
+#define TO_JLONG(a) ((jlong)(intptr_t)(a))
+#else
+#define TO_RHASH(a) ((rhash)(a))
+#define TO_DIGEST(a) ((Digest)(a))
+#define TO_JLONG(a) ((jlong)(a))
+#endif /* __GNUC__ */
+
+
+#include "bindings.h"
+#include "digest.h"
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_library_init
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1library_1init
+(JNIEnv *env, jclass clz) {
+ rhash_library_init();
+}
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_count
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_org_sf_rhash_Bindings_rhash_1count
+(JNIEnv *env, jclass clz) {
+ return rhash_count();
+}
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_msg
+ * Signature: (I[BII)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sf_rhash_Bindings_rhash_1msg
+(JNIEnv *env, jclass clz, jint hash_id, jbyteArray buf, jint ofs, jint len) {
+ // reading data
+ void* msg = malloc(len);
+ (*env)->GetByteArrayRegion(env, buf, ofs, len, msg);
+ // creating and populating Digest
+ Digest obj = malloc(sizeof(DigestStruct));
+ obj->hash_len = rhash_get_digest_size(hash_id);
+ obj->hash_data = calloc(obj->hash_len, sizeof(unsigned char));
+ rhash_msg(hash_id, msg, len, obj->hash_data);
+ //cleaning
+ free(msg);
+ //returning
+ return TO_JLONG(obj);
+}
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_print_bytes
+ * Signature: (JI)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_org_sf_rhash_Bindings_rhash_1print_1bytes
+(JNIEnv *env, jclass clz, jlong ptr, jint flags) {
+ Digest obj = TO_DIGEST(ptr);
+ char output[130];
+ int len = rhash_print_bytes(output, obj->hash_data, obj->hash_len, flags);
+ jbyteArray arr = (*env)->NewByteArray(env, len);
+ (*env)->SetByteArrayRegion(env, arr, 0, len, (jbyte*)output);
+ return arr;
+}
+
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_print_magnet
+ * Signature: (JLjava/lang/String;I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sf_rhash_Bindings_rhash_1print_1magnet
+(JNIEnv *env, jclass clz, jlong context, jstring filepath, jint flags) {
+ const char* fpath = (filepath != NULL) ?
+ (*env)->GetStringUTFChars(env, filepath, NULL) : NULL;
+ size_t len = rhash_print_magnet(NULL, fpath, TO_RHASH(context), flags, RHPR_FILESIZE);
+ char *buf = (char*)malloc(len);
+ rhash_print_magnet(buf, fpath, TO_RHASH(context), flags, RHPR_FILESIZE);
+ if (filepath != NULL) {
+ (*env)->ReleaseStringUTFChars(env, filepath, fpath);
+ }
+ jstring str = (*env)->NewStringUTF(env, buf);
+ free(buf);
+ return str;
+}
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_is_base32
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_sf_rhash_Bindings_rhash_1is_1base32
+(JNIEnv *env, jclass clz, jint hash_id) {
+ return rhash_is_base32(hash_id);
+}
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_get_digest_size
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_org_sf_rhash_Bindings_rhash_1get_1digest_1size
+(JNIEnv *env, jclass clz, jint hash_id) {
+ return rhash_get_digest_size(hash_id);
+}
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_init
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sf_rhash_Bindings_rhash_1init
+(JNIEnv *env, jclass clz, jint hash_flags) {
+ rhash ctx = rhash_init(hash_flags);
+ rhash_set_autofinal(ctx, 0);
+ return TO_JLONG(ctx);
+}
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_update
+ * Signature: (J[BII)V
+ */
+JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1update
+(JNIEnv *env, jclass clz, jlong context, jbyteArray data, jint ofs, jint len) {
+ void* msg = malloc(len);
+ (*env)->GetByteArrayRegion(env, data, ofs, len, msg);
+ rhash_update(TO_RHASH(context), msg, len);
+ free(msg);
+}
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_final
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1final
+(JNIEnv *env, jclass clz, jlong context) {
+ rhash_final(TO_RHASH(context), NULL);
+}
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_reset
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1reset
+(JNIEnv *env, jclass clz, jlong context) {
+ rhash_reset(TO_RHASH(context));
+}
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_print
+ * Signature: (JI)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sf_rhash_Bindings_rhash_1print
+(JNIEnv *env, jclass clz, jlong context, jint hash_id) {
+ Digest obj = malloc(sizeof(DigestStruct));
+ obj->hash_len = rhash_get_digest_size(hash_id);
+ obj->hash_data = calloc(obj->hash_len, sizeof(unsigned char));
+ rhash_print((char*)obj->hash_data, TO_RHASH(context), hash_id, RHPR_RAW);
+ return TO_JLONG(obj);
+}
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_free
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1free
+(JNIEnv *env, jclass clz, jlong context) {
+ rhash_free(TO_RHASH(context));
+}
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: compareDigests
+ * Signature: (JJ)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_sf_rhash_Bindings_compareDigests
+(JNIEnv *env, jclass clz, jlong ptr1, jlong ptr2) {
+ return compareDigests(TO_DIGEST(ptr1), TO_DIGEST(ptr2));
+}
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: hashcodeForDigest
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_sf_rhash_Bindings_hashcodeForDigest
+(JNIEnv *env, jclass clz, jlong ptr) {
+ return hashcodeForDigest(TO_DIGEST(ptr));
+}
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: freeDigest
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_freeDigest
+(JNIEnv *env, jclass clz, jlong ptr) {
+ freeDigest(TO_DIGEST(ptr));
+}
+
diff --git a/bindings/java/native/bindings.h b/bindings/java/native/bindings.h
index a060ca47..1c589f29 100644
--- a/bindings/java/native/bindings.h
+++ b/bindings/java/native/bindings.h
@@ -1,141 +1,141 @@
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include
-/* Header for class org_sf_rhash_Bindings */
-
-#ifndef _Included_org_sf_rhash_Bindings
-#define _Included_org_sf_rhash_Bindings
-#ifdef __cplusplus
-extern "C" {
-#endif
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_library_init
- * Signature: ()V
- */
-JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1library_1init
- (JNIEnv *, jclass);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_count
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_org_sf_rhash_Bindings_rhash_1count
- (JNIEnv *, jclass);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_msg
- * Signature: (I[BII)J
- */
-JNIEXPORT jlong JNICALL Java_org_sf_rhash_Bindings_rhash_1msg
- (JNIEnv *, jclass, jint, jbyteArray, jint, jint);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_print_bytes
- * Signature: (JI)[B
- */
-JNIEXPORT jbyteArray JNICALL Java_org_sf_rhash_Bindings_rhash_1print_1bytes
- (JNIEnv *, jclass, jlong, jint);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_print_magnet
- * Signature: (JLjava/lang/String;I)Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL Java_org_sf_rhash_Bindings_rhash_1print_1magnet
- (JNIEnv *, jclass, jlong, jstring, jint);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_is_base32
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL Java_org_sf_rhash_Bindings_rhash_1is_1base32
- (JNIEnv *, jclass, jint);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_get_digest_size
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL Java_org_sf_rhash_Bindings_rhash_1get_1digest_1size
- (JNIEnv *, jclass, jint);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_init
- * Signature: (I)J
- */
-JNIEXPORT jlong JNICALL Java_org_sf_rhash_Bindings_rhash_1init
- (JNIEnv *, jclass, jint);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_update
- * Signature: (J[BII)V
- */
-JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1update
- (JNIEnv *, jclass, jlong, jbyteArray, jint, jint);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_final
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1final
- (JNIEnv *, jclass, jlong);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_reset
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1reset
- (JNIEnv *, jclass, jlong);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_print
- * Signature: (JI)J
- */
-JNIEXPORT jlong JNICALL Java_org_sf_rhash_Bindings_rhash_1print
- (JNIEnv *, jclass, jlong, jint);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: rhash_free
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1free
- (JNIEnv *, jclass, jlong);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: compareDigests
- * Signature: (JJ)Z
- */
-JNIEXPORT jboolean JNICALL Java_org_sf_rhash_Bindings_compareDigests
- (JNIEnv *, jclass, jlong, jlong);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: hashcodeForDigest
- * Signature: (J)I
- */
-JNIEXPORT jint JNICALL Java_org_sf_rhash_Bindings_hashcodeForDigest
- (JNIEnv *, jclass, jlong);
-
-/*
- * Class: org_sf_rhash_Bindings
- * Method: freeDigest
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_freeDigest
- (JNIEnv *, jclass, jlong);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include
+/* Header for class org_sf_rhash_Bindings */
+
+#ifndef _Included_org_sf_rhash_Bindings
+#define _Included_org_sf_rhash_Bindings
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_library_init
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1library_1init
+ (JNIEnv *, jclass);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_count
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_org_sf_rhash_Bindings_rhash_1count
+ (JNIEnv *, jclass);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_msg
+ * Signature: (I[BII)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sf_rhash_Bindings_rhash_1msg
+ (JNIEnv *, jclass, jint, jbyteArray, jint, jint);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_print_bytes
+ * Signature: (JI)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_org_sf_rhash_Bindings_rhash_1print_1bytes
+ (JNIEnv *, jclass, jlong, jint);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_print_magnet
+ * Signature: (JLjava/lang/String;I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sf_rhash_Bindings_rhash_1print_1magnet
+ (JNIEnv *, jclass, jlong, jstring, jint);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_is_base32
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_sf_rhash_Bindings_rhash_1is_1base32
+ (JNIEnv *, jclass, jint);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_get_digest_size
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_org_sf_rhash_Bindings_rhash_1get_1digest_1size
+ (JNIEnv *, jclass, jint);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_init
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sf_rhash_Bindings_rhash_1init
+ (JNIEnv *, jclass, jint);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_update
+ * Signature: (J[BII)V
+ */
+JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1update
+ (JNIEnv *, jclass, jlong, jbyteArray, jint, jint);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_final
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1final
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_reset
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1reset
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_print
+ * Signature: (JI)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sf_rhash_Bindings_rhash_1print
+ (JNIEnv *, jclass, jlong, jint);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: rhash_free
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1free
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: compareDigests
+ * Signature: (JJ)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_sf_rhash_Bindings_compareDigests
+ (JNIEnv *, jclass, jlong, jlong);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: hashcodeForDigest
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_sf_rhash_Bindings_hashcodeForDigest
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_sf_rhash_Bindings
+ * Method: freeDigest
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_freeDigest
+ (JNIEnv *, jclass, jlong);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/bindings/java/native/digest.c b/bindings/java/native/digest.c
index ed12905b..88f34299 100644
--- a/bindings/java/native/digest.c
+++ b/bindings/java/native/digest.c
@@ -1,45 +1,45 @@
-/*
- * This file is a part of Java Bindings for Librhash
- * Copyright (c) 2011-2012, Sergey Basalaev
- * Librhash is (c) 2011-2012, Aleksey Kravchenko
- *
- * 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.
- *
- * This library 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. Use it at your own risk!
- */
-
-#include
-#include
-
-#include "digest.h"
-
-void freeDigest(Digest obj) {
- free(obj->hash_data);
- free(obj);
-}
-
-int compareDigests(Digest o1, Digest o2) {
- if (o1->hash_len != o2->hash_len) return 0;
- return memcmp(o1->hash_data, o2->hash_data, o1->hash_len) == 0;
-}
-
-int hashcodeForDigest(Digest obj) {
- int hash = 123321, i;
- for (i = 0; i < obj->hash_len; i++) {
- switch (i % 3) {
- case 0: hash ^= obj->hash_data[i];
- case 1: hash ^= obj->hash_data[i] << 8;
- case 2: hash ^= obj->hash_data[i] << 16;
- case 3: hash ^= obj->hash_data[i] << 24;
- }
- }
- return hash ^ (obj->hash_id + obj->hash_len);
-}
-
+/*
+ * This file is a part of Java Bindings for Librhash
+ * Copyright (c) 2011-2012, Sergey Basalaev
+ * Librhash is (c) 2011-2012, Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This library 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. Use it at your own risk!
+ */
+
+#include
+#include
+
+#include "digest.h"
+
+void freeDigest(Digest obj) {
+ free(obj->hash_data);
+ free(obj);
+}
+
+int compareDigests(Digest o1, Digest o2) {
+ if (o1->hash_len != o2->hash_len) return 0;
+ return memcmp(o1->hash_data, o2->hash_data, o1->hash_len) == 0;
+}
+
+int hashcodeForDigest(Digest obj) {
+ int hash = 123321, i;
+ for (i = 0; i < obj->hash_len; i++) {
+ switch (i % 3) {
+ case 0: hash ^= obj->hash_data[i];
+ case 1: hash ^= obj->hash_data[i] << 8;
+ case 2: hash ^= obj->hash_data[i] << 16;
+ case 3: hash ^= obj->hash_data[i] << 24;
+ }
+ }
+ return hash ^ (obj->hash_id + obj->hash_len);
+}
+
diff --git a/bindings/java/native/digest.h b/bindings/java/native/digest.h
index 20f41ddd..4f289d01 100644
--- a/bindings/java/native/digest.h
+++ b/bindings/java/native/digest.h
@@ -1,51 +1,51 @@
-/*
- * This file is a part of Java Bindings for Librhash
- * Copyright (c) 2011-2012, Sergey Basalaev
- * Librhash is (c) 2011-2012, Aleksey Kravchenko
- *
- * 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.
- *
- * This library 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. Use it at your own risk!
- */
-
-/* This is convenient structure to hold message digest. */
-
-#ifndef DIGEST_H
-#define DIGEST_H
-
-typedef struct {
- int hash_id;
- size_t hash_len;
- unsigned char *hash_data;
-} DigestStruct;
-
-typedef DigestStruct* Digest;
-
-/**
- * Frees memory occupated by Digest.
- * @param obj object to free
- */
-void freeDigest(Digest obj);
-
-/**
- * Compares two Digest instances.
- * @param obj1 first object to compare
- * @param obj2 second object to compare
- * @return 1 if objects are equal, 0 otherwise
- */
-int compareDigests(Digest obj1, Digest obj2);
-
-/**
- * Calculates hashcode for Digest.
- * @param obj object to calculate hash code
- */
-int hashcodeForDigest(Digest obj);
-
-#endif /* DIGEST_H */
+/*
+ * This file is a part of Java Bindings for Librhash
+ * Copyright (c) 2011-2012, Sergey Basalaev
+ * Librhash is (c) 2011-2012, Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This library 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. Use it at your own risk!
+ */
+
+/* This is convenient structure to hold message digest. */
+
+#ifndef DIGEST_H
+#define DIGEST_H
+
+typedef struct {
+ int hash_id;
+ size_t hash_len;
+ unsigned char *hash_data;
+} DigestStruct;
+
+typedef DigestStruct* Digest;
+
+/**
+ * Frees memory occupated by Digest.
+ * @param obj object to free
+ */
+void freeDigest(Digest obj);
+
+/**
+ * Compares two Digest instances.
+ * @param obj1 first object to compare
+ * @param obj2 second object to compare
+ * @return 1 if objects are equal, 0 otherwise
+ */
+int compareDigests(Digest obj1, Digest obj2);
+
+/**
+ * Calculates hashcode for Digest.
+ * @param obj object to calculate hash code
+ */
+int hashcodeForDigest(Digest obj);
+
+#endif /* DIGEST_H */
diff --git a/bindings/java/src/org/sf/rhash/Bindings.java b/bindings/java/src/org/sf/rhash/Bindings.java
index fb67b417..70689641 100644
--- a/bindings/java/src/org/sf/rhash/Bindings.java
+++ b/bindings/java/src/org/sf/rhash/Bindings.java
@@ -1,151 +1,151 @@
-/*
- * This file is a part of Java Bindings for Librhash
- * Copyright (c) 2011-2012, Sergey Basalaev
- * Librhash is (c) 2011-2012, Aleksey Kravchenko
- *
- * 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.
- *
- * This library 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. Use it at your own risk!
- */
-
-package org.sf.rhash;
-
-/**
- * Glue to the native API.
- */
-final class Bindings {
-
- /** This class is not instantiable. */
- private Bindings() { }
-
- /**
- * Initializes library.
- */
- static native void rhash_library_init();
-
- /**
- * Returns the number of supported hash algorithms.
- */
- static native int rhash_count();
-
- /**
- * Computes a hash of the given data.
- *
- * @param hash_id id of hash function
- * @param data the data to process
- * @param ofs offset in data array from which to start processing
- * @param len data length
- * @return pointer to the native digest object
- */
- static native long rhash_msg(int hash_id, byte[] data, int ofs, int len);
-
- /**
- * Prints text representation of a given digest.
- *
- * @param rhash pointer to native digest object
- * @param flags output flags
- * @return text representation as byte array
- */
- static native byte[] rhash_print_bytes(long rhash, int flags);
-
- /**
- * Returns magnet link for given hash context and hashing algorithms.
- *
- * @param rhash pointer to native digest object
- * @param filename the name of the file to incorporate in magnet
- * @param flags mask of hash_id values
- * @return magnet string
- */
- static native String rhash_print_magnet(long rhash, String filename, int flags);
-
- /**
- * Tests whether given default hash algorithm output is base32.
- * @param hash_id id of hash function
- * @return true
if default output for hash algorithm is base32,
- * false
otherwise
- */
- static native boolean rhash_is_base32(int hash_id);
-
- /**
- * Returns size of binary message digest.
- * @param hash_id id of hash function
- * @return size of message digest
- */
- static native int rhash_get_digest_size(int hash_id);
-
- /**
- * Creates new hash context.
- * @param flags mask of hash_id values
- * @return pointer to the native hash context
- */
- static native long rhash_init(int flags);
-
- /**
- * Updates hash context with given data.
- * @param rhash pointer to native hash context
- * @param data data to process
- * @param ofs index of the first byte to process
- * @param len count of bytes to process
- */
- static native void rhash_update(long rhash, byte[] data, int ofs, int len);
-
- /**
- * Finalizes hash context.
- * @param rhash pointer to native hash context
- */
- static native void rhash_final(long rhash);
-
- /**
- * Resets hash context.
- * @param rhash pointer to native hash context
- */
- static native void rhash_reset(long rhash);
-
- /**
- * Generates message digest for given context and hash_id.
- * @param rhash pointer to native hash context
- * @param hash_id id of hashing algorithm
- * @return pointer to native digest
- */
- static native long rhash_print(long rhash, int hash_id);
-
- /**
- * Frees hash context.
- * @param rhash pointer to native hash context
- */
- static native void rhash_free(long rhash);
-
- /**
- * Compares two native hash objects.
- * @param hash1 pointer to first object
- * @param hash2 pointer to second object
- * @return true
if objects are the same,
- * false
otherwise
- */
- static native boolean compareDigests(long hash1, long hash2);
-
- /**
- * Computes hashcode for native digest object.
- * @param hash pointer to first object
- * @return hash code for the object
- */
- static native int hashcodeForDigest(long hash);
-
- /**
- * Frees previously created native digest object.
- */
- static native void freeDigest(long hash);
-
- static {
- System.loadLibrary("rhash-jni");
- rhash_library_init();
- }
-}
-
+/*
+ * This file is a part of Java Bindings for Librhash
+ * Copyright (c) 2011-2012, Sergey Basalaev
+ * Librhash is (c) 2011-2012, Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This library 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. Use it at your own risk!
+ */
+
+package org.sf.rhash;
+
+/**
+ * Glue to the native API.
+ */
+final class Bindings {
+
+ /** This class is not instantiable. */
+ private Bindings() { }
+
+ /**
+ * Initializes library.
+ */
+ static native void rhash_library_init();
+
+ /**
+ * Returns the number of supported hash algorithms.
+ */
+ static native int rhash_count();
+
+ /**
+ * Computes a hash of the given data.
+ *
+ * @param hash_id id of hash function
+ * @param data the data to process
+ * @param ofs offset in data array from which to start processing
+ * @param len data length
+ * @return pointer to the native digest object
+ */
+ static native long rhash_msg(int hash_id, byte[] data, int ofs, int len);
+
+ /**
+ * Prints text representation of a given digest.
+ *
+ * @param rhash pointer to native digest object
+ * @param flags output flags
+ * @return text representation as byte array
+ */
+ static native byte[] rhash_print_bytes(long rhash, int flags);
+
+ /**
+ * Returns magnet link for given hash context and hashing algorithms.
+ *
+ * @param rhash pointer to native digest object
+ * @param filename the name of the file to incorporate in magnet
+ * @param flags mask of hash_id values
+ * @return magnet string
+ */
+ static native String rhash_print_magnet(long rhash, String filename, int flags);
+
+ /**
+ * Tests whether given default hash algorithm output is base32.
+ * @param hash_id id of hash function
+ * @return true
if default output for hash algorithm is base32,
+ * false
otherwise
+ */
+ static native boolean rhash_is_base32(int hash_id);
+
+ /**
+ * Returns size of binary message digest.
+ * @param hash_id id of hash function
+ * @return size of message digest
+ */
+ static native int rhash_get_digest_size(int hash_id);
+
+ /**
+ * Creates new hash context.
+ * @param flags mask of hash_id values
+ * @return pointer to the native hash context
+ */
+ static native long rhash_init(int flags);
+
+ /**
+ * Updates hash context with given data.
+ * @param rhash pointer to native hash context
+ * @param data data to process
+ * @param ofs index of the first byte to process
+ * @param len count of bytes to process
+ */
+ static native void rhash_update(long rhash, byte[] data, int ofs, int len);
+
+ /**
+ * Finalizes hash context.
+ * @param rhash pointer to native hash context
+ */
+ static native void rhash_final(long rhash);
+
+ /**
+ * Resets hash context.
+ * @param rhash pointer to native hash context
+ */
+ static native void rhash_reset(long rhash);
+
+ /**
+ * Generates message digest for given context and hash_id.
+ * @param rhash pointer to native hash context
+ * @param hash_id id of hashing algorithm
+ * @return pointer to native digest
+ */
+ static native long rhash_print(long rhash, int hash_id);
+
+ /**
+ * Frees hash context.
+ * @param rhash pointer to native hash context
+ */
+ static native void rhash_free(long rhash);
+
+ /**
+ * Compares two native hash objects.
+ * @param hash1 pointer to first object
+ * @param hash2 pointer to second object
+ * @return true
if objects are the same,
+ * false
otherwise
+ */
+ static native boolean compareDigests(long hash1, long hash2);
+
+ /**
+ * Computes hashcode for native digest object.
+ * @param hash pointer to first object
+ * @return hash code for the object
+ */
+ static native int hashcodeForDigest(long hash);
+
+ /**
+ * Frees previously created native digest object.
+ */
+ static native void freeDigest(long hash);
+
+ static {
+ System.loadLibrary("rhash-jni");
+ rhash_library_init();
+ }
+}
+
diff --git a/bindings/java/src/org/sf/rhash/Digest.java b/bindings/java/src/org/sf/rhash/Digest.java
index 7f7fa347..828b0ed7 100644
--- a/bindings/java/src/org/sf/rhash/Digest.java
+++ b/bindings/java/src/org/sf/rhash/Digest.java
@@ -1,156 +1,156 @@
-/*
- * This file is a part of Java Bindings for Librhash
- * Copyright (c) 2011-2012, Sergey Basalaev
- * Librhash is (c) 2011-2012, Aleksey Kravchenko
- *
- * 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.
- *
- * This library 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. Use it at your own risk!
- */
-
-package org.sf.rhash;
-
-/**
- * Message digest.
- */
-public final class Digest {
-
- static final int RAW = 0x1;
- static final int HEX = 0x2;
- static final int BASE32 = 0x3;
- static final int BASE64 = 0x4;
- static final int UPPERCASE = 0x8;
- static final int REVERSE = 0x10;
-
- private final HashType type;
-
- /** Pointer to native structure. */
- private final long digest_ptr;
-
- /**
- * Creates new Digest
.
- * @param ptr pointer to the native object
- * @param type hash type
- */
- Digest(long ptr, HashType type) {
- this.digest_ptr = ptr;
- this.type = type;
- }
-
- /**
- * Returns type of hashing algorithm that produced
- * this digest.
- *
- * @return type of hashing algorithm
- */
- public HashType hashType() {
- return type;
- }
-
- /**
- * Returns value of this digest as raw bytes.
- * This method allocates new byte array, modifying it
- * has no effect on this Digest
.
- *
- * @return value of this digest as raw bytes
- * @see #hex()
- * @see #base32()
- * @see #base64()
- */
- public byte[] raw() {
- return Bindings.rhash_print_bytes(digest_ptr, RAW);
- }
-
- /**
- * Returns value of this digest as hexadecimal string.
- *
- * @return value of the digest as hexadecimal string
- * @see #raw()
- * @see #base32()
- * @see #base64()
- */
- public String hex() {
- return new String(Bindings.rhash_print_bytes(digest_ptr, HEX));
- }
-
- /**
- * Returns value of this digest as base32 string.
- *
- * @return value of the digest as base32 string
- * @see #raw()
- * @see #hex()
- * @see #base64()
- */
- public String base32() {
- return new String(Bindings.rhash_print_bytes(digest_ptr, BASE32));
- }
-
- /**
- * Returns value of this digest as base64 string.
- *
- * @return value of the digest as base64 string
- * @see #raw()
- * @see #hex()
- * @see #base32()
- */
- public String base64() {
- return new String(Bindings.rhash_print_bytes(digest_ptr, BASE64));
- }
-
- /**
- * Called by garbage collector to free native resources.
- */
- @Override
- protected void finalize() {
- Bindings.freeDigest(digest_ptr);
- }
-
- /**
- * Returns string representation of this object.
- * If default output for hashing algorithm is base32 then
- * returned value is the same as if base32()
- * method was called; otherwise value is the same as returned
- * by hex()
method.
- *
- * @return string representation of this object
- * @see #base32()
- * @see #hex()
- */
- @Override
- public String toString() {
- return (Bindings.rhash_is_base32(type.hashId())) ? base32() : hex();
- }
-
- /**
- * Tests whether this object equals to another one
- * @param obj object to compare to
- * @return
- * true
if obj
is Digest
- * instance with the same HashType
and value;
- * otherwise false
- */
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof Digest)) return false;
- final Digest other = (Digest)obj;
- if (!this.hashType().equals(other.hashType())) return false;
- if (this.digest_ptr == other.digest_ptr) return true;
- return Bindings.compareDigests(this.digest_ptr, other.digest_ptr);
- }
-
- /**
- * Returns hash code for this object.
- * @return hash code for the object
- */
- @Override
- public int hashCode() {
- return Bindings.hashcodeForDigest(digest_ptr);
- }
-}
+/*
+ * This file is a part of Java Bindings for Librhash
+ * Copyright (c) 2011-2012, Sergey Basalaev
+ * Librhash is (c) 2011-2012, Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This library 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. Use it at your own risk!
+ */
+
+package org.sf.rhash;
+
+/**
+ * Message digest.
+ */
+public final class Digest {
+
+ static final int RAW = 0x1;
+ static final int HEX = 0x2;
+ static final int BASE32 = 0x3;
+ static final int BASE64 = 0x4;
+ static final int UPPERCASE = 0x8;
+ static final int REVERSE = 0x10;
+
+ private final HashType type;
+
+ /** Pointer to native structure. */
+ private final long digest_ptr;
+
+ /**
+ * Creates new Digest
.
+ * @param ptr pointer to the native object
+ * @param type hash type
+ */
+ Digest(long ptr, HashType type) {
+ this.digest_ptr = ptr;
+ this.type = type;
+ }
+
+ /**
+ * Returns type of hashing algorithm that produced
+ * this digest.
+ *
+ * @return type of hashing algorithm
+ */
+ public HashType hashType() {
+ return type;
+ }
+
+ /**
+ * Returns value of this digest as raw bytes.
+ * This method allocates new byte array, modifying it
+ * has no effect on this Digest
.
+ *
+ * @return value of this digest as raw bytes
+ * @see #hex()
+ * @see #base32()
+ * @see #base64()
+ */
+ public byte[] raw() {
+ return Bindings.rhash_print_bytes(digest_ptr, RAW);
+ }
+
+ /**
+ * Returns value of this digest as hexadecimal string.
+ *
+ * @return value of the digest as hexadecimal string
+ * @see #raw()
+ * @see #base32()
+ * @see #base64()
+ */
+ public String hex() {
+ return new String(Bindings.rhash_print_bytes(digest_ptr, HEX));
+ }
+
+ /**
+ * Returns value of this digest as base32 string.
+ *
+ * @return value of the digest as base32 string
+ * @see #raw()
+ * @see #hex()
+ * @see #base64()
+ */
+ public String base32() {
+ return new String(Bindings.rhash_print_bytes(digest_ptr, BASE32));
+ }
+
+ /**
+ * Returns value of this digest as base64 string.
+ *
+ * @return value of the digest as base64 string
+ * @see #raw()
+ * @see #hex()
+ * @see #base32()
+ */
+ public String base64() {
+ return new String(Bindings.rhash_print_bytes(digest_ptr, BASE64));
+ }
+
+ /**
+ * Called by garbage collector to free native resources.
+ */
+ @Override
+ protected void finalize() {
+ Bindings.freeDigest(digest_ptr);
+ }
+
+ /**
+ * Returns string representation of this object.
+ * If default output for hashing algorithm is base32 then
+ * returned value is the same as if base32()
+ * method was called; otherwise value is the same as returned
+ * by hex()
method.
+ *
+ * @return string representation of this object
+ * @see #base32()
+ * @see #hex()
+ */
+ @Override
+ public String toString() {
+ return (Bindings.rhash_is_base32(type.hashId())) ? base32() : hex();
+ }
+
+ /**
+ * Tests whether this object equals to another one
+ * @param obj object to compare to
+ * @return
+ * true
if obj
is Digest
+ * instance with the same HashType
and value;
+ * otherwise false
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Digest)) return false;
+ final Digest other = (Digest)obj;
+ if (!this.hashType().equals(other.hashType())) return false;
+ if (this.digest_ptr == other.digest_ptr) return true;
+ return Bindings.compareDigests(this.digest_ptr, other.digest_ptr);
+ }
+
+ /**
+ * Returns hash code for this object.
+ * @return hash code for the object
+ */
+ @Override
+ public int hashCode() {
+ return Bindings.hashcodeForDigest(digest_ptr);
+ }
+}
diff --git a/bindings/java/src/org/sf/rhash/HashType.java b/bindings/java/src/org/sf/rhash/HashType.java
index 8c0d8768..815e23c4 100644
--- a/bindings/java/src/org/sf/rhash/HashType.java
+++ b/bindings/java/src/org/sf/rhash/HashType.java
@@ -1,132 +1,132 @@
-/*
- * This file is a part of Java Bindings for Librhash
- * Copyright (c) 2011-2012, 2014, Sergey Basalaev
- * Librhash is (c) 2011-2014, Aleksey Kravchenko
- *
- * 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.
- *
- * This library 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. Use it at your own risk!
- */
-
-package org.sf.rhash;
-
-/**
- * Type of hashing algorithm. Supported algorithms are CRC32, CRC32C,
- * MD4, MD5, SHA1/SHA2, Tiger, DC++ TTH, BitTorrent BTIH,
- * AICH, EDonkey 2000 hash, GOST R 34.11-94, GOST R 34.11-2012,
- * RIPEMD-160, HAS-160, EDON-R 256/512, Whirlpool and Snefru-128/256.
- */
-public enum HashType {
- /** CRC32 checksum. */
- CRC32(1),
- /** MD4 hash. */
- MD4(1 << 1),
- /** MD5 hash. */
- MD5(1 << 2),
- /** SHA-1 hash. */
- SHA1(1 << 3),
- /** Tiger hash. */
- TIGER(1 << 4),
- /** Tiger tree hash */
- TTH(1 << 5),
- /** BitTorrent info hash. */
- BTIH(1 << 6),
- /** EDonkey 2000 hash. */
- ED2K(1 << 7),
- /** eMule AICH. */
- AICH(1 << 8),
- /** Whirlpool hash. */
- WHIRLPOOL(1 << 9),
- /** RIPEMD-160 hash. */
- RIPEMD160(1 << 10),
- /** GOST R 34.11-94. */
- GOST94(1 << 11),
- GOST94_CRYPTOPRO(1 << 12),
- /** HAS-160 hash. */
- HAS160(1 << 13),
- /** GOST R 34.11-2012 - 256 bit. */
- GOST12_256(1 << 14),
- /** GOST R 34.11-2012 - 512 bit. */
- GOST12_512(1 << 15),
- /** SHA-224 hash. */
- SHA224(1 << 16),
- /** SHA-256 hash. */
- SHA256(1 << 17),
- /** SHA-384 hash. */
- SHA384(1 << 18),
- /** SHA-512 hash. */
- SHA512(1 << 19),
- /** EDON-R 256. */
- EDONR256(1 << 20),
- /** EDON-R 512. */
- EDONR512(1 << 21),
- /** SHA3-224 hash. */
- SHA3_224(1 << 22),
- /** SHA3-256 hash. */
- SHA3_256(1 << 23),
- /** SHA3-384 hash. */
- SHA3_384(1 << 24),
- /** SHA3-512 hash. */
- SHA3_512(1 << 25),
- /** CRC32C checksum. */
- CRC32C(1 << 26),
- /** Snefru-128 hash. */
- SNEFRU128(1 << 27),
- /** Snefru-256 hash. */
- SNEFRU256(1 << 28);
-
- /** hash_id for the native API */
- private int hashId;
-
- /**
- * Construct HashType for specified native hash_id
- * @param hashId hash identifier for native API
- */
- private HashType(int hashId) {
- this.hashId = hashId;
- }
-
- /**
- * Returns hash_id for the native API.
- * @return hash identifier
- */
- int hashId() {
- return hashId;
- }
-
- /**
- * Returns lowest HashType
for given id mask.
- * Used by RHash.getDigest()
.
- * @param flags mask of hash identifiers
- * @return HashType
object or null
- * if no HashType
for given mask exists
- */
- static HashType forHashFlags(int flags) {
- if (flags == 0) return null;
- int lowest = 0;
- while ((flags % 2) == 0) {
- flags >>>= 1;
- lowest++;
- }
- for (HashType t : HashType.values()) {
- if (t.hashId == (1 << lowest)) return t;
- }
- return null;
- }
-
- /**
- * Returns size of binary digest for this type.
- * @return size of binary digest, in bytes
- */
- public int getDigestSize() {
- //TODO: rhash_get_digest_size
- return -1;
- }
-}
+/*
+ * This file is a part of Java Bindings for Librhash
+ * Copyright (c) 2011-2012, 2014, Sergey Basalaev
+ * Librhash is (c) 2011-2014, Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This library 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. Use it at your own risk!
+ */
+
+package org.sf.rhash;
+
+/**
+ * Type of hashing algorithm. Supported algorithms are CRC32, CRC32C,
+ * MD4, MD5, SHA1/SHA2, Tiger, DC++ TTH, BitTorrent BTIH,
+ * AICH, EDonkey 2000 hash, GOST R 34.11-94, GOST R 34.11-2012,
+ * RIPEMD-160, HAS-160, EDON-R 256/512, Whirlpool and Snefru-128/256.
+ */
+public enum HashType {
+ /** CRC32 checksum. */
+ CRC32(1),
+ /** MD4 hash. */
+ MD4(1 << 1),
+ /** MD5 hash. */
+ MD5(1 << 2),
+ /** SHA-1 hash. */
+ SHA1(1 << 3),
+ /** Tiger hash. */
+ TIGER(1 << 4),
+ /** Tiger tree hash */
+ TTH(1 << 5),
+ /** BitTorrent info hash. */
+ BTIH(1 << 6),
+ /** EDonkey 2000 hash. */
+ ED2K(1 << 7),
+ /** eMule AICH. */
+ AICH(1 << 8),
+ /** Whirlpool hash. */
+ WHIRLPOOL(1 << 9),
+ /** RIPEMD-160 hash. */
+ RIPEMD160(1 << 10),
+ /** GOST R 34.11-94. */
+ GOST94(1 << 11),
+ GOST94_CRYPTOPRO(1 << 12),
+ /** HAS-160 hash. */
+ HAS160(1 << 13),
+ /** GOST R 34.11-2012 - 256 bit. */
+ GOST12_256(1 << 14),
+ /** GOST R 34.11-2012 - 512 bit. */
+ GOST12_512(1 << 15),
+ /** SHA-224 hash. */
+ SHA224(1 << 16),
+ /** SHA-256 hash. */
+ SHA256(1 << 17),
+ /** SHA-384 hash. */
+ SHA384(1 << 18),
+ /** SHA-512 hash. */
+ SHA512(1 << 19),
+ /** EDON-R 256. */
+ EDONR256(1 << 20),
+ /** EDON-R 512. */
+ EDONR512(1 << 21),
+ /** SHA3-224 hash. */
+ SHA3_224(1 << 22),
+ /** SHA3-256 hash. */
+ SHA3_256(1 << 23),
+ /** SHA3-384 hash. */
+ SHA3_384(1 << 24),
+ /** SHA3-512 hash. */
+ SHA3_512(1 << 25),
+ /** CRC32C checksum. */
+ CRC32C(1 << 26),
+ /** Snefru-128 hash. */
+ SNEFRU128(1 << 27),
+ /** Snefru-256 hash. */
+ SNEFRU256(1 << 28);
+
+ /** hash_id for the native API */
+ private int hashId;
+
+ /**
+ * Construct HashType for specified native hash_id
+ * @param hashId hash identifier for native API
+ */
+ private HashType(int hashId) {
+ this.hashId = hashId;
+ }
+
+ /**
+ * Returns hash_id for the native API.
+ * @return hash identifier
+ */
+ int hashId() {
+ return hashId;
+ }
+
+ /**
+ * Returns lowest HashType
for given id mask.
+ * Used by RHash.getDigest()
.
+ * @param flags mask of hash identifiers
+ * @return HashType
object or null
+ * if no HashType
for given mask exists
+ */
+ static HashType forHashFlags(int flags) {
+ if (flags == 0) return null;
+ int lowest = 0;
+ while ((flags % 2) == 0) {
+ flags >>>= 1;
+ lowest++;
+ }
+ for (HashType t : HashType.values()) {
+ if (t.hashId == (1 << lowest)) return t;
+ }
+ return null;
+ }
+
+ /**
+ * Returns size of binary digest for this type.
+ * @return size of binary digest, in bytes
+ */
+ public int getDigestSize() {
+ //TODO: rhash_get_digest_size
+ return -1;
+ }
+}
diff --git a/bindings/java/src/org/sf/rhash/RHash.java b/bindings/java/src/org/sf/rhash/RHash.java
index ede5d16e..bc62b165 100644
--- a/bindings/java/src/org/sf/rhash/RHash.java
+++ b/bindings/java/src/org/sf/rhash/RHash.java
@@ -1,449 +1,449 @@
-/*
- * This file is a part of Java Bindings for Librhash
- * Copyright (c) 2011-2012, Sergey Basalaev
- * Librhash is (c) 2011-2012, Aleksey Kravchenko
- *
- * 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.
- *
- * This library 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. Use it at your own risk!
- */
-
-package org.sf.rhash;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.util.Set;
-
-/**
- * Incremental hasher.
- * This class allows you to do incremental hashing for set
- * of hashing algorithms.
- *
- * To do hashing RHash
instance is first created
- * and then filled with message chunks using update()
- * methods. Finally, finish()
should be called to end
- * all calculations and generate digests, which then can be obtained
- * with getDigest()
method. Note, that trying to update
- * finished RHash
has no effect other than throwing
- * IllegalStateException
though you can reuse this class
- * by calling reset()
method, returning it to the state
- * which was immediately after creating.
- *
- * To quickly produce message digest for a single message/file
- * and a single algorithm you may use convenience methods
- * RHash.computeHash()
.
- *
- * This class is thread safe.
- *
- */
-public final class RHash {
-
- /* == EXCEPTION MESSAGES == */
-
- static private final String ERR_FINISHED = "RHash is finished, data update is not possible";
- static private final String ERR_NOHASH = "No HashTypes specified";
- static private final String ERR_UNFINISHED = "RHash should be finished before generating Digest";
- static private final String ERR_WRONGTYPE = "RHash was not created to generate Digest for ";
-
- /**
- * Computes hash of given range in data.
- * This method calculates message digest for byte subsequence
- * in array data
starting from data[ofs]
- * and ending at data[ofs+len-1]
.
- *
- * @param type type of hash algorithm
- * @param data the bytes to process
- * @param ofs index of the first byte in array to process
- * @param len count of bytes to process
- * @return message digest for specified subarray
- * @throws NullPointerException
- * if either type
or data
- * is null
- * @throws IndexOutOfBoundsException
- * if ofs < 0
, len < 0
or
- * ofs+len > data.length
- */
- static public Digest computeHash(HashType type, byte[] data, int ofs, int len) {
- if (type == null || data == null) {
- throw new NullPointerException();
- }
- if (ofs < 0 || len < 0 || ofs+len > data.length) {
- throw new IndexOutOfBoundsException();
- }
- return new Digest(Bindings.rhash_msg(type.hashId(), data, ofs, len), type);
- }
-
- /**
- * Computes hash of given data.
- *
- * @param type type of hash algorithm
- * @param data the bytes to process
- * @return message digest for specified array
- * @throws NullPointerException
- * if either type
or data
- * is null
- */
- static public Digest computeHash(HashType type, byte[] data) {
- return computeHash(type, data, 0, data.length);
- }
-
- /**
- * Computes hash of given string.
- * String is encoded into a sequence of bytes
- * using the specified charset.
- *
- * @param type type of hash algorithm
- * @param str the string to process
- * @param encoding encoding to use
- * @return message digest for specified string
- * @throws NullPointerException if any of arguments is null
- * @throws UnsupportedEncodingException if specified encoding is not supported
- */
- static public Digest computeHash(HashType type, String str, String encoding)
- throws UnsupportedEncodingException {
- if (type == null || str == null || encoding == null) {
- throw new NullPointerException();
- }
- return computeHash(type, str.getBytes(encoding));
- }
-
- /**
- * Computes hash of given string.
- * String is encoded into a sequence of bytes using the
- * default platform encoding.
- *
- * @param type type of hash algorithm
- * @param str the string to process
- * @return message digest for specified string
- * @throws NullPointerException if any of arguments is null
- */
- static public Digest computeHash(HashType type, String str) {
- if (type == null || str == null) throw new NullPointerException();
- return computeHash(type, str.getBytes());
- }
-
- /**
- * Computes hash of given string.
- * @param type type of hash algorithm
- * @param file the file to process
- * @return data hash
- * @throws NullPointerException if any of arguments is null
- * @throws IOException
- * if an I/O error occurs while hashing
- */
- static public Digest computeHash(HashType type, File file) throws IOException {
- if (type == null || file == null) {
- throw new NullPointerException();
- }
- RHash hasher = new RHash(type);
- hasher.update(file).finish();
- return hasher.getDigest();
- }
-
- /**
- * Produces magnet link for specified file with given hashes.
- *
- * @param filename the file to generate magnet for
- * @param types types of hashing algorithms
- */
- static public String getMagnetFor(String filename, HashType... types) throws IOException {
- RHash hasher = new RHash(types);
- hasher.update(new File(filename)).finish();
- return hasher.getMagnet(filename);
- }
-
- /**
- * Produces magnet link for specified file with given hashes.
- *
- * @param filename the file to generate magnet for
- * @param types set of hashing types
- */
- static public String getMagnetFor(String filename, Set types) throws IOException {
- RHash hasher = new RHash(types);
- hasher.update(new File(filename)).finish();
- return hasher.getMagnet(filename);
- }
-
- /** Indicates whether this RHash
is finished. */
- private boolean finished = false;
-
- /** Mask of hash_id values. */
- private final int hash_flags;
-
- /** Pointer to the native hash context. */
- private final long context_ptr;
-
- /** Default hash type used in getDigest()
. */
- private final HashType deftype;
-
- /**
- * Creates new RHash
to compute
- * message digests for given types.
- * @param types types of hashing algorithms
- * @throws NullPointerException
- * if any of arguments is null
- * @throws IllegalArgumentException
- * if zero hash types specified
- */
- public RHash(HashType... types) {
- if (types.length == 0) {
- throw new IllegalArgumentException(ERR_NOHASH);
- }
- int flags = 0;
- HashType def = types[0];
- for (HashType t : types) {
- flags |= t.hashId();
- if (def.compareTo(t) > 0) def = t;
- }
- this.deftype = def;
- this.hash_flags = flags;
- this.context_ptr = Bindings.rhash_init(flags);
- }
-
- /**
- * Creates new RHash
to compute
- * message digests for given types.
- * @param types set of hashing types
- * @throws NullPointerException
- * if argument is null
- * @throws IllegalArgumentException
- * if argument is empty set
- */
- public RHash(Set types) {
- if (types.isEmpty()) {
- throw new IllegalArgumentException(ERR_NOHASH);
- }
- int flags = 0;
- HashType def = null;
- for (HashType t : types) {
- flags |= t.hashId();
- if (def == null || def.compareTo(t) > 0) def = t;
- }
- this.deftype = def;
- this.hash_flags = flags;
- this.context_ptr = Bindings.rhash_init(flags);
- }
-
- /**
- * Updates this RHash
with new data chunk.
- * This method hashes bytes from data[ofs]
- * through data[ofs+len-1]
.
- *
- * @param data data to be hashed
- * @param ofs index of the first byte to hash
- * @param len number of bytes to hash
- * @return this object
- * @throws NullPointerException
- * if data
is null
- * @throws IndexOutOfBoundsException
- * if ofs < 0
, len < 0
or
- * ofs+len > data.length
- * @throws IllegalStateException
- * if finish()
was called and there were no
- * subsequent calls of reset()
- */
- public synchronized RHash update(byte[] data, int ofs, int len) {
- if (finished) {
- throw new IllegalStateException(ERR_FINISHED);
- }
- if (ofs < 0 || len < 0 || ofs+len > data.length) {
- throw new IndexOutOfBoundsException();
- }
- Bindings.rhash_update(context_ptr, data, ofs, len);
- return this;
- }
-
- /**
- * Updates this RHash
with new data chunk.
- * This method has the same effect as
- * update(data, 0, data.length)
- *
- * @param data data to be hashed
- * @return this object
- * @throws NullPointerException
- * if data
is null
- * @throws IllegalStateException
- * if finish()
was called and there were no
- * subsequent calls of reset()
- */
- public RHash update(byte[] data) {
- return update(data, 0, data.length);
- }
-
- /**
- * Updates this RHash
with new data chunk.
- * String is encoded into a sequence of bytes using the
- * default platform encoding.
- *
- * @param str string to be hashed
- * @return this object
- * @throws NullPointerException
- * if str
is null
- * @throws IllegalStateException
- * if finish()
was called and there were no
- * subsequent calls of reset()
- */
- public RHash update(String str) {
- return update(str.getBytes());
- }
-
- /**
- * Updates this RHash
with data from given file.
- *
- * @param file file to be hashed
- * @return this object
- * @throws IOException if an I/O error occurs
- * @throws NullPointerException
- * if file
is null
- * @throws IllegalStateException
- * if finish()
was called and there were no
- * subsequent calls of reset()
- */
- public synchronized RHash update(File file) throws IOException {
- if (finished) {
- throw new IllegalStateException(ERR_FINISHED);
- }
- InputStream in = new FileInputStream(file);
- byte[] buf = new byte[8192]; //shouldn't we avoid magic numbers?
- int len = in.read(buf);
- while (len > 0) {
- this.update(buf, 0, len);
- len = in.read(buf);
- }
- in.close();
- return this;
- }
-
- /**
- * Finishes calculation of hash codes.
- * Does nothing if RHash
is already finished.
- */
- public synchronized void finish() {
- if (!finished) {
- Bindings.rhash_final(context_ptr);
- finished = true;
- }
- }
-
- /**
- * Resets this RHash
to initial state.
- * The RHash
becomes available to process
- * new data chunks. Note, that this method returns
- * RHash
to the state after creating the
- * object, NOT the state when hashing continues.
- * Therefore, all previously calculated hashes are lost
- * and process starts from the very beginning.
- */
- public synchronized void reset() {
- Bindings.rhash_reset(context_ptr);
- finished = false;
- }
-
- /**
- * Tests whether this RHash
is finished or not.
- * @return
- * false
if this RHash
is ready to
- * receive new data for hashing;
- * true
if hash calculations are finished
- */
- public boolean isFinished() {
- return finished;
- }
-
- /**
- * Returns digest for given hash type.
- *
- * @param type hash type
- * @return Digest
for processed data
- * @throws NullPointerException
- * if type
is null
- * @throws IllegalStateException
- * if this RHash
is not finished
- * @throws IllegalArgumentException
- * if this RHash
was not created to calculate
- * hash for specified algorithm
- */
- public Digest getDigest(HashType type) {
- if (type == null) {
- throw new NullPointerException();
- }
- if (!finished) {
- throw new IllegalStateException(ERR_UNFINISHED);
- }
- if ((hash_flags & type.hashId()) == 0) {
- throw new IllegalArgumentException(ERR_WRONGTYPE+type);
- }
- return new Digest(Bindings.rhash_print(context_ptr, type.hashId()), type);
- }
-
- /**
- * Returns digest for processed data.
- * If more than one hashing type was passed to the
- * RHash
constructor, then the least
- * hash type (in the order induced by
- * {@link Enum#compareTo(Enum) compareTo()}) is used.
- *
- * @return Digest
for processed data
- * @throws IllegalStateException
- * if this RHash
is not finished
- */
- public Digest getDigest() {
- return getDigest(deftype);
- }
-
- /**
- * Returns magnet link that includes specified filename
- * and hashes for given algorithms. Only hashes that were
- * computed by this RHash
are included.
- *
- * @param filename file name to include in magnet, may be null
- * @return magnet link
- * @throws IllegalStateException
- * if this RHash
is not finished
- */
- public String getMagnet(String filename, HashType... types) {
- if (!finished) {
- throw new IllegalStateException(ERR_UNFINISHED);
- }
- int flags = 0;
- for (HashType t : types) {
- flags |= t.hashId();
- }
- return Bindings.rhash_print_magnet(context_ptr, filename, flags);
- }
-
- /**
- * Returns magnet link for given filename.
- * Magnet includes all hashes that were computed
- * by this RHash
.
- *
- * @param filename file name to include in magnet, may be null
- * @return magnet link
- * @throws IllegalStateException
- * if this RHash
is not finished
- */
- public String getMagnet(String filename) {
- if (!finished) {
- throw new IllegalStateException(ERR_UNFINISHED);
- }
- return Bindings.rhash_print_magnet(context_ptr, filename, hash_flags);
- }
-
- /**
- * Called by garbage collector to free native resources.
- */
- @Override
- protected void finalize() {
- Bindings.rhash_free(context_ptr);
- }
-}
+/*
+ * This file is a part of Java Bindings for Librhash
+ * Copyright (c) 2011-2012, Sergey Basalaev
+ * Librhash is (c) 2011-2012, Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This library 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. Use it at your own risk!
+ */
+
+package org.sf.rhash;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Set;
+
+/**
+ * Incremental hasher.
+ * This class allows you to do incremental hashing for set
+ * of hashing algorithms.
+ *
+ * To do hashing RHash
instance is first created
+ * and then filled with message chunks using update()
+ * methods. Finally, finish()
should be called to end
+ * all calculations and generate digests, which then can be obtained
+ * with getDigest()
method. Note, that trying to update
+ * finished RHash
has no effect other than throwing
+ * IllegalStateException
though you can reuse this class
+ * by calling reset()
method, returning it to the state
+ * which was immediately after creating.
+ *
+ * To quickly produce message digest for a single message/file
+ * and a single algorithm you may use convenience methods
+ * RHash.computeHash()
.
+ *
+ * This class is thread safe.
+ *
+ */
+public final class RHash {
+
+ /* == EXCEPTION MESSAGES == */
+
+ static private final String ERR_FINISHED = "RHash is finished, data update is not possible";
+ static private final String ERR_NOHASH = "No HashTypes specified";
+ static private final String ERR_UNFINISHED = "RHash should be finished before generating Digest";
+ static private final String ERR_WRONGTYPE = "RHash was not created to generate Digest for ";
+
+ /**
+ * Computes hash of given range in data.
+ * This method calculates message digest for byte subsequence
+ * in array data
starting from data[ofs]
+ * and ending at data[ofs+len-1]
.
+ *
+ * @param type type of hash algorithm
+ * @param data the bytes to process
+ * @param ofs index of the first byte in array to process
+ * @param len count of bytes to process
+ * @return message digest for specified subarray
+ * @throws NullPointerException
+ * if either type
or data
+ * is null
+ * @throws IndexOutOfBoundsException
+ * if ofs < 0
, len < 0
or
+ * ofs+len > data.length
+ */
+ static public Digest computeHash(HashType type, byte[] data, int ofs, int len) {
+ if (type == null || data == null) {
+ throw new NullPointerException();
+ }
+ if (ofs < 0 || len < 0 || ofs+len > data.length) {
+ throw new IndexOutOfBoundsException();
+ }
+ return new Digest(Bindings.rhash_msg(type.hashId(), data, ofs, len), type);
+ }
+
+ /**
+ * Computes hash of given data.
+ *
+ * @param type type of hash algorithm
+ * @param data the bytes to process
+ * @return message digest for specified array
+ * @throws NullPointerException
+ * if either type
or data
+ * is null
+ */
+ static public Digest computeHash(HashType type, byte[] data) {
+ return computeHash(type, data, 0, data.length);
+ }
+
+ /**
+ * Computes hash of given string.
+ * String is encoded into a sequence of bytes
+ * using the specified charset.
+ *
+ * @param type type of hash algorithm
+ * @param str the string to process
+ * @param encoding encoding to use
+ * @return message digest for specified string
+ * @throws NullPointerException if any of arguments is null
+ * @throws UnsupportedEncodingException if specified encoding is not supported
+ */
+ static public Digest computeHash(HashType type, String str, String encoding)
+ throws UnsupportedEncodingException {
+ if (type == null || str == null || encoding == null) {
+ throw new NullPointerException();
+ }
+ return computeHash(type, str.getBytes(encoding));
+ }
+
+ /**
+ * Computes hash of given string.
+ * String is encoded into a sequence of bytes using the
+ * default platform encoding.
+ *
+ * @param type type of hash algorithm
+ * @param str the string to process
+ * @return message digest for specified string
+ * @throws NullPointerException if any of arguments is null
+ */
+ static public Digest computeHash(HashType type, String str) {
+ if (type == null || str == null) throw new NullPointerException();
+ return computeHash(type, str.getBytes());
+ }
+
+ /**
+ * Computes hash of given string.
+ * @param type type of hash algorithm
+ * @param file the file to process
+ * @return data hash
+ * @throws NullPointerException if any of arguments is null
+ * @throws IOException
+ * if an I/O error occurs while hashing
+ */
+ static public Digest computeHash(HashType type, File file) throws IOException {
+ if (type == null || file == null) {
+ throw new NullPointerException();
+ }
+ RHash hasher = new RHash(type);
+ hasher.update(file).finish();
+ return hasher.getDigest();
+ }
+
+ /**
+ * Produces magnet link for specified file with given hashes.
+ *
+ * @param filename the file to generate magnet for
+ * @param types types of hashing algorithms
+ */
+ static public String getMagnetFor(String filename, HashType... types) throws IOException {
+ RHash hasher = new RHash(types);
+ hasher.update(new File(filename)).finish();
+ return hasher.getMagnet(filename);
+ }
+
+ /**
+ * Produces magnet link for specified file with given hashes.
+ *
+ * @param filename the file to generate magnet for
+ * @param types set of hashing types
+ */
+ static public String getMagnetFor(String filename, Set types) throws IOException {
+ RHash hasher = new RHash(types);
+ hasher.update(new File(filename)).finish();
+ return hasher.getMagnet(filename);
+ }
+
+ /** Indicates whether this RHash
is finished. */
+ private boolean finished = false;
+
+ /** Mask of hash_id values. */
+ private final int hash_flags;
+
+ /** Pointer to the native hash context. */
+ private final long context_ptr;
+
+ /** Default hash type used in getDigest()
. */
+ private final HashType deftype;
+
+ /**
+ * Creates new RHash
to compute
+ * message digests for given types.
+ * @param types types of hashing algorithms
+ * @throws NullPointerException
+ * if any of arguments is null
+ * @throws IllegalArgumentException
+ * if zero hash types specified
+ */
+ public RHash(HashType... types) {
+ if (types.length == 0) {
+ throw new IllegalArgumentException(ERR_NOHASH);
+ }
+ int flags = 0;
+ HashType def = types[0];
+ for (HashType t : types) {
+ flags |= t.hashId();
+ if (def.compareTo(t) > 0) def = t;
+ }
+ this.deftype = def;
+ this.hash_flags = flags;
+ this.context_ptr = Bindings.rhash_init(flags);
+ }
+
+ /**
+ * Creates new RHash
to compute
+ * message digests for given types.
+ * @param types set of hashing types
+ * @throws NullPointerException
+ * if argument is null
+ * @throws IllegalArgumentException
+ * if argument is empty set
+ */
+ public RHash(Set types) {
+ if (types.isEmpty()) {
+ throw new IllegalArgumentException(ERR_NOHASH);
+ }
+ int flags = 0;
+ HashType def = null;
+ for (HashType t : types) {
+ flags |= t.hashId();
+ if (def == null || def.compareTo(t) > 0) def = t;
+ }
+ this.deftype = def;
+ this.hash_flags = flags;
+ this.context_ptr = Bindings.rhash_init(flags);
+ }
+
+ /**
+ * Updates this RHash
with new data chunk.
+ * This method hashes bytes from data[ofs]
+ * through data[ofs+len-1]
.
+ *
+ * @param data data to be hashed
+ * @param ofs index of the first byte to hash
+ * @param len number of bytes to hash
+ * @return this object
+ * @throws NullPointerException
+ * if data
is null
+ * @throws IndexOutOfBoundsException
+ * if ofs < 0
, len < 0
or
+ * ofs+len > data.length
+ * @throws IllegalStateException
+ * if finish()
was called and there were no
+ * subsequent calls of reset()
+ */
+ public synchronized RHash update(byte[] data, int ofs, int len) {
+ if (finished) {
+ throw new IllegalStateException(ERR_FINISHED);
+ }
+ if (ofs < 0 || len < 0 || ofs+len > data.length) {
+ throw new IndexOutOfBoundsException();
+ }
+ Bindings.rhash_update(context_ptr, data, ofs, len);
+ return this;
+ }
+
+ /**
+ * Updates this RHash
with new data chunk.
+ * This method has the same effect as
+ * update(data, 0, data.length)
+ *
+ * @param data data to be hashed
+ * @return this object
+ * @throws NullPointerException
+ * if data
is null
+ * @throws IllegalStateException
+ * if finish()
was called and there were no
+ * subsequent calls of reset()
+ */
+ public RHash update(byte[] data) {
+ return update(data, 0, data.length);
+ }
+
+ /**
+ * Updates this RHash
with new data chunk.
+ * String is encoded into a sequence of bytes using the
+ * default platform encoding.
+ *
+ * @param str string to be hashed
+ * @return this object
+ * @throws NullPointerException
+ * if str
is null
+ * @throws IllegalStateException
+ * if finish()
was called and there were no
+ * subsequent calls of reset()
+ */
+ public RHash update(String str) {
+ return update(str.getBytes());
+ }
+
+ /**
+ * Updates this RHash
with data from given file.
+ *
+ * @param file file to be hashed
+ * @return this object
+ * @throws IOException if an I/O error occurs
+ * @throws NullPointerException
+ * if file
is null
+ * @throws IllegalStateException
+ * if finish()
was called and there were no
+ * subsequent calls of reset()
+ */
+ public synchronized RHash update(File file) throws IOException {
+ if (finished) {
+ throw new IllegalStateException(ERR_FINISHED);
+ }
+ InputStream in = new FileInputStream(file);
+ byte[] buf = new byte[8192]; //shouldn't we avoid magic numbers?
+ int len = in.read(buf);
+ while (len > 0) {
+ this.update(buf, 0, len);
+ len = in.read(buf);
+ }
+ in.close();
+ return this;
+ }
+
+ /**
+ * Finishes calculation of hash codes.
+ * Does nothing if RHash
is already finished.
+ */
+ public synchronized void finish() {
+ if (!finished) {
+ Bindings.rhash_final(context_ptr);
+ finished = true;
+ }
+ }
+
+ /**
+ * Resets this RHash
to initial state.
+ * The RHash
becomes available to process
+ * new data chunks. Note, that this method returns
+ * RHash
to the state after creating the
+ * object, NOT the state when hashing continues.
+ * Therefore, all previously calculated hashes are lost
+ * and process starts from the very beginning.
+ */
+ public synchronized void reset() {
+ Bindings.rhash_reset(context_ptr);
+ finished = false;
+ }
+
+ /**
+ * Tests whether this RHash
is finished or not.
+ * @return
+ * false
if this RHash
is ready to
+ * receive new data for hashing;
+ * true
if hash calculations are finished
+ */
+ public boolean isFinished() {
+ return finished;
+ }
+
+ /**
+ * Returns digest for given hash type.
+ *
+ * @param type hash type
+ * @return Digest
for processed data
+ * @throws NullPointerException
+ * if type
is null
+ * @throws IllegalStateException
+ * if this RHash
is not finished
+ * @throws IllegalArgumentException
+ * if this RHash
was not created to calculate
+ * hash for specified algorithm
+ */
+ public Digest getDigest(HashType type) {
+ if (type == null) {
+ throw new NullPointerException();
+ }
+ if (!finished) {
+ throw new IllegalStateException(ERR_UNFINISHED);
+ }
+ if ((hash_flags & type.hashId()) == 0) {
+ throw new IllegalArgumentException(ERR_WRONGTYPE+type);
+ }
+ return new Digest(Bindings.rhash_print(context_ptr, type.hashId()), type);
+ }
+
+ /**
+ * Returns digest for processed data.
+ * If more than one hashing type was passed to the
+ * RHash
constructor, then the least
+ * hash type (in the order induced by
+ * {@link Enum#compareTo(Enum) compareTo()}) is used.
+ *
+ * @return Digest
for processed data
+ * @throws IllegalStateException
+ * if this RHash
is not finished
+ */
+ public Digest getDigest() {
+ return getDigest(deftype);
+ }
+
+ /**
+ * Returns magnet link that includes specified filename
+ * and hashes for given algorithms. Only hashes that were
+ * computed by this RHash
are included.
+ *
+ * @param filename file name to include in magnet, may be null
+ * @return magnet link
+ * @throws IllegalStateException
+ * if this RHash
is not finished
+ */
+ public String getMagnet(String filename, HashType... types) {
+ if (!finished) {
+ throw new IllegalStateException(ERR_UNFINISHED);
+ }
+ int flags = 0;
+ for (HashType t : types) {
+ flags |= t.hashId();
+ }
+ return Bindings.rhash_print_magnet(context_ptr, filename, flags);
+ }
+
+ /**
+ * Returns magnet link for given filename.
+ * Magnet includes all hashes that were computed
+ * by this RHash
.
+ *
+ * @param filename file name to include in magnet, may be null
+ * @return magnet link
+ * @throws IllegalStateException
+ * if this RHash
is not finished
+ */
+ public String getMagnet(String filename) {
+ if (!finished) {
+ throw new IllegalStateException(ERR_UNFINISHED);
+ }
+ return Bindings.rhash_print_magnet(context_ptr, filename, hash_flags);
+ }
+
+ /**
+ * Called by garbage collector to free native resources.
+ */
+ @Override
+ protected void finalize() {
+ Bindings.rhash_free(context_ptr);
+ }
+}
diff --git a/bindings/java/src/org/sf/rhash/package-info.java b/bindings/java/src/org/sf/rhash/package-info.java
index 3b185b75..54b10d32 100644
--- a/bindings/java/src/org/sf/rhash/package-info.java
+++ b/bindings/java/src/org/sf/rhash/package-info.java
@@ -1,62 +1,62 @@
-/*
- * This file is a part of Java Bindings for Librhash
- * Copyright (c) 2011-2012, Sergey Basalaev
- * Librhash is (c) 2011-2012, Aleksey Kravchenko
- *
- * 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.
- *
- * This library 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. Use it at your own risk!
- */
-
-/**
- * Java bindings for librhash.
- * Librhash is a library for computing and verifying hash sums.
- * List of all supported hash functions can be found in
- * {@link org.sf.rhash.HashType} class description.
- *
- * In its simplest usage to calculate a hash for message or file
- * you just need to use one of RHash.computeHash()
- * methods:
- *
- * RHash.computeHash("Hello, world!");
- * RHash.computeHash(new byte[] { 0, 1, 2, 3});
- * RHash.computeHash(new File("SomeFile.txt"));
- * These methods return value of type Digest
which is
- * a message digest. To convert Digest
in human readable
- * format you might use one of methods
- * {@link org.sf.rhash.Digest#hex() hex()},
- * {@link org.sf.rhash.Digest#base32() base32()},
- * {@link org.sf.rhash.Digest#base64() base64()} or
- * {@link org.sf.rhash.Digest#raw() raw()}.
- *
- * Next, RHash
allows you to do incremental hashing,
- * processing data given in portions like it was one big byte sequence.
- * To do this you first need to create RHash
instance
- * with a set of needed hash algorithms and then to fill it using
- * update()
:
- *
- * RHash hasher = new RHash(HashType.MD5);
- * hasher.update("Foo").update(new File("Bar.zip")).finish();
- * Digest result = hasher.getDigest();
- * Method finish()
should be called before obtaining
- * digest to end all calculations and generate result.
- *
- * You can setup RHash
to calculate several digests
- * at once, passing corresponding HashType
s in
- * constructor. Specifically, you can calculate all of them creating
- * RHash
like
- *
- * new Rhash(EnumSet.allOf(HashType.class));
- * In this case to obtain digest for particular hash type use
- * {@link org.sf.rhash.RHash#getDigest(HashType) }
- * method.
- *
- */
-package org.sf.rhash;
+/*
+ * This file is a part of Java Bindings for Librhash
+ * Copyright (c) 2011-2012, Sergey Basalaev
+ * Librhash is (c) 2011-2012, Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This library 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. Use it at your own risk!
+ */
+
+/**
+ * Java bindings for librhash.
+ * Librhash is a library for computing and verifying hash sums.
+ * List of all supported hash functions can be found in
+ * {@link org.sf.rhash.HashType} class description.
+ *
+ * In its simplest usage to calculate a hash for message or file
+ * you just need to use one of RHash.computeHash()
+ * methods:
+ *
+ * RHash.computeHash("Hello, world!");
+ * RHash.computeHash(new byte[] { 0, 1, 2, 3});
+ * RHash.computeHash(new File("SomeFile.txt"));
+ * These methods return value of type Digest
which is
+ * a message digest. To convert Digest
in human readable
+ * format you might use one of methods
+ * {@link org.sf.rhash.Digest#hex() hex()},
+ * {@link org.sf.rhash.Digest#base32() base32()},
+ * {@link org.sf.rhash.Digest#base64() base64()} or
+ * {@link org.sf.rhash.Digest#raw() raw()}.
+ *
+ * Next, RHash
allows you to do incremental hashing,
+ * processing data given in portions like it was one big byte sequence.
+ * To do this you first need to create RHash
instance
+ * with a set of needed hash algorithms and then to fill it using
+ * update()
:
+ *
+ * RHash hasher = new RHash(HashType.MD5);
+ * hasher.update("Foo").update(new File("Bar.zip")).finish();
+ * Digest result = hasher.getDigest();
+ * Method finish()
should be called before obtaining
+ * digest to end all calculations and generate result.
+ *
+ * You can setup RHash
to calculate several digests
+ * at once, passing corresponding HashType
s in
+ * constructor. Specifically, you can calculate all of them creating
+ * RHash
like
+ *
+ * new Rhash(EnumSet.allOf(HashType.class));
+ * In this case to obtain digest for particular hash type use
+ * {@link org.sf.rhash.RHash#getDigest(HashType) }
+ * method.
+ *
+ */
+package org.sf.rhash;
diff --git a/bindings/java/test/RHashTest.java b/bindings/java/test/RHashTest.java
index 0ce74f1c..54a8cf1f 100644
--- a/bindings/java/test/RHashTest.java
+++ b/bindings/java/test/RHashTest.java
@@ -1,76 +1,76 @@
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.util.EnumSet;
-
-import org.sf.rhash.*;
-import static org.sf.rhash.HashType.*;
-
-import org.junit.Test;
-import junit.framework.JUnit4TestAdapter;
-import static junit.framework.TestCase.*;
-
-public class RHashTest {
-
- @Test
- public void testAllHashes() {
- RHash r = new RHash(EnumSet.allOf(HashType.class));
- r.update("a").finish();
-
- assertEquals("e8b7be43", r.getDigest(CRC32).toString());
- assertEquals("c1d04330", r.getDigest(CRC32C).toString());
- assertEquals("bde52cb31de33e46245e05fbdbd6fb24", r.getDigest(MD4).toString());
- assertEquals("0cc175b9c0f1b6a831c399e269772661", r.getDigest(MD5).toString());
- assertEquals("86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", r.getDigest(SHA1).toString());
- assertEquals("77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", r.getDigest(TIGER).toString());
- assertEquals("czquwh3iyxbf5l3bgyugzhassmxu647ip2ike4y", r.getDigest(TTH).toString());
- assertEquals(40, r.getDigest(BTIH).toString().length());
- assertEquals("bde52cb31de33e46245e05fbdbd6fb24", r.getDigest(ED2K).toString());
- assertEquals("q336in72uwt7zyk5dxolt2xk5i3xmz5y", r.getDigest(AICH).toString());
- assertEquals("8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a", r.getDigest(WHIRLPOOL).toString());
- assertEquals("0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", r.getDigest(RIPEMD160).toString());
- assertEquals("d42c539e367c66e9c88a801f6649349c21871b4344c6a573f849fdce62f314dd", r.getDigest(GOST94).toString());
- assertEquals("e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011", r.getDigest(GOST94_CRYPTOPRO).toString());
- assertEquals("4872bcbc4cd0f0a9dc7c2f7045e5b43b6c830db8", r.getDigest(HAS160).toString());
- assertEquals("ba31099b9cc84ec2a671e9313572378920a705b363b031a1cb4fc03e01ce8df3", r.getDigest(GOST12_256).toString());
- assertEquals("8b2a40ecab7b7496bc4cc0f773595452baf658849b495acc3ba017206810efb00420ccd73fb3297e0f7890941b84ac4a8bc27e3c95e1f97c094609e2136abb7e", r.getDigest(GOST12_512).toString());
- assertEquals("abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", r.getDigest(SHA224).toString());
- assertEquals("ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", r.getDigest(SHA256).toString());
- assertEquals("54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", r.getDigest(SHA384).toString());
- assertEquals("1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", r.getDigest(SHA512).toString());
- assertEquals("943aa9225a2cf154ec2e4dd81237720ba538ca8df2fd83c0b893c5d265f353a0", r.getDigest(EDONR256).toString());
- assertEquals("b59ec44f7beef8a04ceed38a973d77c65e22e9458d5f67b497948da34986c093b5efc5483fbee55f2f740fcad31f18d80db44bb6b8843e7fd599188e7c07233b", r.getDigest(EDONR512).toString());
- assertEquals("9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b", r.getDigest(SHA3_224).toString());
- assertEquals("80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b", r.getDigest(SHA3_256).toString());
- assertEquals("1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9", r.getDigest(SHA3_384).toString());
- assertEquals("697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a", r.getDigest(SHA3_512).toString());
- assertEquals("bf5ce540ae51bc50399f96746c5a15bd", r.getDigest(SNEFRU128).toString());
- assertEquals("45161589ac317be0ceba70db2573ddda6e668a31984b39bf65e4b664b584c63d", r.getDigest(SNEFRU256).toString());
-
- r.reset();
- r.finish();
- assertEquals("d41d8cd98f00b204e9800998ecf8427e", r.getDigest(MD5).toString()); // MD5 of ""
- }
-
- @Test
- public void testMagnet() {
- RHash r = new RHash(MD5, TTH);
- r.update("abc").finish();
- assertEquals("magnet:?xl=3&dn=file.txt&xt=urn:md5:900150983cd24fb0d6963f7d28e17f72&xt=urn:tree:tiger:asd4ujseh5m47pdyb46kbtsqtsgdklbhyxomuia", r.getMagnet("file.txt"));
- }
-
- @Test
- public void testUpdateFile() throws IOException {
- File f = new File("java_test_input_123.txt");
- PrintStream out = new PrintStream(f);
- out.println("\0\1\2");
- out.flush();
- out.close();
- assertEquals("e3869ec477661fad6b9fc25914bb2eee5455b483", RHash.computeHash(SHA1, f).toString());
- f.delete();
- }
-
- public static junit.framework.Test suite(){
- return new JUnit4TestAdapter(RHashTest.class);
- }
-}
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.EnumSet;
+
+import org.sf.rhash.*;
+import static org.sf.rhash.HashType.*;
+
+import org.junit.Test;
+import junit.framework.JUnit4TestAdapter;
+import static junit.framework.TestCase.*;
+
+public class RHashTest {
+
+ @Test
+ public void testAllHashes() {
+ RHash r = new RHash(EnumSet.allOf(HashType.class));
+ r.update("a").finish();
+
+ assertEquals("e8b7be43", r.getDigest(CRC32).toString());
+ assertEquals("c1d04330", r.getDigest(CRC32C).toString());
+ assertEquals("bde52cb31de33e46245e05fbdbd6fb24", r.getDigest(MD4).toString());
+ assertEquals("0cc175b9c0f1b6a831c399e269772661", r.getDigest(MD5).toString());
+ assertEquals("86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", r.getDigest(SHA1).toString());
+ assertEquals("77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", r.getDigest(TIGER).toString());
+ assertEquals("czquwh3iyxbf5l3bgyugzhassmxu647ip2ike4y", r.getDigest(TTH).toString());
+ assertEquals(40, r.getDigest(BTIH).toString().length());
+ assertEquals("bde52cb31de33e46245e05fbdbd6fb24", r.getDigest(ED2K).toString());
+ assertEquals("q336in72uwt7zyk5dxolt2xk5i3xmz5y", r.getDigest(AICH).toString());
+ assertEquals("8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a", r.getDigest(WHIRLPOOL).toString());
+ assertEquals("0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", r.getDigest(RIPEMD160).toString());
+ assertEquals("d42c539e367c66e9c88a801f6649349c21871b4344c6a573f849fdce62f314dd", r.getDigest(GOST94).toString());
+ assertEquals("e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011", r.getDigest(GOST94_CRYPTOPRO).toString());
+ assertEquals("4872bcbc4cd0f0a9dc7c2f7045e5b43b6c830db8", r.getDigest(HAS160).toString());
+ assertEquals("ba31099b9cc84ec2a671e9313572378920a705b363b031a1cb4fc03e01ce8df3", r.getDigest(GOST12_256).toString());
+ assertEquals("8b2a40ecab7b7496bc4cc0f773595452baf658849b495acc3ba017206810efb00420ccd73fb3297e0f7890941b84ac4a8bc27e3c95e1f97c094609e2136abb7e", r.getDigest(GOST12_512).toString());
+ assertEquals("abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", r.getDigest(SHA224).toString());
+ assertEquals("ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", r.getDigest(SHA256).toString());
+ assertEquals("54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", r.getDigest(SHA384).toString());
+ assertEquals("1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", r.getDigest(SHA512).toString());
+ assertEquals("943aa9225a2cf154ec2e4dd81237720ba538ca8df2fd83c0b893c5d265f353a0", r.getDigest(EDONR256).toString());
+ assertEquals("b59ec44f7beef8a04ceed38a973d77c65e22e9458d5f67b497948da34986c093b5efc5483fbee55f2f740fcad31f18d80db44bb6b8843e7fd599188e7c07233b", r.getDigest(EDONR512).toString());
+ assertEquals("9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b", r.getDigest(SHA3_224).toString());
+ assertEquals("80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b", r.getDigest(SHA3_256).toString());
+ assertEquals("1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9", r.getDigest(SHA3_384).toString());
+ assertEquals("697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a", r.getDigest(SHA3_512).toString());
+ assertEquals("bf5ce540ae51bc50399f96746c5a15bd", r.getDigest(SNEFRU128).toString());
+ assertEquals("45161589ac317be0ceba70db2573ddda6e668a31984b39bf65e4b664b584c63d", r.getDigest(SNEFRU256).toString());
+
+ r.reset();
+ r.finish();
+ assertEquals("d41d8cd98f00b204e9800998ecf8427e", r.getDigest(MD5).toString()); // MD5 of ""
+ }
+
+ @Test
+ public void testMagnet() {
+ RHash r = new RHash(MD5, TTH);
+ r.update("abc").finish();
+ assertEquals("magnet:?xl=3&dn=file.txt&xt=urn:md5:900150983cd24fb0d6963f7d28e17f72&xt=urn:tree:tiger:asd4ujseh5m47pdyb46kbtsqtsgdklbhyxomuia", r.getMagnet("file.txt"));
+ }
+
+ @Test
+ public void testUpdateFile() throws IOException {
+ File f = new File("java_test_input_123.txt");
+ PrintStream out = new PrintStream(f);
+ out.println("\0\1\2");
+ out.flush();
+ out.close();
+ assertEquals("e3869ec477661fad6b9fc25914bb2eee5455b483", RHash.computeHash(SHA1, f).toString());
+ f.delete();
+ }
+
+ public static junit.framework.Test suite(){
+ return new JUnit4TestAdapter(RHashTest.class);
+ }
+}
diff --git a/bindings/mono/.gitignore b/bindings/mono/.gitignore
index 6aeb83c4..efaec95e 100644
--- a/bindings/mono/.gitignore
+++ b/bindings/mono/.gitignore
@@ -1,8 +1,8 @@
-bin
-RHash.dll
-RHash.dll.mdb
-RHash.pidb
-RHash.tree
-RHash.userprefs
-RHash.zip
-html
+bin
+RHash.dll
+RHash.dll.mdb
+RHash.pidb
+RHash.tree
+RHash.userprefs
+RHash.zip
+html
diff --git a/bindings/mono/AssemblyInfo.cs b/bindings/mono/AssemblyInfo.cs
index fd3d57c8..6c0413f1 100644
--- a/bindings/mono/AssemblyInfo.cs
+++ b/bindings/mono/AssemblyInfo.cs
@@ -1,44 +1,44 @@
-/*
- * This file is a part of Mono Bindings for Librhash
- * Copyright (c) 2011-2012, Sergey Basalaev
- * Librhash is (c) 2011-2012, Aleksey Kravchenko
- *
- * 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.
- *
- * This library 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. Use it at your own risk!
- */
-
-using System.Reflection;
-using System.Runtime.CompilerServices;
-
-// Information about this assembly is defined by the following attributes.
-// Change them to the values specific to your project.
-
-[assembly: AssemblyTitle("RHash")]
-[assembly: AssemblyDescription(".NET/Mono bindings for librhash")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("")]
-[assembly: AssemblyCopyright("(c) 2011, Sergey Basalaev")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
-// The form "{Major}.{Minor}.*" will automatically update the build and revision,
-// and "{Major}.{Minor}.{Build}.*" will update just the revision.
-
-[assembly: AssemblyVersion("1.0.1.1")]
-
-// The following attributes are used to specify the signing key for the assembly,
-// if desired. See the Mono documentation for more information about signing.
-
-[assembly: AssemblyDelaySign(false)]
-//[assembly: AssemblyKeyFile("RHash.snk")]
-
+/*
+ * This file is a part of Mono Bindings for Librhash
+ * Copyright (c) 2011-2012, Sergey Basalaev
+ * Librhash is (c) 2011-2012, Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This library 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. Use it at your own risk!
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("RHash")]
+[assembly: AssemblyDescription(".NET/Mono bindings for librhash")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("(c) 2011, Sergey Basalaev")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.1.1")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("RHash.snk")]
+
diff --git a/bindings/mono/Bindings.cs b/bindings/mono/Bindings.cs
index 6aeed9be..6ab6bac0 100644
--- a/bindings/mono/Bindings.cs
+++ b/bindings/mono/Bindings.cs
@@ -1,67 +1,67 @@
-/*
- * This file is a part of Mono Bindings for Librhash
- * Copyright (c) 2011-2012, Sergey Basalaev
- * Librhash is (c) 2011-2012, Aleksey Kravchenko
- *
- * 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.
- *
- * This library 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. Use it at your own risk!
- */
-
-using System;
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace RHash {
- /* Pointer to native structure. */
- sealed class Bindings {
-
- private const string librhash = "librhash.dll";
-
- private Bindings() { }
-
- static Bindings() {
- rhash_library_init();
- }
-
- [DllImport (librhash)]
- public static extern
- void rhash_library_init();
-
- [DllImport (librhash)]
- public static extern
- IntPtr rhash_init(uint hash_ids);
-
- [DllImport (librhash)]
- public static extern
- void rhash_update(IntPtr ctx, byte[] message, int length);
-
- //may crash, rhash_final actually have 2 arguments
- [DllImport (librhash)]
- public static extern
- void rhash_final(IntPtr ctx, IntPtr unused);
-
- [DllImport (librhash)]
- public static extern
- void rhash_reset(IntPtr ctx);
-
- [DllImport (librhash)]
- public static extern
- void rhash_free(IntPtr ctx);
-
- [DllImport (librhash, CharSet=CharSet.Ansi)]
- public static extern
- void rhash_print(StringBuilder output, IntPtr ctx, uint hash_id, int flags);
-
- [DllImport (librhash)]
- public static extern
- int rhash_print_magnet(StringBuilder output, String filepath, IntPtr ctx, uint hash_mask, int flags);
- }
-}
+/*
+ * This file is a part of Mono Bindings for Librhash
+ * Copyright (c) 2011-2012, Sergey Basalaev
+ * Librhash is (c) 2011-2012, Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This library 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. Use it at your own risk!
+ */
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace RHash {
+ /* Pointer to native structure. */
+ sealed class Bindings {
+
+ private const string librhash = "librhash.dll";
+
+ private Bindings() { }
+
+ static Bindings() {
+ rhash_library_init();
+ }
+
+ [DllImport (librhash)]
+ public static extern
+ void rhash_library_init();
+
+ [DllImport (librhash)]
+ public static extern
+ IntPtr rhash_init(uint hash_ids);
+
+ [DllImport (librhash)]
+ public static extern
+ void rhash_update(IntPtr ctx, byte[] message, int length);
+
+ //may crash, rhash_final actually have 2 arguments
+ [DllImport (librhash)]
+ public static extern
+ void rhash_final(IntPtr ctx, IntPtr unused);
+
+ [DllImport (librhash)]
+ public static extern
+ void rhash_reset(IntPtr ctx);
+
+ [DllImport (librhash)]
+ public static extern
+ void rhash_free(IntPtr ctx);
+
+ [DllImport (librhash, CharSet=CharSet.Ansi)]
+ public static extern
+ void rhash_print(StringBuilder output, IntPtr ctx, uint hash_id, int flags);
+
+ [DllImport (librhash)]
+ public static extern
+ int rhash_print_magnet(StringBuilder output, String filepath, IntPtr ctx, uint hash_mask, int flags);
+ }
+}
diff --git a/bindings/mono/HashType.cs b/bindings/mono/HashType.cs
index d18e712b..9a512975 100644
--- a/bindings/mono/HashType.cs
+++ b/bindings/mono/HashType.cs
@@ -1,86 +1,86 @@
-/*
- * This file is a part of Java Bindings for Librhash
- * Copyright (c) 2011-2012, 2014, Sergey Basalaev
- * Librhash is (c) 2011-2012, Aleksey Kravchenko
- *
- * 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.
- *
- * This library 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. Use it at your own risk!
- */
-
-using System;
-
-namespace RHash {
-
- /*
- * Type of hashing algorithm.
- * Supported algorithms are MD4, MD5, SHA1/SHA2, Tiger,
- * DC++ TTH, BitTorrent BTIH, AICH, EDonkey 2000 hash, GOST R 34.11-94,
- * RIPEMD-160, HAS-160, EDON-R 256/512, Whirlpool and Snefru-128/256.
- */
- public enum HashType : uint {
- /* CRC32 checksum. */
- CRC32 = 1,
- /* MD4 hash. */
- MD4 = 1 << 1,
- /* MD5 hash. */
- MD5 = 1 << 2,
- /* SHA-1 hash. */
- SHA1 = 1 << 3,
- /* Tiger hash. */
- TIGER = 1 << 4,
- /* Tiger tree hash */
- TTH = 1 << 5,
- /* BitTorrent info hash. */
- BTIH = 1 << 6,
- /* EDonkey 2000 hash. */
- ED2K = 1 << 7,
- /* eMule AICH. */
- AICH = 1 << 8,
- /* Whirlpool hash. */
- WHIRLPOOL = 1 << 9,
- /* RIPEMD-160 hash. */
- RIPEMD160 = 1 << 10,
- /* GOST R 34.11-94. */
- GOST94 = 1 << 11,
- GOST94_CRYPTOPRO = 1 << 12,
- /* HAS-160 hash. */
- HAS160 = 1 << 13,
- /* GOST R 34.11-2012. */
- GOST12_256 = 1 << 14,
- GOST12_512 = 1 << 15,
- /* SHA-224 hash. */
- SHA224 = 1 << 16,
- /* SHA-256 hash. */
- SHA256 = 1 << 17,
- /* SHA-384 hash. */
- SHA384 = 1 << 18,
- /* SHA-512 hash. */
- SHA512 = 1 << 19,
- /* EDON-R 256. */
- EDONR256 = 1 << 20,
- /* EDON-R 512. */
- EDONR512 = 1 << 21,
- /** SHA3-224 hash. */
- SHA3_224 = 1 << 22,
- /** SHA3-256 hash. */
- SHA3_256 = 1 << 23,
- /** SHA3-384 hash. */
- SHA3_384 = 1 << 24,
- /** SHA3-512 hash. */
- SHA3_512 = 1 << 25,
- /* CRC32C checksum. */
- CRC32C = 1 << 26,
- /* Snefru-128 hash. */
- SNEFRU128 = 1 << 27,
- /* Snefru-256 hash. */
- SNEFRU256 = 1 << 28
- }
-}
+/*
+ * This file is a part of Java Bindings for Librhash
+ * Copyright (c) 2011-2012, 2014, Sergey Basalaev
+ * Librhash is (c) 2011-2012, Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This library 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. Use it at your own risk!
+ */
+
+using System;
+
+namespace RHash {
+
+ /*
+ * Type of hashing algorithm.
+ * Supported algorithms are MD4, MD5, SHA1/SHA2, Tiger,
+ * DC++ TTH, BitTorrent BTIH, AICH, EDonkey 2000 hash, GOST R 34.11-94,
+ * RIPEMD-160, HAS-160, EDON-R 256/512, Whirlpool and Snefru-128/256.
+ */
+ public enum HashType : uint {
+ /* CRC32 checksum. */
+ CRC32 = 1,
+ /* MD4 hash. */
+ MD4 = 1 << 1,
+ /* MD5 hash. */
+ MD5 = 1 << 2,
+ /* SHA-1 hash. */
+ SHA1 = 1 << 3,
+ /* Tiger hash. */
+ TIGER = 1 << 4,
+ /* Tiger tree hash */
+ TTH = 1 << 5,
+ /* BitTorrent info hash. */
+ BTIH = 1 << 6,
+ /* EDonkey 2000 hash. */
+ ED2K = 1 << 7,
+ /* eMule AICH. */
+ AICH = 1 << 8,
+ /* Whirlpool hash. */
+ WHIRLPOOL = 1 << 9,
+ /* RIPEMD-160 hash. */
+ RIPEMD160 = 1 << 10,
+ /* GOST R 34.11-94. */
+ GOST94 = 1 << 11,
+ GOST94_CRYPTOPRO = 1 << 12,
+ /* HAS-160 hash. */
+ HAS160 = 1 << 13,
+ /* GOST R 34.11-2012. */
+ GOST12_256 = 1 << 14,
+ GOST12_512 = 1 << 15,
+ /* SHA-224 hash. */
+ SHA224 = 1 << 16,
+ /* SHA-256 hash. */
+ SHA256 = 1 << 17,
+ /* SHA-384 hash. */
+ SHA384 = 1 << 18,
+ /* SHA-512 hash. */
+ SHA512 = 1 << 19,
+ /* EDON-R 256. */
+ EDONR256 = 1 << 20,
+ /* EDON-R 512. */
+ EDONR512 = 1 << 21,
+ /** SHA3-224 hash. */
+ SHA3_224 = 1 << 22,
+ /** SHA3-256 hash. */
+ SHA3_256 = 1 << 23,
+ /** SHA3-384 hash. */
+ SHA3_384 = 1 << 24,
+ /** SHA3-512 hash. */
+ SHA3_512 = 1 << 25,
+ /* CRC32C checksum. */
+ CRC32C = 1 << 26,
+ /* Snefru-128 hash. */
+ SNEFRU128 = 1 << 27,
+ /* Snefru-256 hash. */
+ SNEFRU256 = 1 << 28
+ }
+}
diff --git a/bindings/mono/Hasher.cs b/bindings/mono/Hasher.cs
index 484915dd..ac5f8772 100644
--- a/bindings/mono/Hasher.cs
+++ b/bindings/mono/Hasher.cs
@@ -1,171 +1,171 @@
-/*
- * This file is a part of Java Bindings for Librhash
- * Copyright (c) 2011-2012, Sergey Basalaev
- * Librhash is (c) 2011-2012, Aleksey Kravchenko
- *
- * 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.
- *
- * This library 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. Use it at your own risk!
- */
-
-using System;
-using System.IO;
-using System.Text;
-
-namespace RHash {
-
- public sealed class Hasher {
-
- private const int DEFAULT = 0x0;
- /* output as binary message digest */
- private const int RAW = 0x1;
- /* print as a hexadecimal string */
- private const int HEX = 0x2;
- /* print as a base32-encoded string */
- private const int BASE32 = 0x3;
- /* print as a base64-encoded string */
- private const int BASE64 = 0x4;
- /* Print as an uppercase string. */
- private const int UPPERCASE = 0x8;
- /* Reverse hash bytes. */
- private const int REVERSE = 0x10;
- /* Print file size. */
- private const int FILESIZE = 0x40;
-
- private uint hash_ids;
- /* Pointer to the native structure. */
- private IntPtr ptr;
-
- public Hasher (HashType hashtype) {
- this.hash_ids = (uint)hashtype;
- this.ptr = Bindings.rhash_init(hash_ids);
- }
-
- public Hasher (uint hashmask) {
- this.hash_ids = hashmask;
- this.ptr = Bindings.rhash_init(hash_ids);
- if (ptr == IntPtr.Zero) throw new ArgumentException("Invalid mask of hashes", "hashmask");
- }
-
- ~Hasher() {
- if (ptr != IntPtr.Zero) {
- Bindings.rhash_free(ptr);
- ptr = IntPtr.Zero;
- }
- }
-
- public Hasher Update(byte[] buf) {
- Bindings.rhash_update(ptr, buf, buf.Length);
- return this;
- }
-
- public Hasher Update(byte[] buf, int len) {
- if (len < 0 || len >= buf.Length) {
- throw new IndexOutOfRangeException();
- }
- Bindings.rhash_update(ptr, buf, len);
- return this;
- }
-
- public Hasher UpdateFile(string filename) {
- Stream file = new FileStream(filename, FileMode.Open);
- byte[] buf = new byte[8192];
- int len = file.Read(buf, 0, 8192);
- while (len > 0) {
- Bindings.rhash_update(ptr, buf, len);
- len = file.Read(buf, 0, 8192);
- }
- file.Close();
- return this;
- }
-
- public void Finish() {
- Bindings.rhash_final(ptr, IntPtr.Zero);
- }
-
- public void Reset() {
- Bindings.rhash_reset(ptr);
- }
-
- public override string ToString() {
- StringBuilder sb = new StringBuilder(130);
- Bindings.rhash_print(sb, ptr, 0, 0);
- return sb.ToString();
- }
-
- public string ToString(HashType type) {
- if ((hash_ids & (uint)type) == 0) {
- throw new ArgumentException("This hasher does not support hash type "+type, "type");
- }
- StringBuilder sb = new StringBuilder(130);
- Bindings.rhash_print(sb, ptr, (uint)type, 0);
- return sb.ToString();
- }
-
- public string ToHex(HashType type) {
- if ((hash_ids & (uint)type) == 0) {
- throw new ArgumentException("This hasher does not support hash type "+type, "type");
- }
- StringBuilder sb = new StringBuilder(130);
- Bindings.rhash_print(sb, ptr, (uint)type, HEX);
- return sb.ToString();
- }
-
- public string ToBase32(HashType type) {
- if ((hash_ids & (uint)type) == 0) {
- throw new ArgumentException("This hasher does not support hash type "+type, "type");
- }
- StringBuilder sb = new StringBuilder(130);
- Bindings.rhash_print(sb, ptr, (uint)type, BASE32);
- return sb.ToString();
- }
-
- public string ToBase64(HashType type) {
- if ((hash_ids & (uint)type) == 0) {
- throw new ArgumentException("This hasher does not support hash type "+type, "type");
- }
- StringBuilder sb = new StringBuilder(130);
- Bindings.rhash_print(sb, ptr, (uint)type, BASE64);
- return sb.ToString();
- }
-
- public string ToRaw(HashType type) {
- if ((hash_ids & (uint)type) == 0) {
- throw new ArgumentException("This hasher does not support hash type "+type, "type");
- }
- StringBuilder sb = new StringBuilder(130);
- Bindings.rhash_print(sb, ptr, (uint)type, RAW);
- return sb.ToString();
- }
-
- public string GetMagnet(string filepath) {
- return GetMagnet(filepath, hash_ids);
- }
-
- public string GetMagnet(string filepath, uint hashmask) {
- int len = Bindings.rhash_print_magnet(null, filepath, ptr, hashmask, FILESIZE);
- StringBuilder sb = new StringBuilder(len);
- Bindings.rhash_print_magnet(sb, filepath, ptr, hashmask, FILESIZE);
- return sb.ToString();
- }
-
- public static string GetHashForMsg(byte[] buf, HashType type) {
- return new Hasher(type).Update(buf).ToString(type);
- }
-
- public static string GetHashForFile(string filename, HashType type) {
- return new Hasher(type).UpdateFile(filename).ToString(type);
- }
-
- public static string GetMagnetFor(string filepath, uint hashmask) {
- return new Hasher(hashmask).UpdateFile(filepath).GetMagnet(filepath);
- }
- }
-}
+/*
+ * This file is a part of Java Bindings for Librhash
+ * Copyright (c) 2011-2012, Sergey Basalaev
+ * Librhash is (c) 2011-2012, Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This library 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. Use it at your own risk!
+ */
+
+using System;
+using System.IO;
+using System.Text;
+
+namespace RHash {
+
+ public sealed class Hasher {
+
+ private const int DEFAULT = 0x0;
+ /* output as binary message digest */
+ private const int RAW = 0x1;
+ /* print as a hexadecimal string */
+ private const int HEX = 0x2;
+ /* print as a base32-encoded string */
+ private const int BASE32 = 0x3;
+ /* print as a base64-encoded string */
+ private const int BASE64 = 0x4;
+ /* Print as an uppercase string. */
+ private const int UPPERCASE = 0x8;
+ /* Reverse hash bytes. */
+ private const int REVERSE = 0x10;
+ /* Print file size. */
+ private const int FILESIZE = 0x40;
+
+ private uint hash_ids;
+ /* Pointer to the native structure. */
+ private IntPtr ptr;
+
+ public Hasher (HashType hashtype) {
+ this.hash_ids = (uint)hashtype;
+ this.ptr = Bindings.rhash_init(hash_ids);
+ }
+
+ public Hasher (uint hashmask) {
+ this.hash_ids = hashmask;
+ this.ptr = Bindings.rhash_init(hash_ids);
+ if (ptr == IntPtr.Zero) throw new ArgumentException("Invalid mask of hashes", "hashmask");
+ }
+
+ ~Hasher() {
+ if (ptr != IntPtr.Zero) {
+ Bindings.rhash_free(ptr);
+ ptr = IntPtr.Zero;
+ }
+ }
+
+ public Hasher Update(byte[] buf) {
+ Bindings.rhash_update(ptr, buf, buf.Length);
+ return this;
+ }
+
+ public Hasher Update(byte[] buf, int len) {
+ if (len < 0 || len >= buf.Length) {
+ throw new IndexOutOfRangeException();
+ }
+ Bindings.rhash_update(ptr, buf, len);
+ return this;
+ }
+
+ public Hasher UpdateFile(string filename) {
+ Stream file = new FileStream(filename, FileMode.Open);
+ byte[] buf = new byte[8192];
+ int len = file.Read(buf, 0, 8192);
+ while (len > 0) {
+ Bindings.rhash_update(ptr, buf, len);
+ len = file.Read(buf, 0, 8192);
+ }
+ file.Close();
+ return this;
+ }
+
+ public void Finish() {
+ Bindings.rhash_final(ptr, IntPtr.Zero);
+ }
+
+ public void Reset() {
+ Bindings.rhash_reset(ptr);
+ }
+
+ public override string ToString() {
+ StringBuilder sb = new StringBuilder(130);
+ Bindings.rhash_print(sb, ptr, 0, 0);
+ return sb.ToString();
+ }
+
+ public string ToString(HashType type) {
+ if ((hash_ids & (uint)type) == 0) {
+ throw new ArgumentException("This hasher does not support hash type "+type, "type");
+ }
+ StringBuilder sb = new StringBuilder(130);
+ Bindings.rhash_print(sb, ptr, (uint)type, 0);
+ return sb.ToString();
+ }
+
+ public string ToHex(HashType type) {
+ if ((hash_ids & (uint)type) == 0) {
+ throw new ArgumentException("This hasher does not support hash type "+type, "type");
+ }
+ StringBuilder sb = new StringBuilder(130);
+ Bindings.rhash_print(sb, ptr, (uint)type, HEX);
+ return sb.ToString();
+ }
+
+ public string ToBase32(HashType type) {
+ if ((hash_ids & (uint)type) == 0) {
+ throw new ArgumentException("This hasher does not support hash type "+type, "type");
+ }
+ StringBuilder sb = new StringBuilder(130);
+ Bindings.rhash_print(sb, ptr, (uint)type, BASE32);
+ return sb.ToString();
+ }
+
+ public string ToBase64(HashType type) {
+ if ((hash_ids & (uint)type) == 0) {
+ throw new ArgumentException("This hasher does not support hash type "+type, "type");
+ }
+ StringBuilder sb = new StringBuilder(130);
+ Bindings.rhash_print(sb, ptr, (uint)type, BASE64);
+ return sb.ToString();
+ }
+
+ public string ToRaw(HashType type) {
+ if ((hash_ids & (uint)type) == 0) {
+ throw new ArgumentException("This hasher does not support hash type "+type, "type");
+ }
+ StringBuilder sb = new StringBuilder(130);
+ Bindings.rhash_print(sb, ptr, (uint)type, RAW);
+ return sb.ToString();
+ }
+
+ public string GetMagnet(string filepath) {
+ return GetMagnet(filepath, hash_ids);
+ }
+
+ public string GetMagnet(string filepath, uint hashmask) {
+ int len = Bindings.rhash_print_magnet(null, filepath, ptr, hashmask, FILESIZE);
+ StringBuilder sb = new StringBuilder(len);
+ Bindings.rhash_print_magnet(sb, filepath, ptr, hashmask, FILESIZE);
+ return sb.ToString();
+ }
+
+ public static string GetHashForMsg(byte[] buf, HashType type) {
+ return new Hasher(type).Update(buf).ToString(type);
+ }
+
+ public static string GetHashForFile(string filename, HashType type) {
+ return new Hasher(type).UpdateFile(filename).ToString(type);
+ }
+
+ public static string GetMagnetFor(string filepath, uint hashmask) {
+ return new Hasher(hashmask).UpdateFile(filepath).GetMagnet(filepath);
+ }
+ }
+}
diff --git a/bindings/mono/Makefile b/bindings/mono/Makefile
index 464c29bd..cb14753d 100644
--- a/bindings/mono/Makefile
+++ b/bindings/mono/Makefile
@@ -1,49 +1,49 @@
-#!/usr/bin/make -f
-
-# This file is a part of Mono Bindings for Librhash
-# Copyright (c) 2011-2012, Sergey Basalaev
-# Librhash is (c) 2011-2012, Aleksey Kravchenko
-#
-# 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.
-#
-# This library 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. Use it at your own risk!
-
-CS?=mcs
-MDOC?=mdoc
-SOURCES=AssemblyInfo.cs Bindings.cs Hasher.cs HashType.cs
-
-all: assembly assemble-doc html
-
-assembly: RHash.dll RHash.dll.mdb
-
-RHash.dll RHash.dll.mdb: $(SOURCES)
- $(CS) -target:library -out:RHash.dll -debug -keyfile:RHash.snk $(SOURCES)
-
-update-doc: RHash.dll
- $(MDOC) update RHash.dll -o doc
-
-assemble-doc: RHash.tree RHash.zip
-
-RHash.tree RHash.zip:
- $(MDOC) assemble -o RHash doc
-
-html:
- $(MDOC) export-html -o html doc
-
-test: RHash.dll
- +$(MAKE) -C test
-
-clean:
- rm -f RHash.dll RHash.dll.mdb
- rm -f RHash.tree RHash.zip
- rm -rf html
- +$(MAKE) -C test clean
-
-.PHONY : clean html test
+#!/usr/bin/make -f
+
+# This file is a part of Mono Bindings for Librhash
+# Copyright (c) 2011-2012, Sergey Basalaev
+# Librhash is (c) 2011-2012, Aleksey Kravchenko
+#
+# 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.
+#
+# This library 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. Use it at your own risk!
+
+CS?=mcs
+MDOC?=mdoc
+SOURCES=AssemblyInfo.cs Bindings.cs Hasher.cs HashType.cs
+
+all: assembly assemble-doc html
+
+assembly: RHash.dll RHash.dll.mdb
+
+RHash.dll RHash.dll.mdb: $(SOURCES)
+ $(CS) -target:library -out:RHash.dll -debug -keyfile:RHash.snk $(SOURCES)
+
+update-doc: RHash.dll
+ $(MDOC) update RHash.dll -o doc
+
+assemble-doc: RHash.tree RHash.zip
+
+RHash.tree RHash.zip:
+ $(MDOC) assemble -o RHash doc
+
+html:
+ $(MDOC) export-html -o html doc
+
+test: RHash.dll
+ +$(MAKE) -C test
+
+clean:
+ rm -f RHash.dll RHash.dll.mdb
+ rm -f RHash.tree RHash.zip
+ rm -rf html
+ +$(MAKE) -C test clean
+
+.PHONY : clean html test
diff --git a/bindings/mono/RHash.csproj b/bindings/mono/RHash.csproj
index d61a203b..0e5fdb78 100644
--- a/bindings/mono/RHash.csproj
+++ b/bindings/mono/RHash.csproj
@@ -1,44 +1,44 @@
-
-
-
- Debug
- AnyCPU
- 10.0.0
- 2.0
- {2EC1635A-308E-46E4-B016-017C2AF3CDD9}
- Library
- RHash
- RHash
- v4.0
- .NET/Mono bindings for librhash
- 1.0
-
-
- true
- full
- false
- bin\Debug
- DEBUG
- prompt
- 4
- false
-
-
- none
- false
- bin\Release
- prompt
- 4
- false
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ Debug
+ AnyCPU
+ 10.0.0
+ 2.0
+ {2EC1635A-308E-46E4-B016-017C2AF3CDD9}
+ Library
+ RHash
+ RHash
+ v4.0
+ .NET/Mono bindings for librhash
+ 1.0
+
+
+ true
+ full
+ false
+ bin\Debug
+ DEBUG
+ prompt
+ 4
+ false
+
+
+ none
+ false
+ bin\Release
+ prompt
+ 4
+ false
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/bindings/mono/RHash.dll.config b/bindings/mono/RHash.dll.config
index 9e2967e2..632e6688 100644
--- a/bindings/mono/RHash.dll.config
+++ b/bindings/mono/RHash.dll.config
@@ -1,4 +1,4 @@
-
-
-
-
+
+
+
+
diff --git a/bindings/mono/doc/RHash/HashType.xml b/bindings/mono/doc/RHash/HashType.xml
index fe69ff29..a36873ec 100644
--- a/bindings/mono/doc/RHash/HashType.xml
+++ b/bindings/mono/doc/RHash/HashType.xml
@@ -1,390 +1,390 @@
-
-
-
-
- RHash
- 1.0.1.1
-
-
- System.Enum
-
-
- Type of hashing algorithm.
-
-
-Supported algorithms are MD4, MD5, SHA1/SHA2, Tiger,
-DC++ TTH, BitTorrent BTIH, AICH, EDonkey 2000 hash, GOST R 34.11-94,
-RIPEMD-160, HAS-160, EDON-R 256/512, Whirlpool and Snefru-128/256.
-
-
-Constants may be OR-combined to form mask of hashes.
-
-
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- eMule AICH.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- BitTorrent info hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- CRC32 checksum.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- EDonkey 2000 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- EDON-R 256.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- EDON-R 512.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- GOST R 34.11-94.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- GOST R 34.11-94, CryptoPro version.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- HAS-160 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- MD4 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- MD5 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- RIPEMD-160 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- SHA-1 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- SHA-224 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- SHA-256 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- SHA3-224 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- SHA3-256 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- SHA3-384 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- SHA3-512 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- SHA-384 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- SHA-512 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- Snefru-128 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- Snefru-256 hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- Tiger hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- Tiger tree hash.
-
-
-
-
-
- Field
-
- 1.0.1.1
-
-
- RHash.HashType
-
-
- Whirlpool hash.
-
-
-
-
+
+
+
+
+ RHash
+ 1.0.1.1
+
+
+ System.Enum
+
+
+ Type of hashing algorithm.
+
+
+Supported algorithms are MD4, MD5, SHA1/SHA2, Tiger,
+DC++ TTH, BitTorrent BTIH, AICH, EDonkey 2000 hash, GOST R 34.11-94,
+RIPEMD-160, HAS-160, EDON-R 256/512, Whirlpool and Snefru-128/256.
+
+
+Constants may be OR-combined to form mask of hashes.
+
+
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ eMule AICH.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ BitTorrent info hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ CRC32 checksum.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ EDonkey 2000 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ EDON-R 256.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ EDON-R 512.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ GOST R 34.11-94.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ GOST R 34.11-94, CryptoPro version.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ HAS-160 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ MD4 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ MD5 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ RIPEMD-160 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ SHA-1 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ SHA-224 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ SHA-256 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ SHA3-224 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ SHA3-256 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ SHA3-384 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ SHA3-512 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ SHA-384 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ SHA-512 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ Snefru-128 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ Snefru-256 hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ Tiger hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ Tiger tree hash.
+
+
+
+
+
+ Field
+
+ 1.0.1.1
+
+
+ RHash.HashType
+
+
+ Whirlpool hash.
+
+
+
+
diff --git a/bindings/mono/doc/RHash/Hasher.xml b/bindings/mono/doc/RHash/Hasher.xml
index 290012ad..6e1c3a90 100644
--- a/bindings/mono/doc/RHash/Hasher.xml
+++ b/bindings/mono/doc/RHash/Hasher.xml
@@ -1,401 +1,401 @@
-
-
-
-
- RHash
- 1.0.1.1
-
-
- System.Object
-
-
-
- Incremental hasher.
- This class allows you to do incremental hashing for set of hashing algorithms.
-
-
-
-
-
- Constructor
-
- 1.0.1.1
-
-
-
-
-
- Type of hashing algorithm.
- Creates new Hasher to compute message digest for given type.
- To be added.
-
-
-
-
-
- Constructor
-
- 1.0.1.1
-
-
-
-
-
- Mask created of one or more values.
- Creates new Hasher to compute message digests for given set of hashing algorithms.
- Mask should be created from ORed HashType values. The next example will create Hasher that computes both CRC32 and MD5 sums:
-
-
- new Hasher((uint)HashType.CRC32 | (uint)HashType.MD5);
- Argument is zero or contains invalid bits.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- System.Void
-
-
-
- Called by garbage collector to free native resources.
- To be added.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- System.Void
-
-
-
- Finishes calculation of hashes.
- Processes any buffered data and finishes computation of hash sums.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- System.String
-
-
-
-
-
-
- File to compute hash for.
- Type of hash to compute.
- Computes message digest for given file.
- Message digest as returned by .
- To be added.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- System.String
-
-
-
-
-
-
- Binary message to compute hash for.
- Type of hash to compute.
- Computes message digest for given binary message.
- Message digest, as returned by .
- To be added.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- System.String
-
-
-
-
-
- File path to be included in magnet. May be null.
- Generates magnet link with given filename.
- Magnet link.
- Magnet includes all hashes computed by this hasher. If filepath is null then returned magnet does not contain a filename.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- System.String
-
-
-
-
-
-
- File path to be included in magnet. May be null.
- Mask created from one or more values.
- Generates magnet link with given filename and hashes.
- Magnet link.
- Only hashes that were computed by this Hasher are included in the output. If filepath is null then returned magnet does not contain a filename.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- System.String
-
-
-
-
-
-
- File to process.
- Mask created of one or more values.
- Generates magnet for specified file with given hashes.
- Magnet link.
- Returned magnet includes file name and all computed hashes.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- System.Void
-
-
-
- Resets this Hasher to initial state.
- The Hasher becomes available to process new data chunks.
-Note, that this method returns Hasher to the state after creating
-the object, NOT the state when hashing continues.
-Therefore, all previously calculated hashes are lost
-and process starts from the very beginning.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- System.String
-
-
-
-
-
- Type of hashing algorithm.
- Returns value of computed digest as base32 string.
- Message digest in form of base32 string.
- To be added.
- This Hasher does not compute hash of given type.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- System.String
-
-
-
-
-
- Type of hashing algorithm.
- Returns value of computed digest as base64 string.
- Message digest in form of base64 string.
- To be added.
- This Hasher does not compute hash of given type.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- System.String
-
-
-
-
-
- Type of hashing algorithm.
- Returns value of computed digest as hexadecimal string.
- Message digest in form of hexadecimal string.
- To be added.
- This Hasher does not compute hash of given type.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- System.String
-
-
-
-
-
- Type of hashing algorithm.
- Returns value of computed digest as raw bytes encoded in ANSI string.
- Message digest as raw bytes encoded in an ANSI string.
- To be added.
- This Hasher does not compute hash of given type.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- System.String
-
-
-
- Returns value of computed digest as string in default format.
- Message digest as string.
- For Hasher created using constructor, this method returns the same string as method with the hash type used in constructor.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- System.String
-
-
-
-
-
- Type of hashing algorithm.
- Returns value of computed digest as string in default format.
- Message digest for given hashing algorithm.
- If default output for hashing algorithm is base32 then
-returned value is the same as if method was called;
-otherwise value is the same as returned by method.
- This Hasher does not compute hash of given type.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- RHash.Hasher
-
-
-
-
-
- Data for hashing.
- Updates this Hasher with new data chunk.
- This hasher.
- To be added.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- RHash.Hasher
-
-
-
-
-
-
- Data for hashing.
- Number of bytes in array to hash.
- Updates this Hasher with new data chunk.
- This Hasher.
- To be added.
- Argument len is negative or greater than buffer length.
-
-
-
-
-
- Method
-
- 1.0.1.1
-
-
- RHash.Hasher
-
-
-
-
-
- Name of the file to process.
- Updates this Hasher with data from given file.
- This Hasher.
- To be added.
-
-
-
-
+
+
+
+
+ RHash
+ 1.0.1.1
+
+
+ System.Object
+
+
+
+ Incremental hasher.
+ This class allows you to do incremental hashing for set of hashing algorithms.
+
+
+
+
+
+ Constructor
+
+ 1.0.1.1
+
+
+
+
+
+ Type of hashing algorithm.
+ Creates new Hasher to compute message digest for given type.
+ To be added.
+
+
+
+
+
+ Constructor
+
+ 1.0.1.1
+
+
+
+
+
+ Mask created of one or more values.
+ Creates new Hasher to compute message digests for given set of hashing algorithms.
+ Mask should be created from ORed HashType values. The next example will create Hasher that computes both CRC32 and MD5 sums:
+
+
+ new Hasher((uint)HashType.CRC32 | (uint)HashType.MD5);
+ Argument is zero or contains invalid bits.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ System.Void
+
+
+
+ Called by garbage collector to free native resources.
+ To be added.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ System.Void
+
+
+
+ Finishes calculation of hashes.
+ Processes any buffered data and finishes computation of hash sums.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ System.String
+
+
+
+
+
+
+ File to compute hash for.
+ Type of hash to compute.
+ Computes message digest for given file.
+ Message digest as returned by .
+ To be added.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ System.String
+
+
+
+
+
+
+ Binary message to compute hash for.
+ Type of hash to compute.
+ Computes message digest for given binary message.
+ Message digest, as returned by .
+ To be added.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ System.String
+
+
+
+
+
+ File path to be included in magnet. May be null.
+ Generates magnet link with given filename.
+ Magnet link.
+ Magnet includes all hashes computed by this hasher. If filepath is null then returned magnet does not contain a filename.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ System.String
+
+
+
+
+
+
+ File path to be included in magnet. May be null.
+ Mask created from one or more values.
+ Generates magnet link with given filename and hashes.
+ Magnet link.
+ Only hashes that were computed by this Hasher are included in the output. If filepath is null then returned magnet does not contain a filename.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ System.String
+
+
+
+
+
+
+ File to process.
+ Mask created of one or more values.
+ Generates magnet for specified file with given hashes.
+ Magnet link.
+ Returned magnet includes file name and all computed hashes.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ System.Void
+
+
+
+ Resets this Hasher to initial state.
+ The Hasher becomes available to process new data chunks.
+Note, that this method returns Hasher to the state after creating
+the object, NOT the state when hashing continues.
+Therefore, all previously calculated hashes are lost
+and process starts from the very beginning.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ System.String
+
+
+
+
+
+ Type of hashing algorithm.
+ Returns value of computed digest as base32 string.
+ Message digest in form of base32 string.
+ To be added.
+ This Hasher does not compute hash of given type.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ System.String
+
+
+
+
+
+ Type of hashing algorithm.
+ Returns value of computed digest as base64 string.
+ Message digest in form of base64 string.
+ To be added.
+ This Hasher does not compute hash of given type.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ System.String
+
+
+
+
+
+ Type of hashing algorithm.
+ Returns value of computed digest as hexadecimal string.
+ Message digest in form of hexadecimal string.
+ To be added.
+ This Hasher does not compute hash of given type.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ System.String
+
+
+
+
+
+ Type of hashing algorithm.
+ Returns value of computed digest as raw bytes encoded in ANSI string.
+ Message digest as raw bytes encoded in an ANSI string.
+ To be added.
+ This Hasher does not compute hash of given type.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ System.String
+
+
+
+ Returns value of computed digest as string in default format.
+ Message digest as string.
+ For Hasher created using constructor, this method returns the same string as method with the hash type used in constructor.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ System.String
+
+
+
+
+
+ Type of hashing algorithm.
+ Returns value of computed digest as string in default format.
+ Message digest for given hashing algorithm.
+ If default output for hashing algorithm is base32 then
+returned value is the same as if method was called;
+otherwise value is the same as returned by method.
+ This Hasher does not compute hash of given type.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ RHash.Hasher
+
+
+
+
+
+ Data for hashing.
+ Updates this Hasher with new data chunk.
+ This hasher.
+ To be added.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ RHash.Hasher
+
+
+
+
+
+
+ Data for hashing.
+ Number of bytes in array to hash.
+ Updates this Hasher with new data chunk.
+ This Hasher.
+ To be added.
+ Argument len is negative or greater than buffer length.
+
+
+
+
+
+ Method
+
+ 1.0.1.1
+
+
+ RHash.Hasher
+
+
+
+
+
+ Name of the file to process.
+ Updates this Hasher with data from given file.
+ This Hasher.
+ To be added.
+
+
+
+
diff --git a/bindings/mono/doc/index.xml b/bindings/mono/doc/index.xml
index 389d1199..81f54746 100644
--- a/bindings/mono/doc/index.xml
+++ b/bindings/mono/doc/index.xml
@@ -1,42 +1,42 @@
-
-
-
- [00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00 00 24 00 00 52 53 41 31 00 04 00 00 11 00 00 00 2f cc 17 f0 6f bb a5 89 23 fa 26 a6 d9 a2 2a 73 c1 0f 82 84 6c e3 b5 d2 ba a3 82 ef 40 c8 88 8d 16 98 9d 5f a5 ce a5 a8 7c 4e 3d 9f 3a f9 ff 99 a4 d8 c2 51 a8 45 ca a7 df 00 7c 92 07 50 44 60 2a 2f 9c 08 76 6c 4d 61 1a 51 4f 46 44 ff 8f 52 98 25 e8 04 08 35 ee a5 ac 32 b2 eb 4b d6 b0 b0 c5 9b 39 48 0f c7 c9 6e 16 9d b9 33 aa 9e f4 54 21 a2 8d 0a 47 9b fd 15 5f c2 17 b6 09 9f 52 8f ]
-
-
- System.Reflection.AssemblyCompany("")
-
-
- System.Reflection.AssemblyConfiguration("")
-
-
- System.Reflection.AssemblyCopyright("(c) 2011, Sergey Basalaev")
-
-
- System.Reflection.AssemblyDescription(".NET/Mono bindings for librhash")
-
-
- System.Reflection.AssemblyProduct("")
-
-
- System.Reflection.AssemblyTitle("RHash")
-
-
- System.Reflection.AssemblyTrademark("")
-
-
- System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true)
-
-
-
-
- To be added.
- (c) 2011, Sergey Basalaev
-
-
-
-
-
-
- RHash
-
+
+
+
+ [00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00 00 24 00 00 52 53 41 31 00 04 00 00 11 00 00 00 2f cc 17 f0 6f bb a5 89 23 fa 26 a6 d9 a2 2a 73 c1 0f 82 84 6c e3 b5 d2 ba a3 82 ef 40 c8 88 8d 16 98 9d 5f a5 ce a5 a8 7c 4e 3d 9f 3a f9 ff 99 a4 d8 c2 51 a8 45 ca a7 df 00 7c 92 07 50 44 60 2a 2f 9c 08 76 6c 4d 61 1a 51 4f 46 44 ff 8f 52 98 25 e8 04 08 35 ee a5 ac 32 b2 eb 4b d6 b0 b0 c5 9b 39 48 0f c7 c9 6e 16 9d b9 33 aa 9e f4 54 21 a2 8d 0a 47 9b fd 15 5f c2 17 b6 09 9f 52 8f ]
+
+
+ System.Reflection.AssemblyCompany("")
+
+
+ System.Reflection.AssemblyConfiguration("")
+
+
+ System.Reflection.AssemblyCopyright("(c) 2011, Sergey Basalaev")
+
+
+ System.Reflection.AssemblyDescription(".NET/Mono bindings for librhash")
+
+
+ System.Reflection.AssemblyProduct("")
+
+
+ System.Reflection.AssemblyTitle("RHash")
+
+
+ System.Reflection.AssemblyTrademark("")
+
+
+ System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true)
+
+
+
+
+ To be added.
+ (c) 2011, Sergey Basalaev
+
+
+
+
+
+
+ RHash
+
diff --git a/bindings/mono/doc/ns-RHash.xml b/bindings/mono/doc/ns-RHash.xml
index c6c1170d..51cd3f04 100644
--- a/bindings/mono/doc/ns-RHash.xml
+++ b/bindings/mono/doc/ns-RHash.xml
@@ -1,31 +1,31 @@
-
-
- .NET/Mono bindings to librhash.
-
-Librhash is a library for computing and verifying hash sums
-that supports many hashing algorithms. This module provides
-class for incremental hashing that utilizes the library.
-Sample usage of it you can see from the following example:
-
- Hasher hasher = new Hasher((uint)HashType.CRC32 | (uint)HashType.MD5);
- hasher.Update(bytebuffer).UpdateFile("SomeFile.txt");
- hasher.Finish();
- Console.WriteLine(hasher.ToHex(HashType.CRC32));
- Console.WriteLine(hasher.ToBase32(HashType.MD5));
-
- In this example object is first
- created for a set of hashing algorithms.
-
- Next, data for hashing is given in chunks with methods
- Update() and UpdateFile(). Finally, call Finish() to end up
- all remaining calculations.
-
- To receive text represenation of the message digest use one
- of methods ToHex(), ToBase32() and ToBase64(). Binary message
- digest may be obtained with ToRaw(). All of these methods accept
- algorithm value as argument. It may be omitted if Hasher was
- created to compute hash for only a single hashing algorithm.
-
-
-
-
+
+
+ .NET/Mono bindings to librhash.
+
+Librhash is a library for computing and verifying hash sums
+that supports many hashing algorithms. This module provides
+class for incremental hashing that utilizes the library.
+Sample usage of it you can see from the following example:
+
+ Hasher hasher = new Hasher((uint)HashType.CRC32 | (uint)HashType.MD5);
+ hasher.Update(bytebuffer).UpdateFile("SomeFile.txt");
+ hasher.Finish();
+ Console.WriteLine(hasher.ToHex(HashType.CRC32));
+ Console.WriteLine(hasher.ToBase32(HashType.MD5));
+
+ In this example object is first
+ created for a set of hashing algorithms.
+
+ Next, data for hashing is given in chunks with methods
+ Update() and UpdateFile(). Finally, call Finish() to end up
+ all remaining calculations.
+
+ To receive text represenation of the message digest use one
+ of methods ToHex(), ToBase32() and ToBase64(). Binary message
+ digest may be obtained with ToRaw(). All of these methods accept
+ algorithm value as argument. It may be omitted if Hasher was
+ created to compute hash for only a single hashing algorithm.
+
+
+
+
diff --git a/bindings/mono/test/12345.txt b/bindings/mono/test/12345.txt
index e56e15bb..d1877a49 100644
--- a/bindings/mono/test/12345.txt
+++ b/bindings/mono/test/12345.txt
@@ -1 +1 @@
-12345
+12345
diff --git a/bindings/mono/test/Makefile b/bindings/mono/test/Makefile
index 66027c34..9d4567d1 100644
--- a/bindings/mono/test/Makefile
+++ b/bindings/mono/test/Makefile
@@ -1,29 +1,29 @@
-#!/usr/bin/make -f
-
-# This file is a part of Mono Bindings for Librhash
-# Copyright (c) 2011-2012, Sergey Basalaev
-# Librhash is (c) 2011-2012, Aleksey Kravchenko
-#
-# 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.
-#
-# This library 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. Use it at your own risk!
-
-MONO?=mono
-CS?=mcs
-MONO_PATH?=..
-
-test: Test.exe
- MONO_PATH="$(MONO_PATH)" $(MONO) Test.exe
-
-Test.exe: Test.cs
- $(CS) -r:RHash.dll -lib:.. Test.cs
-
-clean:
- rm -f Test.exe
+#!/usr/bin/make -f
+
+# This file is a part of Mono Bindings for Librhash
+# Copyright (c) 2011-2012, Sergey Basalaev
+# Librhash is (c) 2011-2012, Aleksey Kravchenko
+#
+# 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.
+#
+# This library 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. Use it at your own risk!
+
+MONO?=mono
+CS?=mcs
+MONO_PATH?=..
+
+test: Test.exe
+ MONO_PATH="$(MONO_PATH)" $(MONO) Test.exe
+
+Test.exe: Test.cs
+ $(CS) -r:RHash.dll -lib:.. Test.cs
+
+clean:
+ rm -f Test.exe
diff --git a/bindings/mono/test/Test.cs b/bindings/mono/test/Test.cs
index a674f332..78990684 100644
--- a/bindings/mono/test/Test.cs
+++ b/bindings/mono/test/Test.cs
@@ -1,105 +1,105 @@
-/*
- * This file is a part of Mono Bindings for Librhash
- * Copyright (c) 2011-2012, Sergey Basalaev
- * Librhash is (c) 2011-2012, Aleksey Kravchenko
- *
- * 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.
- *
- * This library 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. Use it at your own risk!
- */
-
-using System;
-using System.Collections.Generic;
-using RHash;
-
-class Test {
- static void Main(string[] args) {
- byte[] testbytes = {(byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'\n'};
-
- Dictionary hashes = new Dictionary();
- hashes.Add(HashType.CRC32, "261dafe6");
- hashes.Add(HashType.CRC32C, "3c95f7e7");
- hashes.Add(HashType.MD4, "b1a45cdad19cb02482323fac9cea9b9f");
- hashes.Add(HashType.MD5, "d577273ff885c3f84dadb8578bb41399");
- hashes.Add(HashType.SHA1, "2672275fe0c456fb671e4f417fb2f9892c7573ba");
- hashes.Add(HashType.SHA224, "ea2fa9708c96b4acb281be31fa98827addc5017305b7a038a3fca413");
- hashes.Add(HashType.SHA256, "f33ae3bc9a22cd7564990a794789954409977013966fb1a8f43c35776b833a95");
- hashes.Add(HashType.SHA384, "4e1cbb008acaa65ba788e3f150f7a8689c8fca289a57a65ef65b28f11ba61e59c3f4ddf069ca9521a9ac0e02eade4dae");
- hashes.Add(HashType.SHA512, "f2dc0119c9dac46f49d3b7d0be1f61adf7619b770ff076fb11a2f61ff3fcba6b68d224588c4983670da31b33b4efabd448e38a2fda508622cc33ff8304ddf49c");
- hashes.Add(HashType.TIGER, "6a31f8b7b80bab8b45263f56b5f609f93daf47d0a086bda5");
- hashes.Add(HashType.TTH, "dctamcmte5tqwam5afghps2xpx3yeozwj2odzcq");
- //hashes.Add(HashType.BTIH, "d4344cf79b89e4732c6241e730ac3f945d7a774c");
- hashes.Add(HashType.AICH, "ezzcox7ayrlpwzy6j5ax7mxzrewhk452");
- hashes.Add(HashType.ED2K, "b1a45cdad19cb02482323fac9cea9b9f");
- hashes.Add(HashType.WHIRLPOOL, "0e8ce019c9d5185d2103a4ff015ec92587da9b22e77ad34f2eddbba9705b3602bc6ede67f5b5e4dd225e7762208ea54895b26c39fc550914d6eca9604b724d11");
- hashes.Add(HashType.GOST94, "0aaaf17200323d024437837d6f6f6384a4a108474cff03cd349ac12776713f5f");
- hashes.Add(HashType.GOST94_CRYPTOPRO, "2ed45a995ffdd7a2e5d9ab212c91cec5c65448e6a0840749a00f326ccb0c936d");
- hashes.Add(HashType.GOST12_256, "8ca8bf4245043db42d3c34f4d7d7391d10cfad5f897ca0001c98ffcf56b00a5d");
- hashes.Add(HashType.GOST12_512, "4d46d8ea693092d367d3ba45ea0ae5bd8e58fdbda4c32dcf48489d754e9dae4e992c4db22fcdaf625a8b05af68acc08c40d011180dfec5ba58e3ebc5b21c94ac");
- hashes.Add(HashType.RIPEMD160, "ead888178685c5d3a0400befba9188e4da3d5144");
- hashes.Add(HashType.HAS160, "c7589afd23462e76703b1f7a031010eec70180d4");
- hashes.Add(HashType.SNEFRU128, "d559a2b62f6f44111324f85208723707");
- hashes.Add(HashType.SNEFRU256, "1b59927d85a9349a87796620fe2ff401a06a7ba48794498ebab978efc3a68912");
- hashes.Add(HashType.EDONR256, "c3d2bbfd63f7461a806f756bf4efeb224036331a9c1d867d251e9e480b18e6fb");
- hashes.Add(HashType.EDONR512, "a040056378fbd1f9a528677defd141c964fab9c429003fecf2eadfc20c8980cf2e083a1b4e74d5369af3cc0537bcf9b386fedf3613c9ee6c44f54f11bcf3feae");
- hashes.Add(HashType.SHA3_224, "952f55abd73d0efd9656982f65c4dc837a6a129de02464b85d04cb18");
- hashes.Add(HashType.SHA3_256, "f627c8f9355399ef45e1a6b6e5a9e6a3abcb3e1b6255603357bffa9f2211ba7e");
- hashes.Add(HashType.SHA3_384, "0529075e85bcdc06da94cbc83c53b7402c5032440210a1a24d9ccca481ddbd6c1309ae0ef23741f13352a4f3382dee51");
- hashes.Add(HashType.SHA3_512, "fdd7e7b9655f4f0ef89056e864a2d2dce3602404480281c88455e3a98f728aa08b3f116e6b434200a035e0780d9237ca367c976c5506f7c6f367e6b65447d97c");
-
- Console.WriteLine("\nTests: hashes for message");
- int errcount1 = 0;
- foreach (HashType t in hashes.Keys) {
- string mustbe = hashes[t];
- string got = Hasher.GetHashForMsg(testbytes, t);
- if (!got.Equals(mustbe)) {
- Console.WriteLine("Test for {0} failed: expected '{1}', got '{2}'\n", t, mustbe, got);
- errcount1++;
- }
- }
- Console.WriteLine("{0} tests / {1} failed\n", hashes.Count, errcount1);
-
- Console.WriteLine("\nTests: hashes for file");
- int errcount2 = 0;
- foreach (HashType t in hashes.Keys) {
- string mustbe = hashes[t];
- string got = Hasher.GetHashForFile("12345.txt", t);
- if (!got.Equals(mustbe)) {
- Console.WriteLine("Test for {0} failed: expected '{1}', got '{2}'\n", t, mustbe, got);
- errcount2++;
- }
- }
- Console.WriteLine("{0} tests / {1} failed\n", hashes.Count, errcount2);
-
- Console.WriteLine("\nTests: magnet links");
- int errcount3 = 0;
- {
- // magnet by static method
- string mustbe = "magnet:?xl=6&dn=12345.txt&xt=urn:crc32:261dafe6&xt=urn:md5:d577273ff885c3f84dadb8578bb41399";
- string got = Hasher.GetMagnetFor("12345.txt", (uint)HashType.CRC32 | (uint)HashType.MD5);
- if (!got.Equals(mustbe)) {
- Console.WriteLine("Magnet by static method test failed: expected '{0}', got '{1}'\n", mustbe, got);
- errcount3++;
- }
- // magnet with null argument
- Hasher hasher = new Hasher((uint)HashType.CRC32 | (uint)HashType.MD5);
- hasher.UpdateFile("12345.txt").Finish();
- mustbe = "magnet:?xl=6&xt=urn:crc32:261dafe6";
- got = hasher.GetMagnet(null, (uint)HashType.CRC32 | (uint)HashType.AICH);
- if (!got.Equals(mustbe)) {
- Console.WriteLine("Magnet with null argument test failed: expected '{0}', got '{1}'\n", mustbe, got);
- errcount3++;
- }
- }
- Console.WriteLine("{0} tests / {1} failed\n", 2, errcount3);
-
- System.Environment.ExitCode = errcount1 + errcount2 + errcount3;
- }
-}
+/*
+ * This file is a part of Mono Bindings for Librhash
+ * Copyright (c) 2011-2012, Sergey Basalaev
+ * Librhash is (c) 2011-2012, Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This library 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. Use it at your own risk!
+ */
+
+using System;
+using System.Collections.Generic;
+using RHash;
+
+class Test {
+ static void Main(string[] args) {
+ byte[] testbytes = {(byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'\n'};
+
+ Dictionary hashes = new Dictionary();
+ hashes.Add(HashType.CRC32, "261dafe6");
+ hashes.Add(HashType.CRC32C, "3c95f7e7");
+ hashes.Add(HashType.MD4, "b1a45cdad19cb02482323fac9cea9b9f");
+ hashes.Add(HashType.MD5, "d577273ff885c3f84dadb8578bb41399");
+ hashes.Add(HashType.SHA1, "2672275fe0c456fb671e4f417fb2f9892c7573ba");
+ hashes.Add(HashType.SHA224, "ea2fa9708c96b4acb281be31fa98827addc5017305b7a038a3fca413");
+ hashes.Add(HashType.SHA256, "f33ae3bc9a22cd7564990a794789954409977013966fb1a8f43c35776b833a95");
+ hashes.Add(HashType.SHA384, "4e1cbb008acaa65ba788e3f150f7a8689c8fca289a57a65ef65b28f11ba61e59c3f4ddf069ca9521a9ac0e02eade4dae");
+ hashes.Add(HashType.SHA512, "f2dc0119c9dac46f49d3b7d0be1f61adf7619b770ff076fb11a2f61ff3fcba6b68d224588c4983670da31b33b4efabd448e38a2fda508622cc33ff8304ddf49c");
+ hashes.Add(HashType.TIGER, "6a31f8b7b80bab8b45263f56b5f609f93daf47d0a086bda5");
+ hashes.Add(HashType.TTH, "dctamcmte5tqwam5afghps2xpx3yeozwj2odzcq");
+ //hashes.Add(HashType.BTIH, "d4344cf79b89e4732c6241e730ac3f945d7a774c");
+ hashes.Add(HashType.AICH, "ezzcox7ayrlpwzy6j5ax7mxzrewhk452");
+ hashes.Add(HashType.ED2K, "b1a45cdad19cb02482323fac9cea9b9f");
+ hashes.Add(HashType.WHIRLPOOL, "0e8ce019c9d5185d2103a4ff015ec92587da9b22e77ad34f2eddbba9705b3602bc6ede67f5b5e4dd225e7762208ea54895b26c39fc550914d6eca9604b724d11");
+ hashes.Add(HashType.GOST94, "0aaaf17200323d024437837d6f6f6384a4a108474cff03cd349ac12776713f5f");
+ hashes.Add(HashType.GOST94_CRYPTOPRO, "2ed45a995ffdd7a2e5d9ab212c91cec5c65448e6a0840749a00f326ccb0c936d");
+ hashes.Add(HashType.GOST12_256, "8ca8bf4245043db42d3c34f4d7d7391d10cfad5f897ca0001c98ffcf56b00a5d");
+ hashes.Add(HashType.GOST12_512, "4d46d8ea693092d367d3ba45ea0ae5bd8e58fdbda4c32dcf48489d754e9dae4e992c4db22fcdaf625a8b05af68acc08c40d011180dfec5ba58e3ebc5b21c94ac");
+ hashes.Add(HashType.RIPEMD160, "ead888178685c5d3a0400befba9188e4da3d5144");
+ hashes.Add(HashType.HAS160, "c7589afd23462e76703b1f7a031010eec70180d4");
+ hashes.Add(HashType.SNEFRU128, "d559a2b62f6f44111324f85208723707");
+ hashes.Add(HashType.SNEFRU256, "1b59927d85a9349a87796620fe2ff401a06a7ba48794498ebab978efc3a68912");
+ hashes.Add(HashType.EDONR256, "c3d2bbfd63f7461a806f756bf4efeb224036331a9c1d867d251e9e480b18e6fb");
+ hashes.Add(HashType.EDONR512, "a040056378fbd1f9a528677defd141c964fab9c429003fecf2eadfc20c8980cf2e083a1b4e74d5369af3cc0537bcf9b386fedf3613c9ee6c44f54f11bcf3feae");
+ hashes.Add(HashType.SHA3_224, "952f55abd73d0efd9656982f65c4dc837a6a129de02464b85d04cb18");
+ hashes.Add(HashType.SHA3_256, "f627c8f9355399ef45e1a6b6e5a9e6a3abcb3e1b6255603357bffa9f2211ba7e");
+ hashes.Add(HashType.SHA3_384, "0529075e85bcdc06da94cbc83c53b7402c5032440210a1a24d9ccca481ddbd6c1309ae0ef23741f13352a4f3382dee51");
+ hashes.Add(HashType.SHA3_512, "fdd7e7b9655f4f0ef89056e864a2d2dce3602404480281c88455e3a98f728aa08b3f116e6b434200a035e0780d9237ca367c976c5506f7c6f367e6b65447d97c");
+
+ Console.WriteLine("\nTests: hashes for message");
+ int errcount1 = 0;
+ foreach (HashType t in hashes.Keys) {
+ string mustbe = hashes[t];
+ string got = Hasher.GetHashForMsg(testbytes, t);
+ if (!got.Equals(mustbe)) {
+ Console.WriteLine("Test for {0} failed: expected '{1}', got '{2}'\n", t, mustbe, got);
+ errcount1++;
+ }
+ }
+ Console.WriteLine("{0} tests / {1} failed\n", hashes.Count, errcount1);
+
+ Console.WriteLine("\nTests: hashes for file");
+ int errcount2 = 0;
+ foreach (HashType t in hashes.Keys) {
+ string mustbe = hashes[t];
+ string got = Hasher.GetHashForFile("12345.txt", t);
+ if (!got.Equals(mustbe)) {
+ Console.WriteLine("Test for {0} failed: expected '{1}', got '{2}'\n", t, mustbe, got);
+ errcount2++;
+ }
+ }
+ Console.WriteLine("{0} tests / {1} failed\n", hashes.Count, errcount2);
+
+ Console.WriteLine("\nTests: magnet links");
+ int errcount3 = 0;
+ {
+ // magnet by static method
+ string mustbe = "magnet:?xl=6&dn=12345.txt&xt=urn:crc32:261dafe6&xt=urn:md5:d577273ff885c3f84dadb8578bb41399";
+ string got = Hasher.GetMagnetFor("12345.txt", (uint)HashType.CRC32 | (uint)HashType.MD5);
+ if (!got.Equals(mustbe)) {
+ Console.WriteLine("Magnet by static method test failed: expected '{0}', got '{1}'\n", mustbe, got);
+ errcount3++;
+ }
+ // magnet with null argument
+ Hasher hasher = new Hasher((uint)HashType.CRC32 | (uint)HashType.MD5);
+ hasher.UpdateFile("12345.txt").Finish();
+ mustbe = "magnet:?xl=6&xt=urn:crc32:261dafe6";
+ got = hasher.GetMagnet(null, (uint)HashType.CRC32 | (uint)HashType.AICH);
+ if (!got.Equals(mustbe)) {
+ Console.WriteLine("Magnet with null argument test failed: expected '{0}', got '{1}'\n", mustbe, got);
+ errcount3++;
+ }
+ }
+ Console.WriteLine("{0} tests / {1} failed\n", 2, errcount3);
+
+ System.Environment.ExitCode = errcount1 + errcount2 + errcount3;
+ }
+}
diff --git a/bindings/perl/.gitignore b/bindings/perl/.gitignore
index 9f8771c5..450d16c7 100644
--- a/bindings/perl/.gitignore
+++ b/bindings/perl/.gitignore
@@ -1,6 +1,6 @@
-blib/
-Makefile
-Rhash.c
-Rhash.bs
-pm_to_blib
-MYMETA.*
+blib/
+Makefile
+Rhash.c
+Rhash.bs
+pm_to_blib
+MYMETA.*
diff --git a/bindings/perl/MANIFEST b/bindings/perl/MANIFEST
index f4768505..f99efb79 100644
--- a/bindings/perl/MANIFEST
+++ b/bindings/perl/MANIFEST
@@ -1,11 +1,11 @@
-Makefile.PL
-README
-Rhash.pm
-Rhash.xs
-t/1test_hash_calculation.t
-t/2test_static_functions.t
-t/3test_all_hash_functions.t
-typemap
-MANIFEST
-META.yml Module YAML meta-data (added by MakeMaker)
-META.json Module JSON meta-data (added by MakeMaker)
+Makefile.PL
+README
+Rhash.pm
+Rhash.xs
+t/1test_hash_calculation.t
+t/2test_static_functions.t
+t/3test_all_hash_functions.t
+typemap
+MANIFEST
+META.yml Module YAML meta-data (added by MakeMaker)
+META.json Module JSON meta-data (added by MakeMaker)
diff --git a/bindings/perl/Makefile.PL b/bindings/perl/Makefile.PL
index 1a469509..b1b130cb 100644
--- a/bindings/perl/Makefile.PL
+++ b/bindings/perl/Makefile.PL
@@ -1,111 +1,111 @@
-use strict;
-use warnings;
-use Cwd;
-use ExtUtils::MakeMaker;
-use File::Copy;
-
-my $libs = '';
-my $inc = '';
-my $obj = '';
-my $clean = '';
-my $inc_dir = undef;
-my $lib_dir = undef;
-my $rh_builtin_dir = 'librhash';
-my $rh_local_dir = getcwd() . '/../../librhash';
-my $rh_type = $ENV{'LIBRHASH'} || 'auto';
-my $custom_inc = $ENV{'LIBRHASH_INC'} || '';
-my $custom_ld = $ENV{'LIBRHASH_LD'} || '';
-
-sub has_librhash {
- return (-f $_[0] . '/rhash.h');
-}
-
-if ($rh_type eq 'auto')
-{
- $rh_type = ($custom_ld =~ /-L/ ? 'custom' :
- has_librhash($rh_builtin_dir) ? 'builtin' :
- has_librhash($rh_local_dir) ? 'local' : 'system' );
- print "Selected librhash type: $rh_type\n";
-}
-if ($rh_type ne 'custom')
-{
- $inc_dir = ($rh_type eq 'builtin' ? $rh_builtin_dir :
- $rh_type eq 'local' ? $rh_local_dir :
- $rh_type eq 'system' ? '' : die("Unknown type LIBRHASH='$rh_type'"));
- $lib_dir = $inc_dir if $rh_type ne 'builtin';
- !$inc_dir || -d $inc_dir || die "Not a directory: '$inc_dir'";
- !$inc_dir || has_librhash($inc_dir) || die "No librhash headers at: '$inc_dir'";
- $inc = "-I$inc_dir" if $inc_dir;
- $libs = "-L$lib_dir" if $lib_dir;
- $libs .= ' -lrhash' if $rh_type ne 'builtin';
-} else {
- # set custom compile and linking flags
- $inc = $custom_inc;
- $libs = $custom_ld;
-}
-
-# copy and rename *.c files by prepending underscore '_'
-sub copy_c_files($) {
- my $from_dir = $_[0];
- my @result = ();
- (opendir my($dh), $from_dir) or die "Can't open $from_dir: $!";
- my @files = grep { /(?= $df);
- #print "copy $from -> $to\n";
- copy($from, $to)
- or die "Can't copy $from to $to: $!";
- }
- return @result;
-}
-
-if($rh_type eq 'builtin') {
- # using sources of the builtin librhash
- my @c_files = copy_c_files($rh_builtin_dir);
- $clean = join(' ', @c_files);
- $obj = join(' ', map { s/\.c$/\$(OBJ_EXT)/; $_ } @c_files) . ' ';
-}
-
-# make setting optional MakeMaker parameters more readable
-sub OPTIONAL {
- return () unless $ExtUtils::MakeMaker::VERSION ge shift;
- return @_;
-}
-
-# see ExtUtils::MakeMaker.pm for details of how to influence
-# the contents of the Makefile that is written
-WriteMakefile(
- NAME => 'Crypt::Rhash',
- ABSTRACT => 'Library for computing hash sums and magnet links',
- AUTHOR => 'Aleksey Kravchenko',
- VERSION_FROM => 'Rhash.pm', # finds $VERSION
- OPTIONAL( '6.31',
- LICENSE => 'unrestricted',
- ),
- OPTIONAL( '6.46',
- # Use META_ADD instead of META_MERGE so that we can remove
- # any build-time dependencies that MakeMaker will put into
- # the requires field.
- META_ADD => {
- resources => {
- homepage => 'http://rhash.sf.net/',
- bugtracker => 'https://github.com/rhash/RHash/issues',
- license => 'https://github.com/rhash/RHash/blob/master/COPYING',
- repository => 'https://github.com/rhash/RHash',
- },
- },
- ),
-
- LIBS => [ $libs ],
- DEFINE => '', # e.g., '-DHAVE_SOMETHING'
- INC => $inc, # e.g., '-I/usr/include/other'
- OBJECT => $obj . 'Rhash$(OBJ_EXT)',
- clean => {
- FILES => $clean,
- },
-);
+use strict;
+use warnings;
+use Cwd;
+use ExtUtils::MakeMaker;
+use File::Copy;
+
+my $libs = '';
+my $inc = '';
+my $obj = '';
+my $clean = '';
+my $inc_dir = undef;
+my $lib_dir = undef;
+my $rh_builtin_dir = 'librhash';
+my $rh_local_dir = getcwd() . '/../../librhash';
+my $rh_type = $ENV{'LIBRHASH'} || 'auto';
+my $custom_inc = $ENV{'LIBRHASH_INC'} || '';
+my $custom_ld = $ENV{'LIBRHASH_LD'} || '';
+
+sub has_librhash {
+ return (-f $_[0] . '/rhash.h');
+}
+
+if ($rh_type eq 'auto')
+{
+ $rh_type = ($custom_ld =~ /-L/ ? 'custom' :
+ has_librhash($rh_builtin_dir) ? 'builtin' :
+ has_librhash($rh_local_dir) ? 'local' : 'system' );
+ print "Selected librhash type: $rh_type\n";
+}
+if ($rh_type ne 'custom')
+{
+ $inc_dir = ($rh_type eq 'builtin' ? $rh_builtin_dir :
+ $rh_type eq 'local' ? $rh_local_dir :
+ $rh_type eq 'system' ? '' : die("Unknown type LIBRHASH='$rh_type'"));
+ $lib_dir = $inc_dir if $rh_type ne 'builtin';
+ !$inc_dir || -d $inc_dir || die "Not a directory: '$inc_dir'";
+ !$inc_dir || has_librhash($inc_dir) || die "No librhash headers at: '$inc_dir'";
+ $inc = "-I$inc_dir" if $inc_dir;
+ $libs = "-L$lib_dir" if $lib_dir;
+ $libs .= ' -lrhash' if $rh_type ne 'builtin';
+} else {
+ # set custom compile and linking flags
+ $inc = $custom_inc;
+ $libs = $custom_ld;
+}
+
+# copy and rename *.c files by prepending underscore '_'
+sub copy_c_files($) {
+ my $from_dir = $_[0];
+ my @result = ();
+ (opendir my($dh), $from_dir) or die "Can't open $from_dir: $!";
+ my @files = grep { /(?= $df);
+ #print "copy $from -> $to\n";
+ copy($from, $to)
+ or die "Can't copy $from to $to: $!";
+ }
+ return @result;
+}
+
+if($rh_type eq 'builtin') {
+ # using sources of the builtin librhash
+ my @c_files = copy_c_files($rh_builtin_dir);
+ $clean = join(' ', @c_files);
+ $obj = join(' ', map { s/\.c$/\$(OBJ_EXT)/; $_ } @c_files) . ' ';
+}
+
+# make setting optional MakeMaker parameters more readable
+sub OPTIONAL {
+ return () unless $ExtUtils::MakeMaker::VERSION ge shift;
+ return @_;
+}
+
+# see ExtUtils::MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written
+WriteMakefile(
+ NAME => 'Crypt::Rhash',
+ ABSTRACT => 'Library for computing hash sums and magnet links',
+ AUTHOR => 'Aleksey Kravchenko',
+ VERSION_FROM => 'Rhash.pm', # finds $VERSION
+ OPTIONAL( '6.31',
+ LICENSE => 'unrestricted',
+ ),
+ OPTIONAL( '6.46',
+ # Use META_ADD instead of META_MERGE so that we can remove
+ # any build-time dependencies that MakeMaker will put into
+ # the requires field.
+ META_ADD => {
+ resources => {
+ homepage => 'http://rhash.sf.net/',
+ bugtracker => 'https://github.com/rhash/RHash/issues',
+ license => 'https://github.com/rhash/RHash/blob/master/COPYING',
+ repository => 'https://github.com/rhash/RHash',
+ },
+ },
+ ),
+
+ LIBS => [ $libs ],
+ DEFINE => '', # e.g., '-DHAVE_SOMETHING'
+ INC => $inc, # e.g., '-I/usr/include/other'
+ OBJECT => $obj . 'Rhash$(OBJ_EXT)',
+ clean => {
+ FILES => $clean,
+ },
+);
diff --git a/bindings/perl/README b/bindings/perl/README
index 3094c4c0..63ea6945 100644
--- a/bindings/perl/README
+++ b/bindings/perl/README
@@ -1,37 +1,37 @@
-
-Crypt::Rhash module allows to compute various hash sums and magnet links.
-
-The following hash sums are supported: CRC32, CRC32C, MD4, MD5,
-SHA1, SHA256, SHA512, SHA3, Tiger, TTH, Torrent BTIH, AICH, ED2K,
-GOST R 34.11-94, GOST R 34.11-2012, RIPEMD-160, HAS-160,
-EDON-R 256/512, WHIRLPOOL and SNEFRU.
-
-BUILDING THE MODULE
--------------------
-
-The module can be built using the sequence of commands:
-
- perl Makefile.PL
- make
- make test
-
-INSTALLATION
-------------
-
-To install Crypt::Rhash, run the following command:
-
- make install
-
-LICENSE
--------
-
-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.
-
-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. Use this program at your own risk!
+
+Crypt::Rhash module allows to compute various hash sums and magnet links.
+
+The following hash sums are supported: CRC32, CRC32C, MD4, MD5,
+SHA1, SHA256, SHA512, SHA3, Tiger, TTH, Torrent BTIH, AICH, ED2K,
+GOST R 34.11-94, GOST R 34.11-2012, RIPEMD-160, HAS-160,
+EDON-R 256/512, WHIRLPOOL and SNEFRU.
+
+BUILDING THE MODULE
+-------------------
+
+The module can be built using the sequence of commands:
+
+ perl Makefile.PL
+ make
+ make test
+
+INSTALLATION
+------------
+
+To install Crypt::Rhash, run the following command:
+
+ make install
+
+LICENSE
+-------
+
+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.
+
+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. Use this program at your own risk!
diff --git a/bindings/perl/Rhash.pm b/bindings/perl/Rhash.pm
index 829e37cf..59db394a 100644
--- a/bindings/perl/Rhash.pm
+++ b/bindings/perl/Rhash.pm
@@ -1,471 +1,471 @@
-package Crypt::Rhash;
-
-use 5.006001;
-use strict;
-use warnings;
-
-require Exporter;
-our @ISA = (qw(Exporter));
-
-# possible tags for export
-our %EXPORT_TAGS = (
- Functions => [qw(raw2hex raw2base32 raw2base64)],
- Constants => [qw(RHASH_CRC32 RHASH_CRC32C RHASH_MD4 RHASH_MD5
- RHASH_SHA1 RHASH_TIGER RHASH_TTH RHASH_BTIH RHASH_ED2K
- RHASH_AICH RHASH_WHIRLPOOL RHASH_RIPEMD160 RHASH_GOST94
- RHASH_GOST94_CRYPTOPRO RHASH_GOST12_256 RHASH_GOST12_512
- RHASH_SHA224 RHASH_SHA256 RHASH_SHA384 RHASH_SHA512
- RHASH_SHA3_224 RHASH_SHA3_256 RHASH_SHA3_384 RHASH_SHA3_512
- RHASH_HAS160 RHASH_EDONR256 RHASH_EDONR512
- RHASH_SNEFRU128 RHASH_SNEFRU256 RHASH_ALL)]
-);
-
-Exporter::export_tags( );
-Exporter::export_ok_tags( qw(Functions Constants) );
-
-our $VERSION = '0.97';
-
-require XSLoader;
-XSLoader::load('Crypt::Rhash', $VERSION);
-
-##############################################################################
-# ids of hash functions
-use constant RHASH_CRC32 => 0x01;
-use constant RHASH_MD4 => 0x02;
-use constant RHASH_MD5 => 0x04;
-use constant RHASH_SHA1 => 0x08;
-use constant RHASH_TIGER => 0x10;
-use constant RHASH_TTH => 0x20;
-use constant RHASH_BTIH => 0x40;
-use constant RHASH_ED2K => 0x80;
-use constant RHASH_AICH => 0x100;
-use constant RHASH_WHIRLPOOL => 0x200;
-use constant RHASH_RIPEMD160 => 0x400;
-use constant RHASH_GOST94 => 0x800;
-use constant RHASH_GOST94_CRYPTOPRO => 0x1000;
-use constant RHASH_HAS160 => 0x2000;
-use constant RHASH_GOST12_256 => 0x4000;
-use constant RHASH_GOST12_512 => 0x8000;
-use constant RHASH_SHA224 => 0x10000;
-use constant RHASH_SHA256 => 0x20000;
-use constant RHASH_SHA384 => 0x40000;
-use constant RHASH_SHA512 => 0x80000;
-use constant RHASH_EDONR256 => 0x100000;
-use constant RHASH_EDONR512 => 0x200000;
-use constant RHASH_SHA3_224 => 0x0400000;
-use constant RHASH_SHA3_256 => 0x0800000;
-use constant RHASH_SHA3_384 => 0x1000000;
-use constant RHASH_SHA3_512 => 0x2000000;
-use constant RHASH_CRC32C => 0x4000000;
-use constant RHASH_SNEFRU128 => 0x8000000;
-use constant RHASH_SNEFRU256 => 0x10000000;
-use constant RHASH_ALL => 0x1FFFFFFF;
-
-##############################################################################
-# Rhash class methods
-
-# Rhash object constructor
-sub new
-{
- my $hash_id = $_[1] or die "hash_id not specified";
- my $context = rhash_init(scalar($hash_id)) or return undef;
- my $self = {
- context => $context,
- };
- return bless $self;
-}
-
-# destructor
-sub DESTROY($)
-{
- my $self = shift;
- # the 'if' added as workaround for perl 'global destruction' bug
- # ($self->{context} can disappear on global destruction)
- rhash_free($self->{context}) if $self->{context};
-}
-
-sub update($$)
-{
- my $self = shift;
- my $message = shift;
- rhash_update($self->{context}, $message);
- return $self;
-}
-
-sub update_fd($$;$$)
-{
- my ($self, $fd, $start, $size) = @_;
- my $res = 0;
- my $num = 0;
-
- binmode($fd);
- if(defined($start)) {
- seek($fd, scalar($start), 0) or return undef;
- }
-
- my $data;
- if(defined($size)) {
- for(my $left = scalar($size); $left > 0; $left -= 8192) {
- ($res = read($fd, $data,
- ($left < 8192 ? $left : 8192))) || last;
- rhash_update($self->{context}, $data);
- $num += $res;
- }
- } else {
- while( ($res = read($fd, $data, 8192)) ) {
- rhash_update($self->{context}, $data);
- $num += $res;
- }
- }
-
- return (defined($res) ? $num : undef); # return undef on read error
-}
-
-sub update_file($$;$$)
-{
- my ($self, $file, $start, $size) = @_;
- open(my $fd, "<", $file) or return undef;
- my $res = $self->update_fd($fd, $start, $size);
- close($fd);
- return $res;
-}
-
-sub final($)
-{
- my $self = shift;
- rhash_final($self->{context});
- return $self;
-}
-
-sub reset($)
-{
- my $self = shift;
- rhash_reset($self->{context});
- return $self;
-}
-
-sub hashed_length($)
-{
- my $self = shift;
- return rhash_get_hashed_length($self->{context});
-}
-
-sub hash_id($)
-{
- my $self = shift;
- return rhash_get_hash_id($self->{context});
-}
-
-##############################################################################
-# Hash formatting functions
-
-# printing constants
-use constant RHPR_DEFAULT => 0x0;
-use constant RHPR_RAW => 0x1;
-use constant RHPR_HEX => 0x2;
-use constant RHPR_BASE32 => 0x3;
-use constant RHPR_BASE64 => 0x4;
-use constant RHPR_UPPERCASE => 0x8;
-use constant RHPR_REVERSE => 0x10;
-
-sub hash($;$$)
-{
- my $self = shift;
- my $hash_id = scalar(shift) || 0;
- my $print_flags = scalar(shift) || RHPR_DEFAULT;
- return rhash_print($self->{context}, $hash_id, $print_flags);
-}
-
-sub hash_base32($;$)
-{
- hash($_[0], $_[1], RHPR_BASE32);
-}
-
-sub hash_base64($;$)
-{
- hash($_[0], $_[1], RHPR_BASE64);
-}
-
-sub hash_hex($;$)
-{
- hash($_[0], $_[1], RHPR_HEX);
-}
-
-sub hash_rhex($;$)
-{
- hash($_[0], $_[1], RHPR_HEX | RHPR_REVERSE);
-}
-
-sub hash_raw($;$)
-{
- hash($_[0], $_[1], RHPR_RAW);
-}
-
-sub magnet_link($;$$)
-{
- my ($self, $filename, $hash_mask) = @_;
- return rhash_print_magnet($self->{context}, $filename, $hash_mask);
-}
-
-our $AUTOLOAD;
-
-# report error if a script called unexisting method/field
-sub AUTOLOAD
-{
- my ($self, $field, $type, $pkg) = ($_[0], $AUTOLOAD, undef, __PACKAGE__);
- $field =~ s/.*://;
- die "function $field does not exist" if $field =~ /^(rhash_|raw2)/;
- die "no arguments specified to $field()" if !@_;
- die "the $field() argument is undefined" if !defined $self;
-
- ($type = ref($self)) && $type eq $pkg || die "the $field() argument is not a $pkg reference";
- my $text = (exists $self->{$field} ? "is not accessible" : "does not exist");
- die "the method $field() $text in the class $pkg";
-}
-
-# static functions
-
-sub msg($$)
-{
- my ($hash_id, $msg) = @_;
- my $raw = rhash_msg_raw($hash_id, $msg); # get binary hash
- return (is_base32($hash_id) ? raw2base32($raw) : raw2hex($raw));
-}
-
-1;
-__END__
-# Below is Rhash module documentation in the standard POD format
-
-=head1 NAME
-
-Crypt::Rhash - Compute hash sums and magnet links
-
-=head1 SYNOPSIS
-
- use Crypt::Rhash;
-
- my $msg = "a message text";
- print "MD5 = " . Crypt::Rhash::msg(RHASH_MD5, $msg) . "\n";
-
- # Calculate two hash functions simultaneously
- my $r = Crypt::Rhash->new(RHASH_MD5 | RHASH_SHA1);
- $r->update("a message text")->update(" another message");
- print "MD5 = " . $r->hash(RHASH_MD5) . "\n";
- print "SHA1 = " . $r->hash(RHASH_SHA1) . "\n";
-
-=head1 DESCRIPTION
-
-Crypt::Rhash module is an object-oriented interface to the LibRHash library,
-allowing simultaneous calculation of several hash functions for a file or a
-text message.
-
-Resulting hash digest can be obtained in hexadecimal, BASE32, BASE64, raw
-binary format or as a magnet link.
-
-=head1 SUPPORTED ALGORITHMS
-
-The module supports the following hashing algorithms:
-CRC32, CRC32C, MD4, MD5, SHA1, SHA256, SHA512, SHA3, AICH, ED2K, Tiger,
-DC++ TTH, GOST R 34.11-94, GOST R 34.11-2012, BitTorrent BTIH, RIPEMD-160,
-HAS-160, EDON-R 256/512, Whirlpool and Snefru-128/256.
-
-=head1 CONSTRUCTOR
-
-Creates and returns new Crypt::Rhash object.
-
- my $r = Crypt::Rhash->new($hash_id);
- my $p = new Crypt::Rhash($hash_id); # alternative way to call the constructor
-
-The $hash_id parameter can be union (via bitwise OR) of any of the following bit-flags:
-
- RHASH_CRC32,
- RHASH_CRC32C,
- RHASH_MD4,
- RHASH_MD5,
- RHASH_SHA1,
- RHASH_TIGER,
- RHASH_TTH,
- RHASH_BTIH,
- RHASH_ED2K,
- RHASH_AICH,
- RHASH_WHIRLPOOL,
- RHASH_RIPEMD160,
- RHASH_GOST94,
- RHASH_GOST94_CRYPTOPRO,
- RHASH_GOST12_256,
- RHASH_GOST12_512
- RHASH_HAS160,
- RHASH_SHA224,
- RHASH_SHA256,
- RHASH_SHA384,
- RHASH_SHA512,
- RHASH_SHA3_224,
- RHASH_SHA3_256,
- RHASH_SHA3_384,
- RHASH_SHA3_512,
- RHASH_EDONR256,
- RHASH_EDONR512,
- RHASH_SNEFRU128,
- RHASH_SNEFRU256
-
-Also the RHASH_ALL bit mask is the union of all listed bit-flags.
-So the object created via Crypt::Rhash->new(RHASH_ALL) calculates all
-supported hash functions for the same data.
-
-=head1 COMPUTING HASHES
-
-=over
-
-=item $rhash->update( $msg )
-
-Calculates hashes of the $msg string.
-The method can be called repeatedly with chunks of the message to be hashed.
-It returns the $rhash object itself allowing the following construction:
-
- $rhash = Crypt::Rhash->new(RHASH_MD5)->update( $chunk1 )->update( $chunk2 );
-
-=item $rhash->update_file( $file_path, $start, $size )
-
-=item $rhash->update_fd( $fd, $start, $size )
-
-Calculate a hash of the file (or its part) specified by $file_path or a file descriptor $fd.
-The update_fd method doesn't close the $fd, leaving the file position after the hashed block.
-The optional $start and $size specify the block of the file to hash.
-No error is reported if the $size is greater than the number of the unread bytes left in the file.
-
-Returns the number of characters actually read, 0 at end of file,
-or undef if there was an error (in the latter case $! is also set).
-
- use Crypt::Rhash;
- my $r = new Crypt::Rhash(RHASH_SHA1);
- open(my $fd, "<", "input.txt") or die "cannot open < input.txt: $!";
- while ((my $n = $r->update_fd($fd, undef, 1024) != 0)) {
- print "$n bytes hashed. The SHA1 hash is " . $r->final()->hash() . "\n";
- $r->reset();
- }
- defined($n) or die "read error for input.txt: $!";
- close($fd);
-
-=item $rhash->final()
-
-Finishes calculation for all data buffered by updating methods and stops hash
-calculation. The function is called automatically by any of the
-$rhash->hash*() methods if the final() call was skipped.
-
-=item $rhash->reset()
-
-Resets the $rhash object to the initial state.
-
-=item $rhash->hashed_length()
-
-Returns the total length of the hashed message.
-
-=item $rhash->hash_id()
-
-Returns the hash mask, the $rhash object was constructed with.
-
-=back
-
-=head1 FORMATTING HASH VALUE
-
-Computed hash can be formatted as a hexadecimal string (in the forward or
-reverse byte order), a base32/base64-encoded string or as raw binary data.
-
-=over
-
-=item $rhash->hash( $hash_id )
-
-Returns the hash string in the default format,
-which can be hexadecimal or base32. Actually the method is equivalent of
-
- (Crypt::Rhash::is_base32($hash_id) ? $rhash->hash_base32($hash_id) :
- $rhash->hash_hex($hash_id))
-
-If the optional $hash_id parameter is omitted or zero, then the method returns the hash
-for the algorithm contained in $rhash with the lowest identifier.
-
-=item $rhash->hash_hex( $hash_id )
-
-Returns the specified hash in the hexadecimal format.
-
- use Crypt::Rhash;
- my $msg = "abc";
- print "MD5 = " . Crypt::Rhash->new(RHASH_MD5)->update($msg)->hash_hex() . "\n";
-
-=item $rhash->hash_rhex( $hash_id )
-
-Returns the specified hash in the hexadecimal format with reversed order of bytes.
-Some programs prefer to output the GOST R 34.11-94 hash in this format.
-
-=item $rhash->hash_base32( $hash_id )
-
-Returns the specified hash in the base32 format.
-
-=item $rhash->hash_base64( $hash_id )
-
-Returns the specified hash in the base64 format.
-
-=item $rhash->magnet_link( $filename, $hash_mask )
-
-Returns the magnet link containing the computed hashes, filesize, and,
-optionaly, $filename. The $filename (if specified) is URL-encoded,
-by converting special characters into the % form.
-The optional parameter $hash_mask can limit which hash values to put
-into the link.
-
-=back
-
-=head1 STATIC METHODS
-
-=over
-
-=item Crypt::Rhash::count()
-
-Returns the number of supported hash algorithms
-
-=item Crypt::Rhash::is_base32($hash_id)
-
-Returns nonzero if default output format is Base32 for the hash function specified by $hash_id.
-Returns zero if default format is hexadecimal.
-
-=item Crypt::Rhash::get_digest_size($hash_id)
-
-Returns the size in bytes of raw binary hash of the specified hash algorithm.
-
-=item Crypt::Rhash::get_hash_length($hash_id)
-
-Returns the length of a hash string in default output format for the specified hash algorithm.
-
-=item Crypt::Rhash::get_name($hash_id)
-
-Returns the name of the specified hash algorithm.
-
-=back
-
-=head1 ALTERNATIVE WAY TO COMPUTE HASH
-
-=over
-
-=item Crypt::Rhash::msg($hash_id, $message)
-
-Computes and returns a single hash (in its default format) of the $message by the selected hash algorithm.
-
- use Crypt::Rhash;
- print "SHA1( 'abc' ) = " . Crypt::Rhash::msg(RHASH_SHA1, "abc") . "\n";
-
-=back
-
-=head1 LICENSE
-
- 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.
-
- The Software 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. Use this program at your own risk!
-
-=cut
+package Crypt::Rhash;
+
+use 5.006001;
+use strict;
+use warnings;
+
+require Exporter;
+our @ISA = (qw(Exporter));
+
+# possible tags for export
+our %EXPORT_TAGS = (
+ Functions => [qw(raw2hex raw2base32 raw2base64)],
+ Constants => [qw(RHASH_CRC32 RHASH_CRC32C RHASH_MD4 RHASH_MD5
+ RHASH_SHA1 RHASH_TIGER RHASH_TTH RHASH_BTIH RHASH_ED2K
+ RHASH_AICH RHASH_WHIRLPOOL RHASH_RIPEMD160 RHASH_GOST94
+ RHASH_GOST94_CRYPTOPRO RHASH_GOST12_256 RHASH_GOST12_512
+ RHASH_SHA224 RHASH_SHA256 RHASH_SHA384 RHASH_SHA512
+ RHASH_SHA3_224 RHASH_SHA3_256 RHASH_SHA3_384 RHASH_SHA3_512
+ RHASH_HAS160 RHASH_EDONR256 RHASH_EDONR512
+ RHASH_SNEFRU128 RHASH_SNEFRU256 RHASH_ALL)]
+);
+
+Exporter::export_tags( );
+Exporter::export_ok_tags( qw(Functions Constants) );
+
+our $VERSION = '0.97';
+
+require XSLoader;
+XSLoader::load('Crypt::Rhash', $VERSION);
+
+##############################################################################
+# ids of hash functions
+use constant RHASH_CRC32 => 0x01;
+use constant RHASH_MD4 => 0x02;
+use constant RHASH_MD5 => 0x04;
+use constant RHASH_SHA1 => 0x08;
+use constant RHASH_TIGER => 0x10;
+use constant RHASH_TTH => 0x20;
+use constant RHASH_BTIH => 0x40;
+use constant RHASH_ED2K => 0x80;
+use constant RHASH_AICH => 0x100;
+use constant RHASH_WHIRLPOOL => 0x200;
+use constant RHASH_RIPEMD160 => 0x400;
+use constant RHASH_GOST94 => 0x800;
+use constant RHASH_GOST94_CRYPTOPRO => 0x1000;
+use constant RHASH_HAS160 => 0x2000;
+use constant RHASH_GOST12_256 => 0x4000;
+use constant RHASH_GOST12_512 => 0x8000;
+use constant RHASH_SHA224 => 0x10000;
+use constant RHASH_SHA256 => 0x20000;
+use constant RHASH_SHA384 => 0x40000;
+use constant RHASH_SHA512 => 0x80000;
+use constant RHASH_EDONR256 => 0x100000;
+use constant RHASH_EDONR512 => 0x200000;
+use constant RHASH_SHA3_224 => 0x0400000;
+use constant RHASH_SHA3_256 => 0x0800000;
+use constant RHASH_SHA3_384 => 0x1000000;
+use constant RHASH_SHA3_512 => 0x2000000;
+use constant RHASH_CRC32C => 0x4000000;
+use constant RHASH_SNEFRU128 => 0x8000000;
+use constant RHASH_SNEFRU256 => 0x10000000;
+use constant RHASH_ALL => 0x1FFFFFFF;
+
+##############################################################################
+# Rhash class methods
+
+# Rhash object constructor
+sub new
+{
+ my $hash_id = $_[1] or die "hash_id not specified";
+ my $context = rhash_init(scalar($hash_id)) or return undef;
+ my $self = {
+ context => $context,
+ };
+ return bless $self;
+}
+
+# destructor
+sub DESTROY($)
+{
+ my $self = shift;
+ # the 'if' added as workaround for perl 'global destruction' bug
+ # ($self->{context} can disappear on global destruction)
+ rhash_free($self->{context}) if $self->{context};
+}
+
+sub update($$)
+{
+ my $self = shift;
+ my $message = shift;
+ rhash_update($self->{context}, $message);
+ return $self;
+}
+
+sub update_fd($$;$$)
+{
+ my ($self, $fd, $start, $size) = @_;
+ my $res = 0;
+ my $num = 0;
+
+ binmode($fd);
+ if(defined($start)) {
+ seek($fd, scalar($start), 0) or return undef;
+ }
+
+ my $data;
+ if(defined($size)) {
+ for(my $left = scalar($size); $left > 0; $left -= 8192) {
+ ($res = read($fd, $data,
+ ($left < 8192 ? $left : 8192))) || last;
+ rhash_update($self->{context}, $data);
+ $num += $res;
+ }
+ } else {
+ while( ($res = read($fd, $data, 8192)) ) {
+ rhash_update($self->{context}, $data);
+ $num += $res;
+ }
+ }
+
+ return (defined($res) ? $num : undef); # return undef on read error
+}
+
+sub update_file($$;$$)
+{
+ my ($self, $file, $start, $size) = @_;
+ open(my $fd, "<", $file) or return undef;
+ my $res = $self->update_fd($fd, $start, $size);
+ close($fd);
+ return $res;
+}
+
+sub final($)
+{
+ my $self = shift;
+ rhash_final($self->{context});
+ return $self;
+}
+
+sub reset($)
+{
+ my $self = shift;
+ rhash_reset($self->{context});
+ return $self;
+}
+
+sub hashed_length($)
+{
+ my $self = shift;
+ return rhash_get_hashed_length($self->{context});
+}
+
+sub hash_id($)
+{
+ my $self = shift;
+ return rhash_get_hash_id($self->{context});
+}
+
+##############################################################################
+# Hash formatting functions
+
+# printing constants
+use constant RHPR_DEFAULT => 0x0;
+use constant RHPR_RAW => 0x1;
+use constant RHPR_HEX => 0x2;
+use constant RHPR_BASE32 => 0x3;
+use constant RHPR_BASE64 => 0x4;
+use constant RHPR_UPPERCASE => 0x8;
+use constant RHPR_REVERSE => 0x10;
+
+sub hash($;$$)
+{
+ my $self = shift;
+ my $hash_id = scalar(shift) || 0;
+ my $print_flags = scalar(shift) || RHPR_DEFAULT;
+ return rhash_print($self->{context}, $hash_id, $print_flags);
+}
+
+sub hash_base32($;$)
+{
+ hash($_[0], $_[1], RHPR_BASE32);
+}
+
+sub hash_base64($;$)
+{
+ hash($_[0], $_[1], RHPR_BASE64);
+}
+
+sub hash_hex($;$)
+{
+ hash($_[0], $_[1], RHPR_HEX);
+}
+
+sub hash_rhex($;$)
+{
+ hash($_[0], $_[1], RHPR_HEX | RHPR_REVERSE);
+}
+
+sub hash_raw($;$)
+{
+ hash($_[0], $_[1], RHPR_RAW);
+}
+
+sub magnet_link($;$$)
+{
+ my ($self, $filename, $hash_mask) = @_;
+ return rhash_print_magnet($self->{context}, $filename, $hash_mask);
+}
+
+our $AUTOLOAD;
+
+# report error if a script called unexisting method/field
+sub AUTOLOAD
+{
+ my ($self, $field, $type, $pkg) = ($_[0], $AUTOLOAD, undef, __PACKAGE__);
+ $field =~ s/.*://;
+ die "function $field does not exist" if $field =~ /^(rhash_|raw2)/;
+ die "no arguments specified to $field()" if !@_;
+ die "the $field() argument is undefined" if !defined $self;
+
+ ($type = ref($self)) && $type eq $pkg || die "the $field() argument is not a $pkg reference";
+ my $text = (exists $self->{$field} ? "is not accessible" : "does not exist");
+ die "the method $field() $text in the class $pkg";
+}
+
+# static functions
+
+sub msg($$)
+{
+ my ($hash_id, $msg) = @_;
+ my $raw = rhash_msg_raw($hash_id, $msg); # get binary hash
+ return (is_base32($hash_id) ? raw2base32($raw) : raw2hex($raw));
+}
+
+1;
+__END__
+# Below is Rhash module documentation in the standard POD format
+
+=head1 NAME
+
+Crypt::Rhash - Compute hash sums and magnet links
+
+=head1 SYNOPSIS
+
+ use Crypt::Rhash;
+
+ my $msg = "a message text";
+ print "MD5 = " . Crypt::Rhash::msg(RHASH_MD5, $msg) . "\n";
+
+ # Calculate two hash functions simultaneously
+ my $r = Crypt::Rhash->new(RHASH_MD5 | RHASH_SHA1);
+ $r->update("a message text")->update(" another message");
+ print "MD5 = " . $r->hash(RHASH_MD5) . "\n";
+ print "SHA1 = " . $r->hash(RHASH_SHA1) . "\n";
+
+=head1 DESCRIPTION
+
+Crypt::Rhash module is an object-oriented interface to the LibRHash library,
+allowing simultaneous calculation of several hash functions for a file or a
+text message.
+
+Resulting hash digest can be obtained in hexadecimal, BASE32, BASE64, raw
+binary format or as a magnet link.
+
+=head1 SUPPORTED ALGORITHMS
+
+The module supports the following hashing algorithms:
+CRC32, CRC32C, MD4, MD5, SHA1, SHA256, SHA512, SHA3, AICH, ED2K, Tiger,
+DC++ TTH, GOST R 34.11-94, GOST R 34.11-2012, BitTorrent BTIH, RIPEMD-160,
+HAS-160, EDON-R 256/512, Whirlpool and Snefru-128/256.
+
+=head1 CONSTRUCTOR
+
+Creates and returns new Crypt::Rhash object.
+
+ my $r = Crypt::Rhash->new($hash_id);
+ my $p = new Crypt::Rhash($hash_id); # alternative way to call the constructor
+
+The $hash_id parameter can be union (via bitwise OR) of any of the following bit-flags:
+
+ RHASH_CRC32,
+ RHASH_CRC32C,
+ RHASH_MD4,
+ RHASH_MD5,
+ RHASH_SHA1,
+ RHASH_TIGER,
+ RHASH_TTH,
+ RHASH_BTIH,
+ RHASH_ED2K,
+ RHASH_AICH,
+ RHASH_WHIRLPOOL,
+ RHASH_RIPEMD160,
+ RHASH_GOST94,
+ RHASH_GOST94_CRYPTOPRO,
+ RHASH_GOST12_256,
+ RHASH_GOST12_512
+ RHASH_HAS160,
+ RHASH_SHA224,
+ RHASH_SHA256,
+ RHASH_SHA384,
+ RHASH_SHA512,
+ RHASH_SHA3_224,
+ RHASH_SHA3_256,
+ RHASH_SHA3_384,
+ RHASH_SHA3_512,
+ RHASH_EDONR256,
+ RHASH_EDONR512,
+ RHASH_SNEFRU128,
+ RHASH_SNEFRU256
+
+Also the RHASH_ALL bit mask is the union of all listed bit-flags.
+So the object created via Crypt::Rhash->new(RHASH_ALL) calculates all
+supported hash functions for the same data.
+
+=head1 COMPUTING HASHES
+
+=over
+
+=item $rhash->update( $msg )
+
+Calculates hashes of the $msg string.
+The method can be called repeatedly with chunks of the message to be hashed.
+It returns the $rhash object itself allowing the following construction:
+
+ $rhash = Crypt::Rhash->new(RHASH_MD5)->update( $chunk1 )->update( $chunk2 );
+
+=item $rhash->update_file( $file_path, $start, $size )
+
+=item $rhash->update_fd( $fd, $start, $size )
+
+Calculate a hash of the file (or its part) specified by $file_path or a file descriptor $fd.
+The update_fd method doesn't close the $fd, leaving the file position after the hashed block.
+The optional $start and $size specify the block of the file to hash.
+No error is reported if the $size is greater than the number of the unread bytes left in the file.
+
+Returns the number of characters actually read, 0 at end of file,
+or undef if there was an error (in the latter case $! is also set).
+
+ use Crypt::Rhash;
+ my $r = new Crypt::Rhash(RHASH_SHA1);
+ open(my $fd, "<", "input.txt") or die "cannot open < input.txt: $!";
+ while ((my $n = $r->update_fd($fd, undef, 1024) != 0)) {
+ print "$n bytes hashed. The SHA1 hash is " . $r->final()->hash() . "\n";
+ $r->reset();
+ }
+ defined($n) or die "read error for input.txt: $!";
+ close($fd);
+
+=item $rhash->final()
+
+Finishes calculation for all data buffered by updating methods and stops hash
+calculation. The function is called automatically by any of the
+$rhash->hash*() methods if the final() call was skipped.
+
+=item $rhash->reset()
+
+Resets the $rhash object to the initial state.
+
+=item $rhash->hashed_length()
+
+Returns the total length of the hashed message.
+
+=item $rhash->hash_id()
+
+Returns the hash mask, the $rhash object was constructed with.
+
+=back
+
+=head1 FORMATTING HASH VALUE
+
+Computed hash can be formatted as a hexadecimal string (in the forward or
+reverse byte order), a base32/base64-encoded string or as raw binary data.
+
+=over
+
+=item $rhash->hash( $hash_id )
+
+Returns the hash string in the default format,
+which can be hexadecimal or base32. Actually the method is equivalent of
+
+ (Crypt::Rhash::is_base32($hash_id) ? $rhash->hash_base32($hash_id) :
+ $rhash->hash_hex($hash_id))
+
+If the optional $hash_id parameter is omitted or zero, then the method returns the hash
+for the algorithm contained in $rhash with the lowest identifier.
+
+=item $rhash->hash_hex( $hash_id )
+
+Returns the specified hash in the hexadecimal format.
+
+ use Crypt::Rhash;
+ my $msg = "abc";
+ print "MD5 = " . Crypt::Rhash->new(RHASH_MD5)->update($msg)->hash_hex() . "\n";
+
+=item $rhash->hash_rhex( $hash_id )
+
+Returns the specified hash in the hexadecimal format with reversed order of bytes.
+Some programs prefer to output the GOST R 34.11-94 hash in this format.
+
+=item $rhash->hash_base32( $hash_id )
+
+Returns the specified hash in the base32 format.
+
+=item $rhash->hash_base64( $hash_id )
+
+Returns the specified hash in the base64 format.
+
+=item $rhash->magnet_link( $filename, $hash_mask )
+
+Returns the magnet link containing the computed hashes, filesize, and,
+optionaly, $filename. The $filename (if specified) is URL-encoded,
+by converting special characters into the % form.
+The optional parameter $hash_mask can limit which hash values to put
+into the link.
+
+=back
+
+=head1 STATIC METHODS
+
+=over
+
+=item Crypt::Rhash::count()
+
+Returns the number of supported hash algorithms
+
+=item Crypt::Rhash::is_base32($hash_id)
+
+Returns nonzero if default output format is Base32 for the hash function specified by $hash_id.
+Returns zero if default format is hexadecimal.
+
+=item Crypt::Rhash::get_digest_size($hash_id)
+
+Returns the size in bytes of raw binary hash of the specified hash algorithm.
+
+=item Crypt::Rhash::get_hash_length($hash_id)
+
+Returns the length of a hash string in default output format for the specified hash algorithm.
+
+=item Crypt::Rhash::get_name($hash_id)
+
+Returns the name of the specified hash algorithm.
+
+=back
+
+=head1 ALTERNATIVE WAY TO COMPUTE HASH
+
+=over
+
+=item Crypt::Rhash::msg($hash_id, $message)
+
+Computes and returns a single hash (in its default format) of the $message by the selected hash algorithm.
+
+ use Crypt::Rhash;
+ print "SHA1( 'abc' ) = " . Crypt::Rhash::msg(RHASH_SHA1, "abc") . "\n";
+
+=back
+
+=head1 LICENSE
+
+ 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.
+
+ The Software 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. Use this program at your own risk!
+
+=cut
diff --git a/bindings/perl/Rhash.xs b/bindings/perl/Rhash.xs
index f62a140f..56d5ece8 100644
--- a/bindings/perl/Rhash.xs
+++ b/bindings/perl/Rhash.xs
@@ -1,322 +1,322 @@
-#include "EXTERN.h"
-#include "perl.h"
-#include "XSUB.h"
-
-#include
-#include
-
-typedef unsigned long long ulonglong;
-
-/* helper macros and functions */
-#define BASE32_LENGTH(size) (((size) * 8 + 4) / 5)
-#define BASE64_LENGTH(size) ((((size) + 2) / 3) * 4)
-
-void verify_single_bit_hash_id(unsigned hash_id, CV* cv)
-{
- const char* error;
- const GV *gv;
- const char *func_name;
-
- if(0 == (hash_id & RHASH_ALL_HASHES)) {
- error = "%s: unsupported hash_id = 0x%x";
- } else if(0 != (hash_id & (hash_id - 1))) {
- error = "%s: hash_id is not a single bit: 0x%x";
- } else {
- return; /* success */
- }
-
- gv = CvGV(cv);
- func_name = (gv ? GvNAME(gv) : "Rhash");
- croak(error, func_name, hash_id);
-}
-
-/* allocate a perl string scalar variable, containing str_len + 1 bytes */
-SV * allocate_string_buffer(STRLEN str_len)
-{
- SV * sv = newSV(str_len); /* allocates (str_len + 1) bytes */
- SvPOK_only(sv);
- SvCUR_set(sv, str_len);
- return sv;
-}
-
-MODULE = Crypt::Rhash PACKAGE = Crypt::Rhash
-
-##############################################################################
-# Initialize LibRHash in the module bootstrap function
-
-BOOT:
- rhash_library_init();
-
-##############################################################################
-# perl bindings for Hi-level functions
-
-SV *
-rhash_msg_raw(hash_id, message)
- unsigned hash_id
- PROTOTYPE: $$
- PREINIT:
- STRLEN length;
- unsigned char out[264];
- int res;
- INPUT:
- char* message = SvPV(ST(1), length);
- CODE:
- verify_single_bit_hash_id(hash_id, cv);
- res = rhash_msg(hash_id, message, length, out);
- if(res < 0) {
- croak("%s: %s", "rhash_msg_raw", strerror(errno));
- }
- RETVAL = newSVpv((char*)out, rhash_get_digest_size(hash_id));
- OUTPUT:
- RETVAL
-
-SV *
-rhash_file_raw(hash_id, filepath)
- unsigned hash_id
- char * filepath
- PROTOTYPE: $$
- PREINIT:
- int res;
- unsigned char out[264];
- CODE:
- verify_single_bit_hash_id(hash_id, cv);
- res = rhash_file(hash_id, filepath, out);
- if(res < 0) {
- croak("%s: %s: %s", "rhash_file", filepath, strerror(errno));
- }
- RETVAL = newSVpv((char*)out, rhash_get_digest_size(hash_id));
- OUTPUT:
- RETVAL
-
-##############################################################################
-# perl bindings for Low-level functions
-
-rhash_context *
-rhash_init(hash_id)
- unsigned hash_id
- PROTOTYPE: $
-
-int
-rhash_update(ctx, message)
- rhash_context * ctx
- PROTOTYPE: $$
- PREINIT:
- STRLEN length;
- INPUT:
- char* message = SvPV(ST(1), length);
- CODE:
- RETVAL = rhash_update(ctx, message, length);
- OUTPUT:
- RETVAL
-
-int
-rhash_final(ctx)
- rhash_context * ctx
- PROTOTYPE: $
- CODE:
- RETVAL = rhash_final(ctx, 0);
- OUTPUT:
- RETVAL
-
-void
-rhash_reset(ctx)
- rhash_context * ctx
- PROTOTYPE: $
-
-void
-rhash_free(ctx)
- rhash_context * ctx
- PROTOTYPE: $
-
-SV *
-rhash_print(ctx, hash_id, flags = 0)
- rhash_context * ctx
- unsigned hash_id
- int flags
- PROTOTYPE: $$;$
- PREINIT:
- int len;
- char out[264];
- CODE:
- if(hash_id != 0) verify_single_bit_hash_id(hash_id, cv);
-
- len = rhash_print(out, ctx, hash_id, flags);
-
- /* set exact length to support raw output (RHPR_RAW) */
- RETVAL = newSVpv(out, len);
- OUTPUT:
- RETVAL
-
-SV *
-rhash_print_magnet(ctx, filename, hash_mask)
- rhash_context * ctx
- SV * filename
- SV * hash_mask
- PROTOTYPE: $;$$
- PREINIT:
- /* process undefined values */
- char * name = (SvOK(filename) ? SvPV_nolen(filename) : 0);
- unsigned mask = (SvOK(hash_mask) ? (unsigned)SvUV(hash_mask) : RHASH_ALL_HASHES);
- size_t buf_size;
- CODE:
- /* allocate a string buffer and print magnet link into it */
- buf_size = rhash_print_magnet(0, name, ctx, mask, RHPR_FILESIZE);
- RETVAL = allocate_string_buffer(buf_size - 1);
- rhash_print_magnet(SvPVX(RETVAL), name, ctx, mask, RHPR_FILESIZE);
-
- /* note: length(RETVAL) = (buf_size - 1),
- * so the following call is not required:
- * SvCUR_set(RETVAL, strlen(SvPVX(RETVAL))); */
- OUTPUT:
- RETVAL
-
-unsigned
-rhash_get_hash_id(ctx)
- rhash_context * ctx
- PROTOTYPE: $
- CODE:
- RETVAL = ctx->hash_id;
- OUTPUT:
- RETVAL
-
-ulonglong
-rhash_get_hashed_length(ctx)
- rhash_context * ctx
- PROTOTYPE: $
- CODE:
- RETVAL = ctx->msg_size;
- OUTPUT:
- RETVAL
-
-##############################################################################
-# Hash information functions
-
-int
-count()
- CODE:
- RETVAL = rhash_count();
- OUTPUT:
- RETVAL
-
-int
-is_base32(hash_id)
- unsigned hash_id
- PROTOTYPE: $
- CODE:
- RETVAL = rhash_is_base32(hash_id);
- OUTPUT:
- RETVAL
-
-int
-get_digest_size(hash_id)
- unsigned hash_id
- PROTOTYPE: $
- CODE:
- RETVAL = rhash_get_digest_size(hash_id);
- OUTPUT:
- RETVAL
-
-int
-get_hash_length(hash_id)
- unsigned hash_id
- PROTOTYPE: $
- CODE:
- RETVAL = rhash_get_hash_length(hash_id);
- OUTPUT:
- RETVAL
-
-const char *
-get_name(hash_id)
- unsigned hash_id
- PROTOTYPE: $
- CODE:
- RETVAL = rhash_get_name(hash_id);
- OUTPUT:
- RETVAL
-
-##############################################################################
-# Hash printing functions
-
-##############################################################################
-# Hash conversion functions
-
-SV *
-raw2hex(bytes)
- PROTOTYPE: $
- PREINIT:
- STRLEN size;
- INPUT:
- unsigned char * bytes = (unsigned char*)SvPV(ST(0), size);
- CODE:
- RETVAL = allocate_string_buffer(size * 2);
- rhash_print_bytes(SvPVX(RETVAL), bytes, size, RHPR_HEX);
- OUTPUT:
- RETVAL
-
-SV *
-raw2base32(bytes)
- PROTOTYPE: $
- PREINIT:
- STRLEN size;
- INPUT:
- unsigned char * bytes = (unsigned char*)SvPV(ST(0), size);
- CODE:
- RETVAL = allocate_string_buffer(BASE32_LENGTH(size));
- rhash_print_bytes(SvPVX(RETVAL), bytes, size, RHPR_BASE32);
- OUTPUT:
- RETVAL
-
-SV *
-raw2base64(bytes)
- PROTOTYPE: $
- PREINIT:
- STRLEN size;
- INPUT:
- unsigned char * bytes = (unsigned char*)SvPV(ST(0), size);
- CODE:
- RETVAL = allocate_string_buffer(BASE64_LENGTH(size));
- rhash_print_bytes(SvPVX(RETVAL), bytes, size, RHPR_BASE64);
- OUTPUT:
- RETVAL
-
-##############################################################################
-# BTIH / BitTorrent support functions
-
-void
-rhash_bt_add_filename(ctx, filename, filesize)
- rhash_context * ctx
- char * filename
- ulonglong filesize
- PROTOTYPE: $$$
- CODE:
- rhash_torrent_add_file(ctx, filename, filesize);
-
-void
-rhash_bt_set_piece_length(ctx, piece_length)
- rhash_context * ctx
- unsigned piece_length
- PROTOTYPE: $$
- CODE:
- rhash_torrent_set_piece_length(ctx, piece_length);
-
-void
-rhash_bt_set_private(ctx)
- rhash_context * ctx
- PROTOTYPE: $
- CODE:
- rhash_torrent_set_options(ctx, RHASH_TORRENT_OPT_PRIVATE);
-
-SV *
-rhash_bt_get_torrent_text(ctx)
- rhash_context * ctx
- PROTOTYPE: $
- PREINIT:
- const rhash_str* text;
- CODE:
- text = rhash_torrent_generate_content(ctx);
- if(!text) {
- XSRETURN_UNDEF;
- }
- RETVAL = newSVpv(text->str, text->length);
- OUTPUT:
- RETVAL
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include
+#include
+
+typedef unsigned long long ulonglong;
+
+/* helper macros and functions */
+#define BASE32_LENGTH(size) (((size) * 8 + 4) / 5)
+#define BASE64_LENGTH(size) ((((size) + 2) / 3) * 4)
+
+void verify_single_bit_hash_id(unsigned hash_id, CV* cv)
+{
+ const char* error;
+ const GV *gv;
+ const char *func_name;
+
+ if(0 == (hash_id & RHASH_ALL_HASHES)) {
+ error = "%s: unsupported hash_id = 0x%x";
+ } else if(0 != (hash_id & (hash_id - 1))) {
+ error = "%s: hash_id is not a single bit: 0x%x";
+ } else {
+ return; /* success */
+ }
+
+ gv = CvGV(cv);
+ func_name = (gv ? GvNAME(gv) : "Rhash");
+ croak(error, func_name, hash_id);
+}
+
+/* allocate a perl string scalar variable, containing str_len + 1 bytes */
+SV * allocate_string_buffer(STRLEN str_len)
+{
+ SV * sv = newSV(str_len); /* allocates (str_len + 1) bytes */
+ SvPOK_only(sv);
+ SvCUR_set(sv, str_len);
+ return sv;
+}
+
+MODULE = Crypt::Rhash PACKAGE = Crypt::Rhash
+
+##############################################################################
+# Initialize LibRHash in the module bootstrap function
+
+BOOT:
+ rhash_library_init();
+
+##############################################################################
+# perl bindings for Hi-level functions
+
+SV *
+rhash_msg_raw(hash_id, message)
+ unsigned hash_id
+ PROTOTYPE: $$
+ PREINIT:
+ STRLEN length;
+ unsigned char out[264];
+ int res;
+ INPUT:
+ char* message = SvPV(ST(1), length);
+ CODE:
+ verify_single_bit_hash_id(hash_id, cv);
+ res = rhash_msg(hash_id, message, length, out);
+ if(res < 0) {
+ croak("%s: %s", "rhash_msg_raw", strerror(errno));
+ }
+ RETVAL = newSVpv((char*)out, rhash_get_digest_size(hash_id));
+ OUTPUT:
+ RETVAL
+
+SV *
+rhash_file_raw(hash_id, filepath)
+ unsigned hash_id
+ char * filepath
+ PROTOTYPE: $$
+ PREINIT:
+ int res;
+ unsigned char out[264];
+ CODE:
+ verify_single_bit_hash_id(hash_id, cv);
+ res = rhash_file(hash_id, filepath, out);
+ if(res < 0) {
+ croak("%s: %s: %s", "rhash_file", filepath, strerror(errno));
+ }
+ RETVAL = newSVpv((char*)out, rhash_get_digest_size(hash_id));
+ OUTPUT:
+ RETVAL
+
+##############################################################################
+# perl bindings for Low-level functions
+
+rhash_context *
+rhash_init(hash_id)
+ unsigned hash_id
+ PROTOTYPE: $
+
+int
+rhash_update(ctx, message)
+ rhash_context * ctx
+ PROTOTYPE: $$
+ PREINIT:
+ STRLEN length;
+ INPUT:
+ char* message = SvPV(ST(1), length);
+ CODE:
+ RETVAL = rhash_update(ctx, message, length);
+ OUTPUT:
+ RETVAL
+
+int
+rhash_final(ctx)
+ rhash_context * ctx
+ PROTOTYPE: $
+ CODE:
+ RETVAL = rhash_final(ctx, 0);
+ OUTPUT:
+ RETVAL
+
+void
+rhash_reset(ctx)
+ rhash_context * ctx
+ PROTOTYPE: $
+
+void
+rhash_free(ctx)
+ rhash_context * ctx
+ PROTOTYPE: $
+
+SV *
+rhash_print(ctx, hash_id, flags = 0)
+ rhash_context * ctx
+ unsigned hash_id
+ int flags
+ PROTOTYPE: $$;$
+ PREINIT:
+ int len;
+ char out[264];
+ CODE:
+ if(hash_id != 0) verify_single_bit_hash_id(hash_id, cv);
+
+ len = rhash_print(out, ctx, hash_id, flags);
+
+ /* set exact length to support raw output (RHPR_RAW) */
+ RETVAL = newSVpv(out, len);
+ OUTPUT:
+ RETVAL
+
+SV *
+rhash_print_magnet(ctx, filename, hash_mask)
+ rhash_context * ctx
+ SV * filename
+ SV * hash_mask
+ PROTOTYPE: $;$$
+ PREINIT:
+ /* process undefined values */
+ char * name = (SvOK(filename) ? SvPV_nolen(filename) : 0);
+ unsigned mask = (SvOK(hash_mask) ? (unsigned)SvUV(hash_mask) : RHASH_ALL_HASHES);
+ size_t buf_size;
+ CODE:
+ /* allocate a string buffer and print magnet link into it */
+ buf_size = rhash_print_magnet(0, name, ctx, mask, RHPR_FILESIZE);
+ RETVAL = allocate_string_buffer(buf_size - 1);
+ rhash_print_magnet(SvPVX(RETVAL), name, ctx, mask, RHPR_FILESIZE);
+
+ /* note: length(RETVAL) = (buf_size - 1),
+ * so the following call is not required:
+ * SvCUR_set(RETVAL, strlen(SvPVX(RETVAL))); */
+ OUTPUT:
+ RETVAL
+
+unsigned
+rhash_get_hash_id(ctx)
+ rhash_context * ctx
+ PROTOTYPE: $
+ CODE:
+ RETVAL = ctx->hash_id;
+ OUTPUT:
+ RETVAL
+
+ulonglong
+rhash_get_hashed_length(ctx)
+ rhash_context * ctx
+ PROTOTYPE: $
+ CODE:
+ RETVAL = ctx->msg_size;
+ OUTPUT:
+ RETVAL
+
+##############################################################################
+# Hash information functions
+
+int
+count()
+ CODE:
+ RETVAL = rhash_count();
+ OUTPUT:
+ RETVAL
+
+int
+is_base32(hash_id)
+ unsigned hash_id
+ PROTOTYPE: $
+ CODE:
+ RETVAL = rhash_is_base32(hash_id);
+ OUTPUT:
+ RETVAL
+
+int
+get_digest_size(hash_id)
+ unsigned hash_id
+ PROTOTYPE: $
+ CODE:
+ RETVAL = rhash_get_digest_size(hash_id);
+ OUTPUT:
+ RETVAL
+
+int
+get_hash_length(hash_id)
+ unsigned hash_id
+ PROTOTYPE: $
+ CODE:
+ RETVAL = rhash_get_hash_length(hash_id);
+ OUTPUT:
+ RETVAL
+
+const char *
+get_name(hash_id)
+ unsigned hash_id
+ PROTOTYPE: $
+ CODE:
+ RETVAL = rhash_get_name(hash_id);
+ OUTPUT:
+ RETVAL
+
+##############################################################################
+# Hash printing functions
+
+##############################################################################
+# Hash conversion functions
+
+SV *
+raw2hex(bytes)
+ PROTOTYPE: $
+ PREINIT:
+ STRLEN size;
+ INPUT:
+ unsigned char * bytes = (unsigned char*)SvPV(ST(0), size);
+ CODE:
+ RETVAL = allocate_string_buffer(size * 2);
+ rhash_print_bytes(SvPVX(RETVAL), bytes, size, RHPR_HEX);
+ OUTPUT:
+ RETVAL
+
+SV *
+raw2base32(bytes)
+ PROTOTYPE: $
+ PREINIT:
+ STRLEN size;
+ INPUT:
+ unsigned char * bytes = (unsigned char*)SvPV(ST(0), size);
+ CODE:
+ RETVAL = allocate_string_buffer(BASE32_LENGTH(size));
+ rhash_print_bytes(SvPVX(RETVAL), bytes, size, RHPR_BASE32);
+ OUTPUT:
+ RETVAL
+
+SV *
+raw2base64(bytes)
+ PROTOTYPE: $
+ PREINIT:
+ STRLEN size;
+ INPUT:
+ unsigned char * bytes = (unsigned char*)SvPV(ST(0), size);
+ CODE:
+ RETVAL = allocate_string_buffer(BASE64_LENGTH(size));
+ rhash_print_bytes(SvPVX(RETVAL), bytes, size, RHPR_BASE64);
+ OUTPUT:
+ RETVAL
+
+##############################################################################
+# BTIH / BitTorrent support functions
+
+void
+rhash_bt_add_filename(ctx, filename, filesize)
+ rhash_context * ctx
+ char * filename
+ ulonglong filesize
+ PROTOTYPE: $$$
+ CODE:
+ rhash_torrent_add_file(ctx, filename, filesize);
+
+void
+rhash_bt_set_piece_length(ctx, piece_length)
+ rhash_context * ctx
+ unsigned piece_length
+ PROTOTYPE: $$
+ CODE:
+ rhash_torrent_set_piece_length(ctx, piece_length);
+
+void
+rhash_bt_set_private(ctx)
+ rhash_context * ctx
+ PROTOTYPE: $
+ CODE:
+ rhash_torrent_set_options(ctx, RHASH_TORRENT_OPT_PRIVATE);
+
+SV *
+rhash_bt_get_torrent_text(ctx)
+ rhash_context * ctx
+ PROTOTYPE: $
+ PREINIT:
+ const rhash_str* text;
+ CODE:
+ text = rhash_torrent_generate_content(ctx);
+ if(!text) {
+ XSRETURN_UNDEF;
+ }
+ RETVAL = newSVpv(text->str, text->length);
+ OUTPUT:
+ RETVAL
diff --git a/bindings/perl/t/1test_hash_calculation.t b/bindings/perl/t/1test_hash_calculation.t
index 2df696e9..e3263895 100644
--- a/bindings/perl/t/1test_hash_calculation.t
+++ b/bindings/perl/t/1test_hash_calculation.t
@@ -1,61 +1,61 @@
-use Test::More tests => 22;
-BEGIN { use_ok('Crypt::Rhash') };
-
-#########################
-# test script
-
-$msg = "message digest";
-
-ok( $r = new Crypt::Rhash(RHASH_MD5 | RHASH_TTH));
-ok( $r->update($msg) );
-
-is( $r->hash(), "f96b697d7cb7938d525a2f31aaf161d0"); # prints the first hash by default
-is( $r->hash(RHASH_TTH), "ym432msox5qilih2l4tno62e3o35wygwsbsjoba");
-is( $r->hash_hex(RHASH_TTH), "c339bd324ebf6085a0fa5f26d77b44dbb7db60d690649704");
-is( $r->hash_hex(RHASH_MD5), "f96b697d7cb7938d525a2f31aaf161d0");
-is( $r->hash_rhex(RHASH_MD5), "d061f1aa312f5a528d93b77c7d696bf9");
-is( $r->hash_base32(RHASH_MD5), "7fvws7l4w6jy2us2f4y2v4lb2a");
-#is( $r->hash_base64(RHASH_MD5), "+WtpfXy3k41SWi8xqvFh0A=");
-is( $r->hash_raw(RHASH_MD5), "\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d\x52\x5a\x2f\x31\xaa\xf1\x61\xd0");
-is( $r->reset()->hash(), "d41d8cd98f00b204e9800998ecf8427e");
-
-is( $r->hashed_length(), length($msg));
-is( $r->hash_id(), (RHASH_MD5 | RHASH_TTH));
-$r = undef; # destruct the Rhash object
-
-#########################
-# test hashing a file
-
-$file = "msg.txt";
-open FILE, ">$file" or die $!;
-binmode FILE;
-print FILE $msg;
-close FILE;
-
-$r = new Crypt::Rhash(RHASH_MD5);
-is( $r->update_file($file), 14);
-is( $r->hash(), "f96b697d7cb7938d525a2f31aaf161d0");
-#print "MD5 (\"$msg\") = ". $r->update_file($file)->hash() . "\n";
-
-is( $r->reset()->update_file($file, 4, 1), 1);
-is( $r->hash(), "0cc175b9c0f1b6a831c399e269772661");
-
-open $fd, "<$file" or die $!;
-binmode $fd;
-is( $r->reset()->update_fd($fd), 14);
-is( $r->hash(), "f96b697d7cb7938d525a2f31aaf161d0");
-close $fd;
-unlink($file);
-
-#########################
-# test magnet_link() method
-$r = new Crypt::Rhash(RHASH_ALL);
-$r->update("a")->final();
-is( $r->magnet_link("test.txt", RHASH_MD5 | RHASH_SHA1), "magnet:?xl=1&dn=test.txt&xt=urn:md5:0cc175b9c0f1b6a831c399e269772661&xt=urn:sha1:q336in72uwt7zyk5dxolt2xk5i3xmz5y");
-is( $r->magnet_link(undef, RHASH_ED2K | RHASH_AICH | RHASH_TTH), "magnet:?xl=1&xt=urn:ed2k:bde52cb31de33e46245e05fbdbd6fb24&xt=urn:aich:q336in72uwt7zyk5dxolt2xk5i3xmz5y&xt=urn:tree:tiger:czquwh3iyxbf5l3bgyugzhassmxu647ip2ike4y");
-
-$r = new Crypt::Rhash(RHASH_CRC32 | RHASH_MD4);
-$r->update("abc")->final();
-is( $r->magnet_link(), "magnet:?xl=3&xt=urn:crc32:352441c2&xt=urn:md4:a448017aaf21d8525fc10ae87aa6729d");
-
-__END__
+use Test::More tests => 22;
+BEGIN { use_ok('Crypt::Rhash') };
+
+#########################
+# test script
+
+$msg = "message digest";
+
+ok( $r = new Crypt::Rhash(RHASH_MD5 | RHASH_TTH));
+ok( $r->update($msg) );
+
+is( $r->hash(), "f96b697d7cb7938d525a2f31aaf161d0"); # prints the first hash by default
+is( $r->hash(RHASH_TTH), "ym432msox5qilih2l4tno62e3o35wygwsbsjoba");
+is( $r->hash_hex(RHASH_TTH), "c339bd324ebf6085a0fa5f26d77b44dbb7db60d690649704");
+is( $r->hash_hex(RHASH_MD5), "f96b697d7cb7938d525a2f31aaf161d0");
+is( $r->hash_rhex(RHASH_MD5), "d061f1aa312f5a528d93b77c7d696bf9");
+is( $r->hash_base32(RHASH_MD5), "7fvws7l4w6jy2us2f4y2v4lb2a");
+#is( $r->hash_base64(RHASH_MD5), "+WtpfXy3k41SWi8xqvFh0A=");
+is( $r->hash_raw(RHASH_MD5), "\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d\x52\x5a\x2f\x31\xaa\xf1\x61\xd0");
+is( $r->reset()->hash(), "d41d8cd98f00b204e9800998ecf8427e");
+
+is( $r->hashed_length(), length($msg));
+is( $r->hash_id(), (RHASH_MD5 | RHASH_TTH));
+$r = undef; # destruct the Rhash object
+
+#########################
+# test hashing a file
+
+$file = "msg.txt";
+open FILE, ">$file" or die $!;
+binmode FILE;
+print FILE $msg;
+close FILE;
+
+$r = new Crypt::Rhash(RHASH_MD5);
+is( $r->update_file($file), 14);
+is( $r->hash(), "f96b697d7cb7938d525a2f31aaf161d0");
+#print "MD5 (\"$msg\") = ". $r->update_file($file)->hash() . "\n";
+
+is( $r->reset()->update_file($file, 4, 1), 1);
+is( $r->hash(), "0cc175b9c0f1b6a831c399e269772661");
+
+open $fd, "<$file" or die $!;
+binmode $fd;
+is( $r->reset()->update_fd($fd), 14);
+is( $r->hash(), "f96b697d7cb7938d525a2f31aaf161d0");
+close $fd;
+unlink($file);
+
+#########################
+# test magnet_link() method
+$r = new Crypt::Rhash(RHASH_ALL);
+$r->update("a")->final();
+is( $r->magnet_link("test.txt", RHASH_MD5 | RHASH_SHA1), "magnet:?xl=1&dn=test.txt&xt=urn:md5:0cc175b9c0f1b6a831c399e269772661&xt=urn:sha1:q336in72uwt7zyk5dxolt2xk5i3xmz5y");
+is( $r->magnet_link(undef, RHASH_ED2K | RHASH_AICH | RHASH_TTH), "magnet:?xl=1&xt=urn:ed2k:bde52cb31de33e46245e05fbdbd6fb24&xt=urn:aich:q336in72uwt7zyk5dxolt2xk5i3xmz5y&xt=urn:tree:tiger:czquwh3iyxbf5l3bgyugzhassmxu647ip2ike4y");
+
+$r = new Crypt::Rhash(RHASH_CRC32 | RHASH_MD4);
+$r->update("abc")->final();
+is( $r->magnet_link(), "magnet:?xl=3&xt=urn:crc32:352441c2&xt=urn:md4:a448017aaf21d8525fc10ae87aa6729d");
+
+__END__
diff --git a/bindings/perl/t/2test_static_functions.t b/bindings/perl/t/2test_static_functions.t
index d55f1105..93da3963 100644
--- a/bindings/perl/t/2test_static_functions.t
+++ b/bindings/perl/t/2test_static_functions.t
@@ -1,23 +1,23 @@
-use Test::More tests => 11;
-use Crypt::Rhash;# qw( :Functions );
-
-#########################
-# Rhash module static functions
-
-ok(RHASH_CRC32 > 0);
-ok(&Crypt::Rhash::count() > 0);
-is(&Crypt::Rhash::get_digest_size(RHASH_CRC32), 4);
-is(&Crypt::Rhash::get_hash_length(RHASH_CRC32), 8);
-is(&Crypt::Rhash::is_base32(RHASH_CRC32), 0);
-is(&Crypt::Rhash::is_base32(RHASH_TTH), 1);
-is(&Crypt::Rhash::get_name(RHASH_CRC32), "CRC32");
-
-# test conversion functions
-is(&raw2hex("test msg"), "74657374206d7367");
-is(&raw2base32("test msg"), "orsxg5banvzwo");
-is(&raw2base64("test msg"), "dGVzdCBtc2c=");
-
-$msg = "message digest";
-
-# test msg() hashing method
-is(&Crypt::Rhash::msg(RHASH_MD5, $msg), "f96b697d7cb7938d525a2f31aaf161d0");
+use Test::More tests => 11;
+use Crypt::Rhash;# qw( :Functions );
+
+#########################
+# Rhash module static functions
+
+ok(RHASH_CRC32 > 0);
+ok(&Crypt::Rhash::count() > 0);
+is(&Crypt::Rhash::get_digest_size(RHASH_CRC32), 4);
+is(&Crypt::Rhash::get_hash_length(RHASH_CRC32), 8);
+is(&Crypt::Rhash::is_base32(RHASH_CRC32), 0);
+is(&Crypt::Rhash::is_base32(RHASH_TTH), 1);
+is(&Crypt::Rhash::get_name(RHASH_CRC32), "CRC32");
+
+# test conversion functions
+is(&raw2hex("test msg"), "74657374206d7367");
+is(&raw2base32("test msg"), "orsxg5banvzwo");
+is(&raw2base64("test msg"), "dGVzdCBtc2c=");
+
+$msg = "message digest";
+
+# test msg() hashing method
+is(&Crypt::Rhash::msg(RHASH_MD5, $msg), "f96b697d7cb7938d525a2f31aaf161d0");
diff --git a/bindings/perl/t/3test_all_hash_functions.t b/bindings/perl/t/3test_all_hash_functions.t
index 964fa557..fecd3afc 100644
--- a/bindings/perl/t/3test_all_hash_functions.t
+++ b/bindings/perl/t/3test_all_hash_functions.t
@@ -1,39 +1,39 @@
-use Test::More tests => 29;
-use Crypt::Rhash;
-
-#########################
-
-$r = new Crypt::Rhash(RHASH_ALL);
-$r->update("a")->final();
-
-is( $r->hash(RHASH_CRC32), "e8b7be43");
-is( $r->hash(RHASH_CRC32C), "c1d04330");
-is( $r->hash(RHASH_MD4), "bde52cb31de33e46245e05fbdbd6fb24");
-is( $r->hash(RHASH_MD5), "0cc175b9c0f1b6a831c399e269772661");
-is( $r->hash(RHASH_SHA1), "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8");
-is( $r->hash(RHASH_TIGER), "77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809");
-is( $r->hash(RHASH_TTH), "czquwh3iyxbf5l3bgyugzhassmxu647ip2ike4y");
-is( length($r->hash(RHASH_BTIH)), 40);
-is( $r->hash(RHASH_ED2K), "bde52cb31de33e46245e05fbdbd6fb24");
-is( $r->hash(RHASH_AICH), "q336in72uwt7zyk5dxolt2xk5i3xmz5y");
-is( $r->hash(RHASH_WHIRLPOOL), "8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a");
-is( $r->hash(RHASH_RIPEMD160), "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe");
-is( $r->hash(RHASH_GOST94), "d42c539e367c66e9c88a801f6649349c21871b4344c6a573f849fdce62f314dd");
-is( $r->hash(RHASH_GOST94_CRYPTOPRO), "e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011");
-is( $r->hash(RHASH_GOST12_256), "ba31099b9cc84ec2a671e9313572378920a705b363b031a1cb4fc03e01ce8df3");
-is( $r->hash(RHASH_GOST12_512), "8b2a40ecab7b7496bc4cc0f773595452baf658849b495acc3ba017206810efb00420ccd73fb3297e0f7890941b84ac4a8bc27e3c95e1f97c094609e2136abb7e");
-is( $r->hash(RHASH_HAS160), "4872bcbc4cd0f0a9dc7c2f7045e5b43b6c830db8");
-is( $r->hash(RHASH_SHA224), "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5");
-is( $r->hash(RHASH_SHA256), "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb");
-is( $r->hash(RHASH_SHA384), "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31");
-is( $r->hash(RHASH_SHA512), "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75");
-is( $r->hash(RHASH_EDONR256), "943aa9225a2cf154ec2e4dd81237720ba538ca8df2fd83c0b893c5d265f353a0");
-is( $r->hash(RHASH_EDONR512), "b59ec44f7beef8a04ceed38a973d77c65e22e9458d5f67b497948da34986c093b5efc5483fbee55f2f740fcad31f18d80db44bb6b8843e7fd599188e7c07233b");
-is( $r->hash(RHASH_SHA3_224), "9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b");
-is( $r->hash(RHASH_SHA3_256), "80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b");
-is( $r->hash(RHASH_SHA3_384), "1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9");
-is( $r->hash(RHASH_SHA3_512), "697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a");
-is( $r->hash(RHASH_SNEFRU128), "bf5ce540ae51bc50399f96746c5a15bd");
-is( $r->hash(RHASH_SNEFRU256), "45161589ac317be0ceba70db2573ddda6e668a31984b39bf65e4b664b584c63d");
-
-__END__
+use Test::More tests => 29;
+use Crypt::Rhash;
+
+#########################
+
+$r = new Crypt::Rhash(RHASH_ALL);
+$r->update("a")->final();
+
+is( $r->hash(RHASH_CRC32), "e8b7be43");
+is( $r->hash(RHASH_CRC32C), "c1d04330");
+is( $r->hash(RHASH_MD4), "bde52cb31de33e46245e05fbdbd6fb24");
+is( $r->hash(RHASH_MD5), "0cc175b9c0f1b6a831c399e269772661");
+is( $r->hash(RHASH_SHA1), "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8");
+is( $r->hash(RHASH_TIGER), "77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809");
+is( $r->hash(RHASH_TTH), "czquwh3iyxbf5l3bgyugzhassmxu647ip2ike4y");
+is( length($r->hash(RHASH_BTIH)), 40);
+is( $r->hash(RHASH_ED2K), "bde52cb31de33e46245e05fbdbd6fb24");
+is( $r->hash(RHASH_AICH), "q336in72uwt7zyk5dxolt2xk5i3xmz5y");
+is( $r->hash(RHASH_WHIRLPOOL), "8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a");
+is( $r->hash(RHASH_RIPEMD160), "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe");
+is( $r->hash(RHASH_GOST94), "d42c539e367c66e9c88a801f6649349c21871b4344c6a573f849fdce62f314dd");
+is( $r->hash(RHASH_GOST94_CRYPTOPRO), "e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011");
+is( $r->hash(RHASH_GOST12_256), "ba31099b9cc84ec2a671e9313572378920a705b363b031a1cb4fc03e01ce8df3");
+is( $r->hash(RHASH_GOST12_512), "8b2a40ecab7b7496bc4cc0f773595452baf658849b495acc3ba017206810efb00420ccd73fb3297e0f7890941b84ac4a8bc27e3c95e1f97c094609e2136abb7e");
+is( $r->hash(RHASH_HAS160), "4872bcbc4cd0f0a9dc7c2f7045e5b43b6c830db8");
+is( $r->hash(RHASH_SHA224), "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5");
+is( $r->hash(RHASH_SHA256), "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb");
+is( $r->hash(RHASH_SHA384), "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31");
+is( $r->hash(RHASH_SHA512), "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75");
+is( $r->hash(RHASH_EDONR256), "943aa9225a2cf154ec2e4dd81237720ba538ca8df2fd83c0b893c5d265f353a0");
+is( $r->hash(RHASH_EDONR512), "b59ec44f7beef8a04ceed38a973d77c65e22e9458d5f67b497948da34986c093b5efc5483fbee55f2f740fcad31f18d80db44bb6b8843e7fd599188e7c07233b");
+is( $r->hash(RHASH_SHA3_224), "9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b");
+is( $r->hash(RHASH_SHA3_256), "80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b");
+is( $r->hash(RHASH_SHA3_384), "1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9");
+is( $r->hash(RHASH_SHA3_512), "697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a");
+is( $r->hash(RHASH_SNEFRU128), "bf5ce540ae51bc50399f96746c5a15bd");
+is( $r->hash(RHASH_SNEFRU256), "45161589ac317be0ceba70db2573ddda6e668a31984b39bf65e4b664b584c63d");
+
+__END__
diff --git a/bindings/perl/typemap b/bindings/perl/typemap
index 63b07fdf..9f16a75c 100644
--- a/bindings/perl/typemap
+++ b/bindings/perl/typemap
@@ -1,4 +1,4 @@
-rhash_context * T_PTROBJ
-rhash_uptr_t T_NV
-ulonglong T_NV
-const char * T_PV
+rhash_context * T_PTROBJ
+rhash_uptr_t T_NV
+ulonglong T_NV
+const char * T_PV
diff --git a/bindings/php/config.m4 b/bindings/php/config.m4
index 25321f17..ddefc12a 100644
--- a/bindings/php/config.m4
+++ b/bindings/php/config.m4
@@ -1,44 +1,44 @@
-dnl
-dnl config.m4 for RHash extension
-dnl
-
-PHP_ARG_WITH(rhash, for RHash support,
-[ --with-rhash[=DIR] Include RHash support.])
-
-if test "$PHP_RHASH" != "no"; then
- if test -r $PHP_RHASH/include/rhash.h; then
- RHASH_INCLUDE_DIR=$PHP_RHASH/include
- RHASH_LIB_DIR=$PHP_RHASH/lib
- elif test -r $PHP_RHASH/rhash.h; then
- RHASH_INCLUDE_DIR=$PHP_RHASH
- RHASH_LIB_DIR=$PHP_RHASH
- else
- AC_MSG_CHECKING(for RHash in default path)
- for i in /usr/local /usr; do
- if test -r $i/include/rhash.h; then
- RHASH_INCLUDE_DIR=$i/include
- RHASH_LIB_DIR=$i/lib
- AC_MSG_RESULT(found at $i)
- break
- fi
- done
- fi
-
- if test -z "$RHASH_INCLUDE_DIR" -a -r ../../librhash/rhash.h; then
- RHASH_INCLUDE_DIR=$(pwd)/../../librhash
- RHASH_LIB_DIR=$RHASH_INCLUDE_DIR
- AC_MSG_RESULT(found at $RHASH_INCLUDE_DIR)
- fi
-
- if test -z "$RHASH_INCLUDE_DIR"; then
- AC_MSG_RESULT(not found)
- AC_MSG_ERROR(Please reinstall the librhash -
- rhash.h should be in /include/)
- fi
-
- AC_DEFINE(HAVE_RHASH, 1, [Whether you have RHash])
- PHP_ADD_INCLUDE($RHASH_INCLUDE_DIR)
- PHP_ADD_LIBRARY_WITH_PATH(rhash, $RHASH_LIB_DIR, RHASH_SHARED_LIBADD)
- PHP_NEW_EXTENSION(rhash, php_rhash.c, $ext_shared)
- PHP_SUBST(RHASH_SHARED_LIBADD)
-fi
+dnl
+dnl config.m4 for RHash extension
+dnl
+
+PHP_ARG_WITH(rhash, for RHash support,
+[ --with-rhash[=DIR] Include RHash support.])
+
+if test "$PHP_RHASH" != "no"; then
+ if test -r $PHP_RHASH/include/rhash.h; then
+ RHASH_INCLUDE_DIR=$PHP_RHASH/include
+ RHASH_LIB_DIR=$PHP_RHASH/lib
+ elif test -r $PHP_RHASH/rhash.h; then
+ RHASH_INCLUDE_DIR=$PHP_RHASH
+ RHASH_LIB_DIR=$PHP_RHASH
+ else
+ AC_MSG_CHECKING(for RHash in default path)
+ for i in /usr/local /usr; do
+ if test -r $i/include/rhash.h; then
+ RHASH_INCLUDE_DIR=$i/include
+ RHASH_LIB_DIR=$i/lib
+ AC_MSG_RESULT(found at $i)
+ break
+ fi
+ done
+ fi
+
+ if test -z "$RHASH_INCLUDE_DIR" -a -r ../../librhash/rhash.h; then
+ RHASH_INCLUDE_DIR=$(pwd)/../../librhash
+ RHASH_LIB_DIR=$RHASH_INCLUDE_DIR
+ AC_MSG_RESULT(found at $RHASH_INCLUDE_DIR)
+ fi
+
+ if test -z "$RHASH_INCLUDE_DIR"; then
+ AC_MSG_RESULT(not found)
+ AC_MSG_ERROR(Please reinstall the librhash -
+ rhash.h should be in /include/)
+ fi
+
+ AC_DEFINE(HAVE_RHASH, 1, [Whether you have RHash])
+ PHP_ADD_INCLUDE($RHASH_INCLUDE_DIR)
+ PHP_ADD_LIBRARY_WITH_PATH(rhash, $RHASH_LIB_DIR, RHASH_SHARED_LIBADD)
+ PHP_NEW_EXTENSION(rhash, php_rhash.c, $ext_shared)
+ PHP_SUBST(RHASH_SHARED_LIBADD)
+fi
diff --git a/bindings/php/php_compatibility.h b/bindings/php/php_compatibility.h
index a5537202..e45ee6c3 100644
--- a/bindings/php/php_compatibility.h
+++ b/bindings/php/php_compatibility.h
@@ -1,42 +1,42 @@
-#ifndef PHP_PORTABLE_H
-#define PHP_PORTABLE_H
-
-#if PHP_MAJOR_VERSION < 7
-
-struct _zend_string {
- char *val;
- int len;
- int persistent;
-};
-typedef struct _zend_string zend_string;
-
-#define RETURN_NEW_STR(s) RETURN_STRINGL(s->val,s->len,0);
-
-static zend_always_inline zend_string *zend_string_alloc(int len, int persistent)
-{
- /* aligned to 8 bytes size of buffer to hold (len + 1) characters */
- int alligned_size = (len + 1 + 7) & ~7;
- /* single alloc, so free the buf, will also free the struct */
- char *buf = safe_pemalloc(sizeof(zend_string) + alligned_size, 1, 0, persistent);
- zend_string *str = (zend_string *)(buf + alligned_size);
- str->val = buf;
- str->len = len;
- str->persistent = persistent;
- return str;
-}
-
-/* compatibility macros */
-# define _RETURN_STRING(str) RETURN_STRING(str, 1)
-# define _RETURN_STRINGL(str, l) RETURN_STRINGL(str, l, 1)
-typedef long zend_long;
-typedef int strsize_t;
-
-#else
-
-# define _RETURN_STRING(str) RETURN_STRING(str)
-# define _RETURN_STRINGL(str, l) RETURN_STRINGL(str, l)
-typedef size_t strsize_t;
-
-#endif
-
-#endif /* PHP_PORTABLE_H */
+#ifndef PHP_PORTABLE_H
+#define PHP_PORTABLE_H
+
+#if PHP_MAJOR_VERSION < 7
+
+struct _zend_string {
+ char *val;
+ int len;
+ int persistent;
+};
+typedef struct _zend_string zend_string;
+
+#define RETURN_NEW_STR(s) RETURN_STRINGL(s->val,s->len,0);
+
+static zend_always_inline zend_string *zend_string_alloc(int len, int persistent)
+{
+ /* aligned to 8 bytes size of buffer to hold (len + 1) characters */
+ int alligned_size = (len + 1 + 7) & ~7;
+ /* single alloc, so free the buf, will also free the struct */
+ char *buf = safe_pemalloc(sizeof(zend_string) + alligned_size, 1, 0, persistent);
+ zend_string *str = (zend_string *)(buf + alligned_size);
+ str->val = buf;
+ str->len = len;
+ str->persistent = persistent;
+ return str;
+}
+
+/* compatibility macros */
+# define _RETURN_STRING(str) RETURN_STRING(str, 1)
+# define _RETURN_STRINGL(str, l) RETURN_STRINGL(str, l, 1)
+typedef long zend_long;
+typedef int strsize_t;
+
+#else
+
+# define _RETURN_STRING(str) RETURN_STRING(str)
+# define _RETURN_STRINGL(str, l) RETURN_STRINGL(str, l)
+typedef size_t strsize_t;
+
+#endif
+
+#endif /* PHP_PORTABLE_H */
diff --git a/bindings/php/php_rhash.c b/bindings/php/php_rhash.c
index 8283a7b3..d5fb7884 100644
--- a/bindings/php/php_rhash.c
+++ b/bindings/php/php_rhash.c
@@ -1,680 +1,680 @@
-/* php_rhash.c */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "php_streams.h"
-#include "php_rhash.h"
-#include "php_compatibility.h"
-
-#define PHP_RHASH_VERSION "1.2.9"
-
-/* {{{ arginfo */
-ZEND_BEGIN_ARG_INFO(arginfo_rhash_count, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO(arginfo_rhash_get_digest_size, 0)
- ZEND_ARG_INFO(0, hash_id)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO(arginfo_rhash_is_base32, 0)
- ZEND_ARG_INFO(0, hash_id)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO(arginfo_rhash_get_name, 0)
- ZEND_ARG_INFO(0, hash_id)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO(arginfo_rhash_msg, 0)
- ZEND_ARG_INFO(0, hash_id)
- ZEND_ARG_INFO(0, message)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO(arginfo_rhash_file, 0)
- ZEND_ARG_INFO(0, hash_id)
- ZEND_ARG_INFO(0, path)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO(arginfo_rhash_magnet_func, 0)
- ZEND_ARG_INFO(0, hash_id)
- ZEND_ARG_INFO(0, path)
-ZEND_END_ARG_INFO()
-/* }}} */
-
-/* {{{ The table of global functions
-*/
-static zend_function_entry rhash_functions[] = {
- PHP_FE(rhash_count, arginfo_rhash_count)
- PHP_FE(rhash_get_digest_size, arginfo_rhash_get_digest_size)
- PHP_FE(rhash_is_base32, arginfo_rhash_is_base32)
- PHP_FE(rhash_get_name, arginfo_rhash_get_name)
- PHP_FE(rhash_msg, arginfo_rhash_msg)
- PHP_FE(rhash_file, arginfo_rhash_file)
- PHP_FE(rhash_magnet, arginfo_rhash_magnet_func)
- PHP_FE_END
-};
-/* }}} */
-
-
-/* {{{ arginfo */
-ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash__construct, 0, 0, 0)
- ZEND_ARG_INFO(0, hash_id)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO(arginfo_rhash_update, 0)
- ZEND_ARG_INFO(0, message)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_update_stream, 0, 0, 1)
- ZEND_ARG_INFO(0, handle)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, size)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_update_file, 0, 0, 1)
- ZEND_ARG_INFO(0, path)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, size)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO(arginfo_rhash_final, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO(arginfo_rhash_reset, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO(arginfo_rhash_hashed_length, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_hash, 0, 0, 0)
- ZEND_ARG_INFO(0, hash_id)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_raw, 0, 0, 0)
- ZEND_ARG_INFO(0, hash_id)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_hex, 0, 0, 0)
- ZEND_ARG_INFO(0, hash_id)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_base32, 0, 0, 0)
- ZEND_ARG_INFO(0, hash_id)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_base64, 0, 0, 0)
- ZEND_ARG_INFO(0, hash_id)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_magnet, 0, 0, 0)
- ZEND_ARG_INFO(0, filename)
-ZEND_END_ARG_INFO()
-/* }}} */
-
-/* {{{ The table of the RHash class methods
-*/
-zend_function_entry rhash_methods[] = {
- PHP_ME(RHash, __construct, arginfo_rhash__construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
- PHP_ME(RHash, update, arginfo_rhash_update, ZEND_ACC_PUBLIC)
- PHP_ME(RHash, update_stream, arginfo_rhash_update_stream, ZEND_ACC_PUBLIC)
- PHP_ME(RHash, update_file, arginfo_rhash_update_file, ZEND_ACC_PUBLIC)
- PHP_ME(RHash, final, arginfo_rhash_final, ZEND_ACC_PUBLIC)
- PHP_ME(RHash, reset, arginfo_rhash_reset, ZEND_ACC_PUBLIC)
- PHP_ME(RHash, hashed_length, arginfo_rhash_hashed_length, ZEND_ACC_PUBLIC)
- PHP_ME(RHash, hash, arginfo_rhash_hash, ZEND_ACC_PUBLIC)
- PHP_ME(RHash, raw, arginfo_rhash_raw, ZEND_ACC_PUBLIC)
- PHP_ME(RHash, hex, arginfo_rhash_hex, ZEND_ACC_PUBLIC)
- PHP_ME(RHash, base32, arginfo_rhash_base32, ZEND_ACC_PUBLIC)
- PHP_ME(RHash, base64, arginfo_rhash_base64, ZEND_ACC_PUBLIC)
- PHP_ME(RHash, magnet, arginfo_rhash_magnet, ZEND_ACC_PUBLIC)
- PHP_FE_END
-};
-/* }}} */
-
-zend_class_entry *rhash_ce;
-zend_object_handlers rhash_object_handlers;
-
-/* {{{ Module struct
-*/
-zend_module_entry rhash_module_entry = {
-#if ZEND_MODULE_API_NO >= 20010901
- STANDARD_MODULE_HEADER,
-#endif
- "rhash", /* extension name */
- rhash_functions, /* function list */
- PHP_MINIT(rhash), /* process startup */
- PHP_MSHUTDOWN(rhash), /* process shutdown */
- NULL,
- NULL,
- PHP_MINFO(rhash), /* extension info */
-#if ZEND_MODULE_API_NO >= 20010901
- PHP_RHASH_VERSION, /* extension version */
-#endif
- STANDARD_MODULE_PROPERTIES
-};
-/* }}} */
-
-#ifdef COMPILE_DL_RHASH
-ZEND_GET_MODULE(rhash)
-#endif
-
-#define REGISTER_RHASH_CONSTANT(c) REGISTER_LONG_CONSTANT(#c, c, CONST_CS | CONST_PERSISTENT)
-#define RHASH_ALL RHASH_ALL_HASHES
-
-
-#if PHP_MAJOR_VERSION < 7
-typedef struct _rhash_object {
- zend_object zobj;
- rhash rhash;
-} rhash_object;
-
-# define get_rhash_object(this_zval) ((rhash_object*)zend_object_store_get_object(this_zval TSRMLS_CC))
-# define get_rhash_object_from_zend_object(object) (rhash_object *)(object)
-#else
-typedef struct _rhash_object {
- rhash rhash;
- zend_object zobj;
-} rhash_object;
-
-static rhash_object * get_rhash_object(zval *this_zval)
-{
- zend_object *zobj = Z_OBJ_P(this_zval);
- return (rhash_object *)((char *)zobj - XtOffsetOf(rhash_object, zobj));
-}
-# define get_rhash_object_from_zend_object(object) (rhash_object *)((char *)object - XtOffsetOf(rhash_object, zobj));
-#endif
-
-static void rhash_free_object(zend_object *object TSRMLS_DC)
-{
- rhash_object *obj = get_rhash_object_from_zend_object(object);
- if (obj->rhash)
- rhash_free(obj->rhash);
-
- /* call Zend's free handler, which will free object properties */
- zend_object_std_dtor(object TSRMLS_CC);
-#if PHP_MAJOR_VERSION < 7
- efree(object);
-#endif
-}
-
-/* Allocate memory for new rhash_object */
-#if PHP_MAJOR_VERSION < 7
-static zend_object_value rhash_create_object(zend_class_entry *ce TSRMLS_DC)
-{
- zend_object_value retval;
-
- rhash_object *obj = (rhash_object *)emalloc(sizeof(rhash_object));
- memset(obj, 0, sizeof(rhash_object));
- zend_object_std_init(&obj->zobj, ce TSRMLS_CC);
- obj->rhash = NULL;
-
- /* call object_properties_init(), because extending classes may use properties. */
- object_properties_init(&obj->zobj, ce);
-
- retval.handle = zend_objects_store_put(obj,
- (zend_objects_store_dtor_t) zend_objects_destroy_object,
- (zend_objects_free_object_storage_t)rhash_free_object, NULL TSRMLS_CC);
- retval.handlers = &rhash_object_handlers;
- return retval;
-}
-#else
-static zend_object *rhash_create_object(zend_class_entry *ce TSRMLS_DC)
-{
- rhash_object *obj = ecalloc(1, sizeof(*obj) + zend_object_properties_size(ce));
- zend_object_std_init(&obj->zobj, ce TSRMLS_CC);
-
- obj->zobj.handlers = &rhash_object_handlers;
- return &obj->zobj;
-}
-#endif
-
-/* {{{ PHP_MINIT_FUNCTION(rhash) */
-PHP_MINIT_FUNCTION(rhash)
-{
- zend_class_entry ce;
- rhash_library_init(); /* initialize LibRHash */
-
- /* register RHash class, its methods and handlers */
- INIT_CLASS_ENTRY(ce, "RHash", rhash_methods);
- rhash_ce = zend_register_internal_class(&ce TSRMLS_CC);
- rhash_ce->create_object = rhash_create_object;
-
- memcpy(&rhash_object_handlers,
- zend_get_std_object_handlers(), sizeof(zend_object_handlers));
- rhash_object_handlers.clone_obj = NULL;
-#if PHP_MAJOR_VERSION >= 7
- rhash_object_handlers.free_obj = rhash_free_object; /* This is the free handler */
- rhash_object_handlers.offset = XtOffsetOf(rhash_object, zobj);
-#endif
-
- REGISTER_RHASH_CONSTANT(RHASH_CRC32);
- REGISTER_RHASH_CONSTANT(RHASH_CRC32C);
- REGISTER_RHASH_CONSTANT(RHASH_MD4);
- REGISTER_RHASH_CONSTANT(RHASH_MD5);
- REGISTER_RHASH_CONSTANT(RHASH_SHA1);
- REGISTER_RHASH_CONSTANT(RHASH_TIGER);
- REGISTER_RHASH_CONSTANT(RHASH_TTH);
- REGISTER_RHASH_CONSTANT(RHASH_BTIH);
- REGISTER_RHASH_CONSTANT(RHASH_ED2K);
- REGISTER_RHASH_CONSTANT(RHASH_AICH);
- REGISTER_RHASH_CONSTANT(RHASH_WHIRLPOOL);
- REGISTER_RHASH_CONSTANT(RHASH_RIPEMD160);
- REGISTER_RHASH_CONSTANT(RHASH_GOST94);
- REGISTER_RHASH_CONSTANT(RHASH_GOST94_CRYPTOPRO);
- REGISTER_RHASH_CONSTANT(RHASH_GOST12_256);
- REGISTER_RHASH_CONSTANT(RHASH_GOST12_512);
- REGISTER_RHASH_CONSTANT(RHASH_HAS160);
- REGISTER_RHASH_CONSTANT(RHASH_SHA224);
- REGISTER_RHASH_CONSTANT(RHASH_SHA256);
- REGISTER_RHASH_CONSTANT(RHASH_SHA384);
- REGISTER_RHASH_CONSTANT(RHASH_SHA512);
- REGISTER_RHASH_CONSTANT(RHASH_EDONR256);
- REGISTER_RHASH_CONSTANT(RHASH_EDONR512);
- REGISTER_RHASH_CONSTANT(RHASH_SHA3_224);
- REGISTER_RHASH_CONSTANT(RHASH_SHA3_256);
- REGISTER_RHASH_CONSTANT(RHASH_SHA3_384);
- REGISTER_RHASH_CONSTANT(RHASH_SHA3_512);
- REGISTER_RHASH_CONSTANT(RHASH_SNEFRU128);
- REGISTER_RHASH_CONSTANT(RHASH_SNEFRU256);
- REGISTER_RHASH_CONSTANT(RHASH_ALL);
-
- return SUCCESS;
-}
-/* }}} */
-
-/* {{{ PHP_MSHUTDOWN_FUNCTION(rhash) */
-PHP_MSHUTDOWN_FUNCTION(rhash)
-{
- return SUCCESS;
-}
-/* }}} */
-
-/* {{{ PHP_MINFO_FUNCTION(rhash) */
-PHP_MINFO_FUNCTION(rhash)
-{
- php_info_print_table_start();
- php_info_print_table_row(2, "rhash support", "enabled");
- php_info_print_table_end();
-}
-/* }}} */
-
-/* Global functions */
-
-/* {{{ proto int rhash_count()
- Returns the number of supported hash functions */
-PHP_FUNCTION(rhash_count) {
- RETURN_LONG(rhash_count());
-}
-/* }}} */
-
-/* {{{ proto int rhash_get_digest_size(int hash_id)
- Returns the size in bytes of message digest of the specified hash function */
-PHP_FUNCTION(rhash_get_digest_size) {
- zend_long hash_id;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &hash_id) == FAILURE) {
- RETURN_FALSE;
- }
- RETURN_LONG(rhash_get_digest_size((unsigned)hash_id));
-}
-/* }}} */
-
-/* {{{ proto boolean rhash_is_base32(int hash_id)
- Returns true if default format of message digest is base32 and false if it's hexadecimal */
-PHP_FUNCTION(rhash_is_base32) {
- zend_long hash_id;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &hash_id) == FAILURE) {
- RETURN_FALSE;
- }
- RETURN_BOOL(rhash_is_base32((unsigned)hash_id));
-}
-/* }}} */
-
-/* {{{ proto string rhash_get_name(int hash_id)
- Returns the name of the specified hash function */
-PHP_FUNCTION(rhash_get_name) {
- zend_long hash_id;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &hash_id) == FAILURE) {
- RETURN_FALSE;
- }
- _RETURN_STRING(rhash_get_name((unsigned)hash_id));
-}
-/* }}} */
-
-/* {{{ proto string rhash_msg(int hash_id, string message)
- Returns message digest for the message string */
-PHP_FUNCTION(rhash_msg) {
- zend_long hash_id;
- char *s;
- strsize_t s_len;
- strsize_t length;
- rhash context = NULL;
- char buffer[130];
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &hash_id, &s, &s_len) == FAILURE) {
- RETURN_NULL();
- }
-
- if (!(context = rhash_init((unsigned)hash_id))) {
- RETURN_NULL();
- }
-
- rhash_update(context, s, s_len);
- rhash_final(context, 0);
- length = rhash_print(buffer, context, (unsigned)hash_id, 0);
- rhash_free(context);
- _RETURN_STRINGL(buffer, length);
-}
-
-/* Calculate hash for a php stream. Returns SUCCESS or FAILURE. */
-static strsize_t _php_rhash_stream(INTERNAL_FUNCTION_PARAMETERS, rhash context, php_stream *stream, zend_long start, zend_long size)
-{
- char data[8192];
- if (context == NULL) {
- rhash_object *obj = get_rhash_object(getThis());
- if ((context = obj->rhash) == NULL) return FAILURE;
- }
-
- if (start >= 0) {
- if (php_stream_seek(stream, start, SEEK_SET) < 0) return FAILURE;
- }
-
- if (size >= 0) {
- while (size > 0 && !php_stream_eof(stream)) {
- int length = php_stream_read(stream, data, (size < 8192 ? size : 8192));
- if (!length) return FAILURE;
- size -= length;
- rhash_update(context, data, length);
- }
- } else {
- while (!php_stream_eof(stream)) {
- int length = php_stream_read(stream, data, 8192);
- if (!length) return FAILURE;
- rhash_update(context, data, length);
- }
- }
- return SUCCESS;
-}
-/* }}} */
-
-/* Calculate hash of the given file or its part. Returns SUCCESS or FAILURE. */
-static strsize_t _php_rhash_file(INTERNAL_FUNCTION_PARAMETERS, rhash context, char* path, zend_long start, zend_long size)
-{
- strsize_t res;
- php_stream *stream = php_stream_open_wrapper(path, "rb", 0, 0);
- if (stream == NULL) return FAILURE;
-
- res = _php_rhash_stream(INTERNAL_FUNCTION_PARAM_PASSTHRU, context, stream, start, size);
- php_stream_close(stream);
- return res;
-}
-/* }}} */
-
-/* {{{ proto string rhash_file(int hash_id, string path)
- Computes and returns message digest for a file. Returns NULL on failure. */
-PHP_FUNCTION(rhash_file) {
- zend_long hash_id = 0;
- char *path;
- strsize_t path_len;
- rhash context = NULL;
- char buffer[130];
- int buffer_length;
- strsize_t res;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lp", &hash_id, &path, &path_len) == FAILURE) {
- RETURN_NULL();
- }
- if (!hash_id || !(context = rhash_init(hash_id))) {
- RETURN_NULL()
- }
- res = _php_rhash_file(INTERNAL_FUNCTION_PARAM_PASSTHRU, context, path, -1, -1);
- rhash_final(context, 0);
- buffer_length = rhash_print(buffer, context, hash_id, 0);
- rhash_free(context);
-
- /* return NULL on failure */
- if (res != SUCCESS) {
- RETURN_NULL();
- }
- _RETURN_STRINGL(buffer, buffer_length);
-}
-/* }}} */
-
-/* {{{ proto string rhash_magnet(int hash_id, string path)
- Computes and returns magnet link for a file. Returns NULL on failure. */
-PHP_FUNCTION(rhash_magnet) {
- zend_long hash_id = 0;
- char *path;
- strsize_t path_len;
- rhash context = NULL;
- zend_string* str;
- size_t buffer_size;
- strsize_t res;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lp", &hash_id, &path, &path_len) == FAILURE) {
- RETURN_NULL();
- }
- if (!hash_id || !(context = rhash_init(hash_id))) {
- RETURN_NULL();
- }
- res = _php_rhash_file(INTERNAL_FUNCTION_PARAM_PASSTHRU, context, path, -1, -1);
- if (res != SUCCESS) RETURN_NULL();
- rhash_final(context, 0);
-
- buffer_size = rhash_print_magnet(0, path, context, hash_id, RHPR_FILESIZE);
-
- str = zend_string_alloc(buffer_size - 1, 0);
- if (!str) {
- rhash_free(context);
- RETURN_NULL();
- }
-
- rhash_print_magnet(str->val, path, context, hash_id, RHPR_FILESIZE);
- rhash_free(context);
- RETURN_NEW_STR(str);
-}
-/* }}} */
-
-
-/* RHash class methods */
-
-/* {{{ proto RHash::__construct([int hash_id])
- Creates new RHash object */
-PHP_METHOD(RHash, __construct)
-{
- zend_long hash_id = 0;
- rhash context = NULL;
- rhash_object *obj;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &hash_id) == FAILURE) {
- RETURN_NULL();
- }
- if (!hash_id)
- hash_id = RHASH_ALL_HASHES;
- if (!(context = rhash_init(hash_id))) {
- RETURN_NULL();
- }
- rhash_set_autofinal(context, 0);
- obj = get_rhash_object(getThis());
- obj->rhash = context;
-}
-/* }}} */
-
-/* {{{ proto RHash RHash::update(string message)
- Updates RHash object with new data chunk and returns $this */
-PHP_METHOD(RHash, update)
-{
- char *s;
- strsize_t s_len;
- zval *object = getThis();
- rhash_object *obj = get_rhash_object(object);
-
- if (obj->rhash == NULL ||
- zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &s, &s_len) == FAILURE) {
- RETURN_FALSE;
- }
- rhash_update(obj->rhash, s, s_len);
- Z_ADDREF(*object);
- *return_value = *object;
-}
-/* }}} */
-
-/* {{{ proto boolean RHash::update_stream(resource handle[, int start[, int size]])
- Returns true if successfully calculated hashes for a (part of) stream, false on error */
-PHP_METHOD(RHash, update_stream)
-{
- zval *handle;
- strsize_t res;
- zend_long start = -1, size = -1;
- php_stream *stream;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|ll", &handle, &start, &size) == FAILURE) {
- RETURN_FALSE;
- }
-#if PHP_MAJOR_VERSION < 7
- php_stream_from_zval_no_verify(stream, &handle);
-#else
- php_stream_from_zval_no_verify(stream, handle);
-#endif
- if (stream == NULL) RETURN_FALSE;
- res = _php_rhash_stream(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, stream, start, size);
- RETURN_BOOL(res == SUCCESS);
-}
-/* }}} */
-
-/* {{{ proto boolean RHash::update_file(string path[, int start[, int size]])
- Returns true if successfully calculated hashes for a (part of) file, false on error */
-PHP_METHOD(RHash, update_file)
-{
- char *path;
- strsize_t len;
- zend_long start = -1, size = -1;
- strsize_t res = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|ll", &path, &len, &start, &size);
- if (res == SUCCESS) {
- res = _php_rhash_file(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, path, start, size);
- }
- RETURN_BOOL(res == SUCCESS);
-}
-/* }}} */
-
-/* {{{ proto RHash RHash::final()
- Finalizes calculation for all hashed data and returns $this */
-PHP_METHOD(RHash, final)
-{
- zval *object = getThis();
- rhash_object *obj = get_rhash_object(object);
- if (obj->rhash == NULL) RETURN_FALSE;
- rhash_final(obj->rhash, NULL);
- Z_ADDREF(*object);
- *return_value = *object;
-}
-/* }}} */
-
-/* {{{ proto RHash RHash::reset()
- Resets RHash object to initial state and returns $this */
-PHP_METHOD(RHash, reset)
-{
- zval *object = getThis();
- rhash_object *obj = get_rhash_object(object);
- if (obj->rhash == NULL) RETURN_FALSE;
- rhash_reset(obj->rhash);
- Z_ADDREF(*object);
- *return_value = *object;
-}
-/* }}} */
-
-/* {{{ proto int RHash::hashed_length()
- Returns length in bytes of the hashed data */
-PHP_METHOD(RHash, hashed_length)
-{
- rhash_object *obj = get_rhash_object(getThis());
- if (obj->rhash == NULL) RETURN_FALSE;
- RETURN_LONG((long)obj->rhash->msg_size);
-}
-/* }}} */
-
-/* {{{ _php_get_hash(RHash this_class[, int hash_id], int print_flags)
- Returns calculated hash in the specified format */
-static void _php_get_hash(INTERNAL_FUNCTION_PARAMETERS, int print_flags)
-{
- zend_long hash_id = 0;
- char buffer[130];
- int length;
- rhash_object *obj = get_rhash_object(getThis());
- if (obj->rhash == NULL ||
- zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &hash_id) == FAILURE) {
- RETURN_FALSE;
- }
- length = rhash_print(buffer, obj->rhash, hash_id, print_flags);
- _RETURN_STRINGL(buffer, length)
-}
-/* }}} */
-
-/* {{{ proto string RHash::hash([int hash_id])
- Returns hash value in default format */
-PHP_METHOD(RHash, hash)
-{
- _php_get_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
-}
-/* }}} */
-
-/* {{{ proto string RHash::raw([int hash_id])
- Returns hash value as raw bytes */
-PHP_METHOD(RHash, raw)
-{
- _php_get_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, RHPR_RAW);
-}
-/* }}} */
-
-/* {{{ proto string RHash::hex([int hash_id])
- Returns hash value as hexadecimal string */
-PHP_METHOD(RHash, hex)
-{
- _php_get_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, RHPR_HEX);
-}
-/* }}} */
-
-/* {{{ proto string RHash::base32([int hash_id])
- Returns hash value as base32 string */
-PHP_METHOD(RHash, base32)
-{
- _php_get_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, RHPR_BASE32);
-}
-/* }}} */
-
-/* {{{ proto string RHash::base64([int hash_id])
- Returns hash value as base64 string */
-PHP_METHOD(RHash, base64)
-{
- _php_get_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, RHPR_BASE64);
-}
-/* }}} */
-
-/* {{{ proto string RHash::magnet([string filename])
- Returns magnet link with all hashes computed by the RHash object */
-PHP_METHOD(RHash, magnet)
-{
- char *s = 0;
- strsize_t s_len;
- size_t buf_size;
- zend_string *magnet_str;
- rhash_object *obj = get_rhash_object(getThis());
-
- if (obj->rhash == NULL ||
- zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &s, &s_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- buf_size = rhash_print_magnet(0, s, obj->rhash, RHASH_ALL_HASHES, RHPR_FILESIZE);
- magnet_str = zend_string_alloc(buf_size - 1, 0);
- if (!magnet_str) RETURN_FALSE;
-
- rhash_print_magnet(magnet_str->val, s, obj->rhash, RHASH_ALL_HASHES, RHPR_FILESIZE);
- RETURN_NEW_STR(magnet_str);
-}
-/* }}} */
+/* php_rhash.c */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "php_streams.h"
+#include "php_rhash.h"
+#include "php_compatibility.h"
+
+#define PHP_RHASH_VERSION "1.2.9"
+
+/* {{{ arginfo */
+ZEND_BEGIN_ARG_INFO(arginfo_rhash_count, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_rhash_get_digest_size, 0)
+ ZEND_ARG_INFO(0, hash_id)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_rhash_is_base32, 0)
+ ZEND_ARG_INFO(0, hash_id)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_rhash_get_name, 0)
+ ZEND_ARG_INFO(0, hash_id)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_rhash_msg, 0)
+ ZEND_ARG_INFO(0, hash_id)
+ ZEND_ARG_INFO(0, message)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_rhash_file, 0)
+ ZEND_ARG_INFO(0, hash_id)
+ ZEND_ARG_INFO(0, path)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_rhash_magnet_func, 0)
+ ZEND_ARG_INFO(0, hash_id)
+ ZEND_ARG_INFO(0, path)
+ZEND_END_ARG_INFO()
+/* }}} */
+
+/* {{{ The table of global functions
+*/
+static zend_function_entry rhash_functions[] = {
+ PHP_FE(rhash_count, arginfo_rhash_count)
+ PHP_FE(rhash_get_digest_size, arginfo_rhash_get_digest_size)
+ PHP_FE(rhash_is_base32, arginfo_rhash_is_base32)
+ PHP_FE(rhash_get_name, arginfo_rhash_get_name)
+ PHP_FE(rhash_msg, arginfo_rhash_msg)
+ PHP_FE(rhash_file, arginfo_rhash_file)
+ PHP_FE(rhash_magnet, arginfo_rhash_magnet_func)
+ PHP_FE_END
+};
+/* }}} */
+
+
+/* {{{ arginfo */
+ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash__construct, 0, 0, 0)
+ ZEND_ARG_INFO(0, hash_id)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_rhash_update, 0)
+ ZEND_ARG_INFO(0, message)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_update_stream, 0, 0, 1)
+ ZEND_ARG_INFO(0, handle)
+ ZEND_ARG_INFO(0, start)
+ ZEND_ARG_INFO(0, size)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_update_file, 0, 0, 1)
+ ZEND_ARG_INFO(0, path)
+ ZEND_ARG_INFO(0, start)
+ ZEND_ARG_INFO(0, size)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_rhash_final, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_rhash_reset, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_rhash_hashed_length, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_hash, 0, 0, 0)
+ ZEND_ARG_INFO(0, hash_id)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_raw, 0, 0, 0)
+ ZEND_ARG_INFO(0, hash_id)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_hex, 0, 0, 0)
+ ZEND_ARG_INFO(0, hash_id)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_base32, 0, 0, 0)
+ ZEND_ARG_INFO(0, hash_id)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_base64, 0, 0, 0)
+ ZEND_ARG_INFO(0, hash_id)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_rhash_magnet, 0, 0, 0)
+ ZEND_ARG_INFO(0, filename)
+ZEND_END_ARG_INFO()
+/* }}} */
+
+/* {{{ The table of the RHash class methods
+*/
+zend_function_entry rhash_methods[] = {
+ PHP_ME(RHash, __construct, arginfo_rhash__construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+ PHP_ME(RHash, update, arginfo_rhash_update, ZEND_ACC_PUBLIC)
+ PHP_ME(RHash, update_stream, arginfo_rhash_update_stream, ZEND_ACC_PUBLIC)
+ PHP_ME(RHash, update_file, arginfo_rhash_update_file, ZEND_ACC_PUBLIC)
+ PHP_ME(RHash, final, arginfo_rhash_final, ZEND_ACC_PUBLIC)
+ PHP_ME(RHash, reset, arginfo_rhash_reset, ZEND_ACC_PUBLIC)
+ PHP_ME(RHash, hashed_length, arginfo_rhash_hashed_length, ZEND_ACC_PUBLIC)
+ PHP_ME(RHash, hash, arginfo_rhash_hash, ZEND_ACC_PUBLIC)
+ PHP_ME(RHash, raw, arginfo_rhash_raw, ZEND_ACC_PUBLIC)
+ PHP_ME(RHash, hex, arginfo_rhash_hex, ZEND_ACC_PUBLIC)
+ PHP_ME(RHash, base32, arginfo_rhash_base32, ZEND_ACC_PUBLIC)
+ PHP_ME(RHash, base64, arginfo_rhash_base64, ZEND_ACC_PUBLIC)
+ PHP_ME(RHash, magnet, arginfo_rhash_magnet, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+/* }}} */
+
+zend_class_entry *rhash_ce;
+zend_object_handlers rhash_object_handlers;
+
+/* {{{ Module struct
+*/
+zend_module_entry rhash_module_entry = {
+#if ZEND_MODULE_API_NO >= 20010901
+ STANDARD_MODULE_HEADER,
+#endif
+ "rhash", /* extension name */
+ rhash_functions, /* function list */
+ PHP_MINIT(rhash), /* process startup */
+ PHP_MSHUTDOWN(rhash), /* process shutdown */
+ NULL,
+ NULL,
+ PHP_MINFO(rhash), /* extension info */
+#if ZEND_MODULE_API_NO >= 20010901
+ PHP_RHASH_VERSION, /* extension version */
+#endif
+ STANDARD_MODULE_PROPERTIES
+};
+/* }}} */
+
+#ifdef COMPILE_DL_RHASH
+ZEND_GET_MODULE(rhash)
+#endif
+
+#define REGISTER_RHASH_CONSTANT(c) REGISTER_LONG_CONSTANT(#c, c, CONST_CS | CONST_PERSISTENT)
+#define RHASH_ALL RHASH_ALL_HASHES
+
+
+#if PHP_MAJOR_VERSION < 7
+typedef struct _rhash_object {
+ zend_object zobj;
+ rhash rhash;
+} rhash_object;
+
+# define get_rhash_object(this_zval) ((rhash_object*)zend_object_store_get_object(this_zval TSRMLS_CC))
+# define get_rhash_object_from_zend_object(object) (rhash_object *)(object)
+#else
+typedef struct _rhash_object {
+ rhash rhash;
+ zend_object zobj;
+} rhash_object;
+
+static rhash_object * get_rhash_object(zval *this_zval)
+{
+ zend_object *zobj = Z_OBJ_P(this_zval);
+ return (rhash_object *)((char *)zobj - XtOffsetOf(rhash_object, zobj));
+}
+# define get_rhash_object_from_zend_object(object) (rhash_object *)((char *)object - XtOffsetOf(rhash_object, zobj));
+#endif
+
+static void rhash_free_object(zend_object *object TSRMLS_DC)
+{
+ rhash_object *obj = get_rhash_object_from_zend_object(object);
+ if (obj->rhash)
+ rhash_free(obj->rhash);
+
+ /* call Zend's free handler, which will free object properties */
+ zend_object_std_dtor(object TSRMLS_CC);
+#if PHP_MAJOR_VERSION < 7
+ efree(object);
+#endif
+}
+
+/* Allocate memory for new rhash_object */
+#if PHP_MAJOR_VERSION < 7
+static zend_object_value rhash_create_object(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value retval;
+
+ rhash_object *obj = (rhash_object *)emalloc(sizeof(rhash_object));
+ memset(obj, 0, sizeof(rhash_object));
+ zend_object_std_init(&obj->zobj, ce TSRMLS_CC);
+ obj->rhash = NULL;
+
+ /* call object_properties_init(), because extending classes may use properties. */
+ object_properties_init(&obj->zobj, ce);
+
+ retval.handle = zend_objects_store_put(obj,
+ (zend_objects_store_dtor_t) zend_objects_destroy_object,
+ (zend_objects_free_object_storage_t)rhash_free_object, NULL TSRMLS_CC);
+ retval.handlers = &rhash_object_handlers;
+ return retval;
+}
+#else
+static zend_object *rhash_create_object(zend_class_entry *ce TSRMLS_DC)
+{
+ rhash_object *obj = ecalloc(1, sizeof(*obj) + zend_object_properties_size(ce));
+ zend_object_std_init(&obj->zobj, ce TSRMLS_CC);
+
+ obj->zobj.handlers = &rhash_object_handlers;
+ return &obj->zobj;
+}
+#endif
+
+/* {{{ PHP_MINIT_FUNCTION(rhash) */
+PHP_MINIT_FUNCTION(rhash)
+{
+ zend_class_entry ce;
+ rhash_library_init(); /* initialize LibRHash */
+
+ /* register RHash class, its methods and handlers */
+ INIT_CLASS_ENTRY(ce, "RHash", rhash_methods);
+ rhash_ce = zend_register_internal_class(&ce TSRMLS_CC);
+ rhash_ce->create_object = rhash_create_object;
+
+ memcpy(&rhash_object_handlers,
+ zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ rhash_object_handlers.clone_obj = NULL;
+#if PHP_MAJOR_VERSION >= 7
+ rhash_object_handlers.free_obj = rhash_free_object; /* This is the free handler */
+ rhash_object_handlers.offset = XtOffsetOf(rhash_object, zobj);
+#endif
+
+ REGISTER_RHASH_CONSTANT(RHASH_CRC32);
+ REGISTER_RHASH_CONSTANT(RHASH_CRC32C);
+ REGISTER_RHASH_CONSTANT(RHASH_MD4);
+ REGISTER_RHASH_CONSTANT(RHASH_MD5);
+ REGISTER_RHASH_CONSTANT(RHASH_SHA1);
+ REGISTER_RHASH_CONSTANT(RHASH_TIGER);
+ REGISTER_RHASH_CONSTANT(RHASH_TTH);
+ REGISTER_RHASH_CONSTANT(RHASH_BTIH);
+ REGISTER_RHASH_CONSTANT(RHASH_ED2K);
+ REGISTER_RHASH_CONSTANT(RHASH_AICH);
+ REGISTER_RHASH_CONSTANT(RHASH_WHIRLPOOL);
+ REGISTER_RHASH_CONSTANT(RHASH_RIPEMD160);
+ REGISTER_RHASH_CONSTANT(RHASH_GOST94);
+ REGISTER_RHASH_CONSTANT(RHASH_GOST94_CRYPTOPRO);
+ REGISTER_RHASH_CONSTANT(RHASH_GOST12_256);
+ REGISTER_RHASH_CONSTANT(RHASH_GOST12_512);
+ REGISTER_RHASH_CONSTANT(RHASH_HAS160);
+ REGISTER_RHASH_CONSTANT(RHASH_SHA224);
+ REGISTER_RHASH_CONSTANT(RHASH_SHA256);
+ REGISTER_RHASH_CONSTANT(RHASH_SHA384);
+ REGISTER_RHASH_CONSTANT(RHASH_SHA512);
+ REGISTER_RHASH_CONSTANT(RHASH_EDONR256);
+ REGISTER_RHASH_CONSTANT(RHASH_EDONR512);
+ REGISTER_RHASH_CONSTANT(RHASH_SHA3_224);
+ REGISTER_RHASH_CONSTANT(RHASH_SHA3_256);
+ REGISTER_RHASH_CONSTANT(RHASH_SHA3_384);
+ REGISTER_RHASH_CONSTANT(RHASH_SHA3_512);
+ REGISTER_RHASH_CONSTANT(RHASH_SNEFRU128);
+ REGISTER_RHASH_CONSTANT(RHASH_SNEFRU256);
+ REGISTER_RHASH_CONSTANT(RHASH_ALL);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MSHUTDOWN_FUNCTION(rhash) */
+PHP_MSHUTDOWN_FUNCTION(rhash)
+{
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MINFO_FUNCTION(rhash) */
+PHP_MINFO_FUNCTION(rhash)
+{
+ php_info_print_table_start();
+ php_info_print_table_row(2, "rhash support", "enabled");
+ php_info_print_table_end();
+}
+/* }}} */
+
+/* Global functions */
+
+/* {{{ proto int rhash_count()
+ Returns the number of supported hash functions */
+PHP_FUNCTION(rhash_count) {
+ RETURN_LONG(rhash_count());
+}
+/* }}} */
+
+/* {{{ proto int rhash_get_digest_size(int hash_id)
+ Returns the size in bytes of message digest of the specified hash function */
+PHP_FUNCTION(rhash_get_digest_size) {
+ zend_long hash_id;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &hash_id) == FAILURE) {
+ RETURN_FALSE;
+ }
+ RETURN_LONG(rhash_get_digest_size((unsigned)hash_id));
+}
+/* }}} */
+
+/* {{{ proto boolean rhash_is_base32(int hash_id)
+ Returns true if default format of message digest is base32 and false if it's hexadecimal */
+PHP_FUNCTION(rhash_is_base32) {
+ zend_long hash_id;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &hash_id) == FAILURE) {
+ RETURN_FALSE;
+ }
+ RETURN_BOOL(rhash_is_base32((unsigned)hash_id));
+}
+/* }}} */
+
+/* {{{ proto string rhash_get_name(int hash_id)
+ Returns the name of the specified hash function */
+PHP_FUNCTION(rhash_get_name) {
+ zend_long hash_id;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &hash_id) == FAILURE) {
+ RETURN_FALSE;
+ }
+ _RETURN_STRING(rhash_get_name((unsigned)hash_id));
+}
+/* }}} */
+
+/* {{{ proto string rhash_msg(int hash_id, string message)
+ Returns message digest for the message string */
+PHP_FUNCTION(rhash_msg) {
+ zend_long hash_id;
+ char *s;
+ strsize_t s_len;
+ strsize_t length;
+ rhash context = NULL;
+ char buffer[130];
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &hash_id, &s, &s_len) == FAILURE) {
+ RETURN_NULL();
+ }
+
+ if (!(context = rhash_init((unsigned)hash_id))) {
+ RETURN_NULL();
+ }
+
+ rhash_update(context, s, s_len);
+ rhash_final(context, 0);
+ length = rhash_print(buffer, context, (unsigned)hash_id, 0);
+ rhash_free(context);
+ _RETURN_STRINGL(buffer, length);
+}
+
+/* Calculate hash for a php stream. Returns SUCCESS or FAILURE. */
+static strsize_t _php_rhash_stream(INTERNAL_FUNCTION_PARAMETERS, rhash context, php_stream *stream, zend_long start, zend_long size)
+{
+ char data[8192];
+ if (context == NULL) {
+ rhash_object *obj = get_rhash_object(getThis());
+ if ((context = obj->rhash) == NULL) return FAILURE;
+ }
+
+ if (start >= 0) {
+ if (php_stream_seek(stream, start, SEEK_SET) < 0) return FAILURE;
+ }
+
+ if (size >= 0) {
+ while (size > 0 && !php_stream_eof(stream)) {
+ int length = php_stream_read(stream, data, (size < 8192 ? size : 8192));
+ if (!length) return FAILURE;
+ size -= length;
+ rhash_update(context, data, length);
+ }
+ } else {
+ while (!php_stream_eof(stream)) {
+ int length = php_stream_read(stream, data, 8192);
+ if (!length) return FAILURE;
+ rhash_update(context, data, length);
+ }
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+/* Calculate hash of the given file or its part. Returns SUCCESS or FAILURE. */
+static strsize_t _php_rhash_file(INTERNAL_FUNCTION_PARAMETERS, rhash context, char* path, zend_long start, zend_long size)
+{
+ strsize_t res;
+ php_stream *stream = php_stream_open_wrapper(path, "rb", 0, 0);
+ if (stream == NULL) return FAILURE;
+
+ res = _php_rhash_stream(INTERNAL_FUNCTION_PARAM_PASSTHRU, context, stream, start, size);
+ php_stream_close(stream);
+ return res;
+}
+/* }}} */
+
+/* {{{ proto string rhash_file(int hash_id, string path)
+ Computes and returns message digest for a file. Returns NULL on failure. */
+PHP_FUNCTION(rhash_file) {
+ zend_long hash_id = 0;
+ char *path;
+ strsize_t path_len;
+ rhash context = NULL;
+ char buffer[130];
+ int buffer_length;
+ strsize_t res;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lp", &hash_id, &path, &path_len) == FAILURE) {
+ RETURN_NULL();
+ }
+ if (!hash_id || !(context = rhash_init(hash_id))) {
+ RETURN_NULL()
+ }
+ res = _php_rhash_file(INTERNAL_FUNCTION_PARAM_PASSTHRU, context, path, -1, -1);
+ rhash_final(context, 0);
+ buffer_length = rhash_print(buffer, context, hash_id, 0);
+ rhash_free(context);
+
+ /* return NULL on failure */
+ if (res != SUCCESS) {
+ RETURN_NULL();
+ }
+ _RETURN_STRINGL(buffer, buffer_length);
+}
+/* }}} */
+
+/* {{{ proto string rhash_magnet(int hash_id, string path)
+ Computes and returns magnet link for a file. Returns NULL on failure. */
+PHP_FUNCTION(rhash_magnet) {
+ zend_long hash_id = 0;
+ char *path;
+ strsize_t path_len;
+ rhash context = NULL;
+ zend_string* str;
+ size_t buffer_size;
+ strsize_t res;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lp", &hash_id, &path, &path_len) == FAILURE) {
+ RETURN_NULL();
+ }
+ if (!hash_id || !(context = rhash_init(hash_id))) {
+ RETURN_NULL();
+ }
+ res = _php_rhash_file(INTERNAL_FUNCTION_PARAM_PASSTHRU, context, path, -1, -1);
+ if (res != SUCCESS) RETURN_NULL();
+ rhash_final(context, 0);
+
+ buffer_size = rhash_print_magnet(0, path, context, hash_id, RHPR_FILESIZE);
+
+ str = zend_string_alloc(buffer_size - 1, 0);
+ if (!str) {
+ rhash_free(context);
+ RETURN_NULL();
+ }
+
+ rhash_print_magnet(str->val, path, context, hash_id, RHPR_FILESIZE);
+ rhash_free(context);
+ RETURN_NEW_STR(str);
+}
+/* }}} */
+
+
+/* RHash class methods */
+
+/* {{{ proto RHash::__construct([int hash_id])
+ Creates new RHash object */
+PHP_METHOD(RHash, __construct)
+{
+ zend_long hash_id = 0;
+ rhash context = NULL;
+ rhash_object *obj;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &hash_id) == FAILURE) {
+ RETURN_NULL();
+ }
+ if (!hash_id)
+ hash_id = RHASH_ALL_HASHES;
+ if (!(context = rhash_init(hash_id))) {
+ RETURN_NULL();
+ }
+ rhash_set_autofinal(context, 0);
+ obj = get_rhash_object(getThis());
+ obj->rhash = context;
+}
+/* }}} */
+
+/* {{{ proto RHash RHash::update(string message)
+ Updates RHash object with new data chunk and returns $this */
+PHP_METHOD(RHash, update)
+{
+ char *s;
+ strsize_t s_len;
+ zval *object = getThis();
+ rhash_object *obj = get_rhash_object(object);
+
+ if (obj->rhash == NULL ||
+ zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &s, &s_len) == FAILURE) {
+ RETURN_FALSE;
+ }
+ rhash_update(obj->rhash, s, s_len);
+ Z_ADDREF(*object);
+ *return_value = *object;
+}
+/* }}} */
+
+/* {{{ proto boolean RHash::update_stream(resource handle[, int start[, int size]])
+ Returns true if successfully calculated hashes for a (part of) stream, false on error */
+PHP_METHOD(RHash, update_stream)
+{
+ zval *handle;
+ strsize_t res;
+ zend_long start = -1, size = -1;
+ php_stream *stream;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|ll", &handle, &start, &size) == FAILURE) {
+ RETURN_FALSE;
+ }
+#if PHP_MAJOR_VERSION < 7
+ php_stream_from_zval_no_verify(stream, &handle);
+#else
+ php_stream_from_zval_no_verify(stream, handle);
+#endif
+ if (stream == NULL) RETURN_FALSE;
+ res = _php_rhash_stream(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, stream, start, size);
+ RETURN_BOOL(res == SUCCESS);
+}
+/* }}} */
+
+/* {{{ proto boolean RHash::update_file(string path[, int start[, int size]])
+ Returns true if successfully calculated hashes for a (part of) file, false on error */
+PHP_METHOD(RHash, update_file)
+{
+ char *path;
+ strsize_t len;
+ zend_long start = -1, size = -1;
+ strsize_t res = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|ll", &path, &len, &start, &size);
+ if (res == SUCCESS) {
+ res = _php_rhash_file(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, path, start, size);
+ }
+ RETURN_BOOL(res == SUCCESS);
+}
+/* }}} */
+
+/* {{{ proto RHash RHash::final()
+ Finalizes calculation for all hashed data and returns $this */
+PHP_METHOD(RHash, final)
+{
+ zval *object = getThis();
+ rhash_object *obj = get_rhash_object(object);
+ if (obj->rhash == NULL) RETURN_FALSE;
+ rhash_final(obj->rhash, NULL);
+ Z_ADDREF(*object);
+ *return_value = *object;
+}
+/* }}} */
+
+/* {{{ proto RHash RHash::reset()
+ Resets RHash object to initial state and returns $this */
+PHP_METHOD(RHash, reset)
+{
+ zval *object = getThis();
+ rhash_object *obj = get_rhash_object(object);
+ if (obj->rhash == NULL) RETURN_FALSE;
+ rhash_reset(obj->rhash);
+ Z_ADDREF(*object);
+ *return_value = *object;
+}
+/* }}} */
+
+/* {{{ proto int RHash::hashed_length()
+ Returns length in bytes of the hashed data */
+PHP_METHOD(RHash, hashed_length)
+{
+ rhash_object *obj = get_rhash_object(getThis());
+ if (obj->rhash == NULL) RETURN_FALSE;
+ RETURN_LONG((long)obj->rhash->msg_size);
+}
+/* }}} */
+
+/* {{{ _php_get_hash(RHash this_class[, int hash_id], int print_flags)
+ Returns calculated hash in the specified format */
+static void _php_get_hash(INTERNAL_FUNCTION_PARAMETERS, int print_flags)
+{
+ zend_long hash_id = 0;
+ char buffer[130];
+ int length;
+ rhash_object *obj = get_rhash_object(getThis());
+ if (obj->rhash == NULL ||
+ zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &hash_id) == FAILURE) {
+ RETURN_FALSE;
+ }
+ length = rhash_print(buffer, obj->rhash, hash_id, print_flags);
+ _RETURN_STRINGL(buffer, length)
+}
+/* }}} */
+
+/* {{{ proto string RHash::hash([int hash_id])
+ Returns hash value in default format */
+PHP_METHOD(RHash, hash)
+{
+ _php_get_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
+}
+/* }}} */
+
+/* {{{ proto string RHash::raw([int hash_id])
+ Returns hash value as raw bytes */
+PHP_METHOD(RHash, raw)
+{
+ _php_get_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, RHPR_RAW);
+}
+/* }}} */
+
+/* {{{ proto string RHash::hex([int hash_id])
+ Returns hash value as hexadecimal string */
+PHP_METHOD(RHash, hex)
+{
+ _php_get_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, RHPR_HEX);
+}
+/* }}} */
+
+/* {{{ proto string RHash::base32([int hash_id])
+ Returns hash value as base32 string */
+PHP_METHOD(RHash, base32)
+{
+ _php_get_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, RHPR_BASE32);
+}
+/* }}} */
+
+/* {{{ proto string RHash::base64([int hash_id])
+ Returns hash value as base64 string */
+PHP_METHOD(RHash, base64)
+{
+ _php_get_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, RHPR_BASE64);
+}
+/* }}} */
+
+/* {{{ proto string RHash::magnet([string filename])
+ Returns magnet link with all hashes computed by the RHash object */
+PHP_METHOD(RHash, magnet)
+{
+ char *s = 0;
+ strsize_t s_len;
+ size_t buf_size;
+ zend_string *magnet_str;
+ rhash_object *obj = get_rhash_object(getThis());
+
+ if (obj->rhash == NULL ||
+ zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &s, &s_len) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ buf_size = rhash_print_magnet(0, s, obj->rhash, RHASH_ALL_HASHES, RHPR_FILESIZE);
+ magnet_str = zend_string_alloc(buf_size - 1, 0);
+ if (!magnet_str) RETURN_FALSE;
+
+ rhash_print_magnet(magnet_str->val, s, obj->rhash, RHASH_ALL_HASHES, RHPR_FILESIZE);
+ RETURN_NEW_STR(magnet_str);
+}
+/* }}} */
diff --git a/bindings/php/php_rhash.h b/bindings/php/php_rhash.h
index d8b603dc..1139c281 100644
--- a/bindings/php/php_rhash.h
+++ b/bindings/php/php_rhash.h
@@ -1,34 +1,34 @@
-#ifndef PHP_RHASH_H
-#define PHP_RHASH_H
-
-extern zend_module_entry rhash_module_entry;
-#define phpext_rhash_ptr &rhash_module_entry
-
-PHP_MINIT_FUNCTION(rhash);
-PHP_MSHUTDOWN_FUNCTION(rhash);
-PHP_MINFO_FUNCTION(rhash);
-
-PHP_FUNCTION(rhash_count);
-PHP_FUNCTION(rhash_get_digest_size);
-PHP_FUNCTION(rhash_get_name);
-PHP_FUNCTION(rhash_is_base32);
-PHP_FUNCTION(rhash_msg);
-PHP_FUNCTION(rhash_file);
-PHP_FUNCTION(rhash_magnet);
-
-PHP_METHOD(RHash, __construct);
-PHP_METHOD(RHash, update);
-PHP_METHOD(RHash, update_stream);
-PHP_METHOD(RHash, update_file);
-PHP_METHOD(RHash, final);
-PHP_METHOD(RHash, reset);
-PHP_METHOD(RHash, hashed_length);
-
-PHP_METHOD(RHash, hash);
-PHP_METHOD(RHash, raw);
-PHP_METHOD(RHash, hex);
-PHP_METHOD(RHash, base32);
-PHP_METHOD(RHash, base64);
-PHP_METHOD(RHash, magnet);
-
-#endif /* PHP_RHASH_H */
+#ifndef PHP_RHASH_H
+#define PHP_RHASH_H
+
+extern zend_module_entry rhash_module_entry;
+#define phpext_rhash_ptr &rhash_module_entry
+
+PHP_MINIT_FUNCTION(rhash);
+PHP_MSHUTDOWN_FUNCTION(rhash);
+PHP_MINFO_FUNCTION(rhash);
+
+PHP_FUNCTION(rhash_count);
+PHP_FUNCTION(rhash_get_digest_size);
+PHP_FUNCTION(rhash_get_name);
+PHP_FUNCTION(rhash_is_base32);
+PHP_FUNCTION(rhash_msg);
+PHP_FUNCTION(rhash_file);
+PHP_FUNCTION(rhash_magnet);
+
+PHP_METHOD(RHash, __construct);
+PHP_METHOD(RHash, update);
+PHP_METHOD(RHash, update_stream);
+PHP_METHOD(RHash, update_file);
+PHP_METHOD(RHash, final);
+PHP_METHOD(RHash, reset);
+PHP_METHOD(RHash, hashed_length);
+
+PHP_METHOD(RHash, hash);
+PHP_METHOD(RHash, raw);
+PHP_METHOD(RHash, hex);
+PHP_METHOD(RHash, base32);
+PHP_METHOD(RHash, base64);
+PHP_METHOD(RHash, magnet);
+
+#endif /* PHP_RHASH_H */
diff --git a/bindings/php/tests/001.phpt b/bindings/php/tests/001.phpt
index f7dcc417..8dddcdbc 100644
--- a/bindings/php/tests/001.phpt
+++ b/bindings/php/tests/001.phpt
@@ -1,20 +1,20 @@
---TEST--
-test RHash global functions
---FILE--
-= 26) . "\n";
-echo rhash_get_digest_size(RHASH_CRC32) . "\n";
-echo (int)rhash_is_base32(RHASH_MD5) . "\n";
-echo (int)rhash_is_base32(RHASH_AICH) . "\n";
-echo rhash_get_name(RHASH_SHA1) . "\n";
-echo rhash_msg(RHASH_TTH, 'abc') . "\n";
-echo "Done\n";
-?>
---EXPECTF--
-1
-4
-0
-1
-SHA1
-asd4ujseh5m47pdyb46kbtsqtsgdklbhyxomuia
-Done
+--TEST--
+test RHash global functions
+--FILE--
+= 26) . "\n";
+echo rhash_get_digest_size(RHASH_CRC32) . "\n";
+echo (int)rhash_is_base32(RHASH_MD5) . "\n";
+echo (int)rhash_is_base32(RHASH_AICH) . "\n";
+echo rhash_get_name(RHASH_SHA1) . "\n";
+echo rhash_msg(RHASH_TTH, 'abc') . "\n";
+echo "Done\n";
+?>
+--EXPECTF--
+1
+4
+0
+1
+SHA1
+asd4ujseh5m47pdyb46kbtsqtsgdklbhyxomuia
+Done
diff --git a/bindings/php/tests/002.phpt b/bindings/php/tests/002.phpt
index 4396e458..a708bea9 100644
--- a/bindings/php/tests/002.phpt
+++ b/bindings/php/tests/002.phpt
@@ -1,82 +1,82 @@
---TEST--
-test RHash basic methods
---FILE--
-update('a')->final();
-echo $r->hashed_length() . "\n";
-
-echo $r->hash(RHASH_CRC32) . "\n";
-echo $r->hash(RHASH_CRC32C) . "\n";
-echo $r->hash(RHASH_MD4) . "\n";
-echo $r->hash(RHASH_MD5) . "\n";
-echo $r->hash(RHASH_SHA1) . "\n";
-echo $r->hash(RHASH_TIGER) . "\n";
-echo $r->hash(RHASH_TTH) . "\n";
-echo strlen($r->hash(RHASH_BTIH)) . "\n";
-echo $r->hash(RHASH_ED2K) . "\n";
-echo $r->hash(RHASH_AICH) . "\n";
-echo $r->hash(RHASH_WHIRLPOOL) . "\n";
-echo $r->hash(RHASH_RIPEMD160) . "\n";
-echo $r->hash(RHASH_GOST94) . "\n";
-echo $r->hash(RHASH_GOST94_CRYPTOPRO) . "\n";
-echo $r->hash(RHASH_GOST12_256) . "\n";
-echo $r->hash(RHASH_GOST12_512) . "\n";
-echo $r->hash(RHASH_HAS160) . "\n";
-echo $r->hash(RHASH_SNEFRU128) . "\n";
-echo $r->hash(RHASH_SNEFRU256) . "\n";
-echo $r->hash(RHASH_SHA224) . "\n";
-echo $r->hash(RHASH_SHA256) . "\n";
-echo $r->hash(RHASH_SHA384) . "\n";
-echo $r->hash(RHASH_SHA512) . "\n";
-echo $r->hash(RHASH_SHA3_224) . "\n";
-echo $r->hash(RHASH_SHA3_256) . "\n";
-echo $r->hash(RHASH_SHA3_384) . "\n";
-echo $r->hash(RHASH_SHA3_512) . "\n";
-echo $r->hash(RHASH_EDONR256) . "\n";
-echo $r->hash(RHASH_EDONR512) . "\n";
-echo $r->raw(RHASH_SHA1) . "\n";
-echo $r->hex(RHASH_TTH) . "\n";
-echo $r->base32(RHASH_SHA1) . "\n";
-echo $r->base64(RHASH_SHA1) . "\n";
-$r = new RHash(RHASH_CRC32 | RHASH_AICH);
-echo $r->update('a')->final()->magnet('file.txt') . "\n";
-echo "Done\n";
-?>
---EXPECTF--
-1
-e8b7be43
-c1d04330
-bde52cb31de33e46245e05fbdbd6fb24
-0cc175b9c0f1b6a831c399e269772661
-86f7e437faa5a7fce15d1ddcb9eaeaea377667b8
-77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809
-czquwh3iyxbf5l3bgyugzhassmxu647ip2ike4y
-40
-bde52cb31de33e46245e05fbdbd6fb24
-q336in72uwt7zyk5dxolt2xk5i3xmz5y
-8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a
-0bdc9d2d256b3ee9daae347be6f4dc835a467ffe
-d42c539e367c66e9c88a801f6649349c21871b4344c6a573f849fdce62f314dd
-e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011
-ba31099b9cc84ec2a671e9313572378920a705b363b031a1cb4fc03e01ce8df3
-8b2a40ecab7b7496bc4cc0f773595452baf658849b495acc3ba017206810efb00420ccd73fb3297e0f7890941b84ac4a8bc27e3c95e1f97c094609e2136abb7e
-4872bcbc4cd0f0a9dc7c2f7045e5b43b6c830db8
-bf5ce540ae51bc50399f96746c5a15bd
-45161589ac317be0ceba70db2573ddda6e668a31984b39bf65e4b664b584c63d
-abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5
-ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb
-54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31
-1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75
-9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b
-80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b
-1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9
-697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a
-943aa9225a2cf154ec2e4dd81237720ba538ca8df2fd83c0b893c5d265f353a0
-b59ec44f7beef8a04ceed38a973d77c65e22e9458d5f67b497948da34986c093b5efc5483fbee55f2f740fcad31f18d80db44bb6b8843e7fd599188e7c07233b
-7]ܹ7vg
-16614b1f68c5c25eaf6136286c9c12932f4f73e87e90a273
-q336in72uwt7zyk5dxolt2xk5i3xmz5y
-hvfkN/qlp/zhXR3cuerq6jd2Z7g=
-magnet:?xl=1&dn=file.txt&xt=urn:aich:q336in72uwt7zyk5dxolt2xk5i3xmz5y&xt=urn:crc32:e8b7be43
-Done
+--TEST--
+test RHash basic methods
+--FILE--
+update('a')->final();
+echo $r->hashed_length() . "\n";
+
+echo $r->hash(RHASH_CRC32) . "\n";
+echo $r->hash(RHASH_CRC32C) . "\n";
+echo $r->hash(RHASH_MD4) . "\n";
+echo $r->hash(RHASH_MD5) . "\n";
+echo $r->hash(RHASH_SHA1) . "\n";
+echo $r->hash(RHASH_TIGER) . "\n";
+echo $r->hash(RHASH_TTH) . "\n";
+echo strlen($r->hash(RHASH_BTIH)) . "\n";
+echo $r->hash(RHASH_ED2K) . "\n";
+echo $r->hash(RHASH_AICH) . "\n";
+echo $r->hash(RHASH_WHIRLPOOL) . "\n";
+echo $r->hash(RHASH_RIPEMD160) . "\n";
+echo $r->hash(RHASH_GOST94) . "\n";
+echo $r->hash(RHASH_GOST94_CRYPTOPRO) . "\n";
+echo $r->hash(RHASH_GOST12_256) . "\n";
+echo $r->hash(RHASH_GOST12_512) . "\n";
+echo $r->hash(RHASH_HAS160) . "\n";
+echo $r->hash(RHASH_SNEFRU128) . "\n";
+echo $r->hash(RHASH_SNEFRU256) . "\n";
+echo $r->hash(RHASH_SHA224) . "\n";
+echo $r->hash(RHASH_SHA256) . "\n";
+echo $r->hash(RHASH_SHA384) . "\n";
+echo $r->hash(RHASH_SHA512) . "\n";
+echo $r->hash(RHASH_SHA3_224) . "\n";
+echo $r->hash(RHASH_SHA3_256) . "\n";
+echo $r->hash(RHASH_SHA3_384) . "\n";
+echo $r->hash(RHASH_SHA3_512) . "\n";
+echo $r->hash(RHASH_EDONR256) . "\n";
+echo $r->hash(RHASH_EDONR512) . "\n";
+echo $r->raw(RHASH_SHA1) . "\n";
+echo $r->hex(RHASH_TTH) . "\n";
+echo $r->base32(RHASH_SHA1) . "\n";
+echo $r->base64(RHASH_SHA1) . "\n";
+$r = new RHash(RHASH_CRC32 | RHASH_AICH);
+echo $r->update('a')->final()->magnet('file.txt') . "\n";
+echo "Done\n";
+?>
+--EXPECTF--
+1
+e8b7be43
+c1d04330
+bde52cb31de33e46245e05fbdbd6fb24
+0cc175b9c0f1b6a831c399e269772661
+86f7e437faa5a7fce15d1ddcb9eaeaea377667b8
+77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809
+czquwh3iyxbf5l3bgyugzhassmxu647ip2ike4y
+40
+bde52cb31de33e46245e05fbdbd6fb24
+q336in72uwt7zyk5dxolt2xk5i3xmz5y
+8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a
+0bdc9d2d256b3ee9daae347be6f4dc835a467ffe
+d42c539e367c66e9c88a801f6649349c21871b4344c6a573f849fdce62f314dd
+e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011
+ba31099b9cc84ec2a671e9313572378920a705b363b031a1cb4fc03e01ce8df3
+8b2a40ecab7b7496bc4cc0f773595452baf658849b495acc3ba017206810efb00420ccd73fb3297e0f7890941b84ac4a8bc27e3c95e1f97c094609e2136abb7e
+4872bcbc4cd0f0a9dc7c2f7045e5b43b6c830db8
+bf5ce540ae51bc50399f96746c5a15bd
+45161589ac317be0ceba70db2573ddda6e668a31984b39bf65e4b664b584c63d
+abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5
+ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb
+54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31
+1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75
+9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b
+80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b
+1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9
+697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a
+943aa9225a2cf154ec2e4dd81237720ba538ca8df2fd83c0b893c5d265f353a0
+b59ec44f7beef8a04ceed38a973d77c65e22e9458d5f67b497948da34986c093b5efc5483fbee55f2f740fcad31f18d80db44bb6b8843e7fd599188e7c07233b
+7]ܹ7vg
+16614b1f68c5c25eaf6136286c9c12932f4f73e87e90a273
+q336in72uwt7zyk5dxolt2xk5i3xmz5y
+hvfkN/qlp/zhXR3cuerq6jd2Z7g=
+magnet:?xl=1&dn=file.txt&xt=urn:aich:q336in72uwt7zyk5dxolt2xk5i3xmz5y&xt=urn:crc32:e8b7be43
+Done
diff --git a/bindings/php/tests/003.phpt b/bindings/php/tests/003.phpt
index 43211178..e84673c8 100644
--- a/bindings/php/tests/003.phpt
+++ b/bindings/php/tests/003.phpt
@@ -1,31 +1,31 @@
---TEST--
-test RHash file methods
---FILE--
-update_stream($handle, 3, 3);
-echo $r->final()->magnet($filename) . "\n";
-fclose($handle);
-
-$r->reset()->update_file($filename);
-echo $r->final()->magnet($filename) . "\n";
-$r->reset()->update_file($filename, 2, 1);
-echo $r->final()->magnet($filename) . "\n";
-
-// test global file reading functions
-echo rhash_file(RHASH_TTH, $filename) . "\n";
-echo rhash_magnet(RHASH_TTH, $filename) . "\n";
-unlink($filename);
-echo "Done\n";
-?>
---EXPECTF--
-magnet:?xl=3&dn=003_test.txt&xt=urn:md5:900150983cd24fb0d6963f7d28e17f72
-magnet:?xl=12&dn=003_test.txt&xt=urn:md5:5a73501e89118bfc45e19f26c0bb2c33
-magnet:?xl=13&dn=003_test.txt&xt=urn:md5:c81e728d9d4c2f636f067f89cc14862c
-2yu5rdna7qwl6e3ivtgzleuft766u72dxnlzdri
-magnet:?xl=9&dn=003_test.txt&xt=urn:tree:tiger:2yu5rdna7qwl6e3ivtgzleuft766u72dxnlzdri
-Done
+--TEST--
+test RHash file methods
+--FILE--
+update_stream($handle, 3, 3);
+echo $r->final()->magnet($filename) . "\n";
+fclose($handle);
+
+$r->reset()->update_file($filename);
+echo $r->final()->magnet($filename) . "\n";
+$r->reset()->update_file($filename, 2, 1);
+echo $r->final()->magnet($filename) . "\n";
+
+// test global file reading functions
+echo rhash_file(RHASH_TTH, $filename) . "\n";
+echo rhash_magnet(RHASH_TTH, $filename) . "\n";
+unlink($filename);
+echo "Done\n";
+?>
+--EXPECTF--
+magnet:?xl=3&dn=003_test.txt&xt=urn:md5:900150983cd24fb0d6963f7d28e17f72
+magnet:?xl=12&dn=003_test.txt&xt=urn:md5:5a73501e89118bfc45e19f26c0bb2c33
+magnet:?xl=13&dn=003_test.txt&xt=urn:md5:c81e728d9d4c2f636f067f89cc14862c
+2yu5rdna7qwl6e3ivtgzleuft766u72dxnlzdri
+magnet:?xl=9&dn=003_test.txt&xt=urn:tree:tiger:2yu5rdna7qwl6e3ivtgzleuft766u72dxnlzdri
+Done
diff --git a/bindings/python/.gitignore b/bindings/python/.gitignore
index 0d20b648..94487b95 100644
--- a/bindings/python/.gitignore
+++ b/bindings/python/.gitignore
@@ -1 +1 @@
-*.pyc
+*.pyc
diff --git a/bindings/python/rhash.py b/bindings/python/rhash.py
index 1432a4e9..51969939 100644
--- a/bindings/python/rhash.py
+++ b/bindings/python/rhash.py
@@ -1,293 +1,293 @@
-# Python Bindings for Librhash
-# Copyright (c) 2011-2012, Sergey Basalaev
-# Librhash is (c) 2011-2012, Aleksey Kravchenko
-#
-# 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.
-#
-# This library 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. Use it at your own risk!
-
-"""Python bindings for librhash
-
-Librhash is a library for computing and verifying hash sums
-that supports many hashing algorithms. The simplest way to
-calculate hash of a message or a file is by using one of
-the functions:
-
-hash_for_msg(message, hash_id)
-hash_for_file(filename, hash_id)
-magnet_for_file(filename, hash_ids)
-
-Here hash_id is one of the constants CRC32, CRC32C, MD4, MD5,
-SHA1, TIGER, TTH, BTIH, ED2K, AICH, WHIRLPOOL, RIPEMD160,
-GOST94, GOST94_CRYPTOPRO, GOST12_256, GOST12_512, HAS160,
-SHA224, SHA256, SHA384, SHA512, SHA3_224, SHA3_256, SHA3_384, SHA3_512,
-EDONR256, EDONR512, SNEFRU128, SNEFRU256.
-The first two functions will return the default text representation
-of the message digest they compute. The latter will return the
-magnet link for the file. In this function you can OR-combine
-several hash_ids, like
-
->>> print magnet_for_file('rhash.py', CRC32 | MD5)
-magnet:?xl=6041&dn=rhash.py&xt=urn:crc32:f5866f7a&xt=urn:md5:
-f88e6c1620361da9d04e2a2a1c788059
-
-Next, this module provides a class to calculate several hashes
-simultaneously in an incremental way. Example of using it:
-
->>> hasher = RHash(CRC32 | MD5)
->>> hasher.update('Hello, ')
->>> hasher << 'world' << '!'
->>> hasher.finish()
->>> print hasher.HEX(CRC32)
-EBE6C6E6
->>> print hasher.hex(MD5)
-6cd3556deb0da54bca060b4c39479839
-
-In this example RHash object is first created for a set of
-hashing algorithms. Then, data for hashing is given in chunks
-with methods update(message) and update_file(filename).
-Finally, call finish() to end up all remaining calculations.
-
-To receive text represenation of the message digest use one
-of the methods hex(), HEX(), base32(), BASE32(), base64() and
-BASE64(). The hash() method outputs message digest in its
-default format. Binary message digest may be obtained with
-raw(). All of these methods accept hash_id as argument.
-It may be omitted if RHash was created to compute hash
-for only a single hashing algorithm.
-
-Method magnet(filename) will generate magnet link with all
-hashes computed by the RHash object.
-"""
-
-# public API
-__all__ = [
- 'ALL', 'CRC32', 'CRC3C', 'MD4', 'MD5', 'SHA1', 'TIGER', 'TTH',
- 'BTIH', 'ED2K', 'AICH', 'WHIRLPOOL', 'RIPEMD160', 'GOST94',
- 'GOST94_CRYPTOPRO', 'GOST12_256', 'GOST12_512', 'HAS160',
- 'SHA224', 'SHA256', 'SHA384', 'SHA512', 'EDONR256', 'EDONR512',
- 'SHA3_224', 'SHA3_256', 'SHA3_384', 'SHA3_512', 'SNEFRU128', 'SNEFRU256',
- 'RHash', 'hash_for_msg', 'hash_for_file', 'magnet_for_file']
-
-import sys
-from ctypes import (
- CDLL, c_char_p, c_int, c_size_t, c_uint, c_void_p, create_string_buffer)
-
-# initialization
-if sys.platform == 'win32':
- LIBNAME = 'librhash.dll'
-elif sys.platform == 'darwin':
- LIBNAME = 'librhash.0.dylib'
-elif sys.platform == 'cygwin':
- LIBNAME = 'cygrhash.dll'
-elif sys.platform == 'msys':
- LIBNAME = 'msys-rhash.dll'
-else:
- LIBNAME = 'librhash.so.0'
-LIBRHASH = CDLL(LIBNAME)
-LIBRHASH.rhash_library_init()
-
-# function prototypes
-LIBRHASH.rhash_init.argtypes = [c_uint]
-LIBRHASH.rhash_init.restype = c_void_p
-LIBRHASH.rhash_free.argtypes = [c_void_p]
-LIBRHASH.rhash_reset.argtypes = [c_void_p]
-LIBRHASH.rhash_update.argtypes = [c_void_p, c_char_p, c_size_t]
-LIBRHASH.rhash_final.argtypes = [c_void_p, c_char_p]
-LIBRHASH.rhash_print.argtypes = [c_char_p, c_void_p, c_uint, c_int]
-LIBRHASH.rhash_print.restype = c_size_t
-LIBRHASH.rhash_print_magnet.argtypes = [
- c_char_p, c_char_p, c_void_p, c_uint, c_int]
-LIBRHASH.rhash_print_magnet.restype = c_size_t
-LIBRHASH.rhash_transmit.argtypes = [c_uint, c_void_p, c_size_t, c_size_t]
-
-# conversion of a string to binary data with Python 2/3 compatibility
-if sys.version < '3':
- def _s2b(string):
- """Python 2: just return the string"""
- return string
- def _msg_to_bytes(msg):
- """convert the msg parameter to a string"""
- if isinstance(msg, str):
- return msg
- return str(msg)
-else:
- import codecs
- def _s2b(string):
- """Python 3: convert the string to binary data"""
- return codecs.utf_8_encode(string)[0]
- def _msg_to_bytes(msg):
- """convert the msg parameter to binary data"""
- if isinstance(msg, bytes):
- return msg
- if isinstance(msg, str):
- return _s2b(msg)
- return _s2b(str(msg))
-
-# hash_id values
-CRC32 = 0x01
-MD4 = 0x02
-MD5 = 0x04
-SHA1 = 0x08
-TIGER = 0x10
-TTH = 0x20
-BTIH = 0x40
-ED2K = 0x80
-AICH = 0x100
-WHIRLPOOL = 0x200
-RIPEMD160 = 0x400
-GOST94 = 0x800
-GOST94_CRYPTOPRO = 0x1000
-HAS160 = 0x2000
-GOST12_256 = 0x4000
-GOST12_512 = 0x8000
-SHA224 = 0x10000
-SHA256 = 0x20000
-SHA384 = 0x40000
-SHA512 = 0x80000
-EDONR256 = 0x100000
-EDONR512 = 0x200000
-SHA3_224 = 0x0400000
-SHA3_256 = 0x0800000
-SHA3_384 = 0x1000000
-SHA3_512 = 0x2000000
-CRC32C = 0x4000000
-SNEFRU128 = 0x08000000
-SNEFRU256 = 0x10000000
-ALL = SNEFRU256*2 - 1
-
-
-#rhash_print values
-RHPR_RAW = 1
-RHPR_HEX = 2
-RHPR_BASE32 = 3
-RHPR_BASE64 = 4
-RHPR_UPPERCASE = 8
-RHPR_NO_MAGNET = 0x20
-RHPR_FILESIZE = 0x40
-
-class RHash(object):
- 'Incremental hasher'
-
- def __init__(self, hash_ids):
- if hash_ids == 0:
- self._ctx = None
- raise ValueError('Invalid argument')
- self._ctx = LIBRHASH.rhash_init(hash_ids)
- #switching off the autofinal feature
- LIBRHASH.rhash_transmit(5, self._ctx, 0, 0)
-
- def __del__(self):
- if self._ctx != None:
- LIBRHASH.rhash_free(self._ctx)
-
- def reset(self):
- """reset this object to initial state"""
- LIBRHASH.rhash_reset(self._ctx)
- return self
-
- def update(self, message):
- """update this object with new data chunk"""
- data = _msg_to_bytes(message)
- LIBRHASH.rhash_update(self._ctx, data, len(data))
- return self
-
- def __lshift__(self, message):
- return self.update(message)
-
- def update_file(self, filename):
- """Update this object with data from the given file."""
- file = open(filename, 'rb')
- buf = file.read(8192)
- while len(buf) > 0:
- self.update(buf)
- buf = file.read(8192)
- file.close()
- return self
-
- def finish(self):
- """Calculate hashes for all the data buffered by
- the update() method.
- """
- LIBRHASH.rhash_final(self._ctx, None)
- return self
-
- def _print(self, hash_id, flags):
- """Retrieve the message hash in required format."""
- buf = create_string_buffer(130)
- size = LIBRHASH.rhash_print(buf, self._ctx, hash_id, flags)
- if (flags & 3) == RHPR_RAW:
- return buf[0:size]
- else:
- return buf[0:size].decode()
-
- def raw(self, hash_id=0):
- """Returns the message hash as raw binary data."""
- return self._print(hash_id, RHPR_RAW)
-
- def hex(self, hash_id=0):
- """Returns the message hash as a hexadecimal lower-case string."""
- return self._print(hash_id, RHPR_HEX)
-
- def base32(self, hash_id=0):
- """Returns the message hash as a Base32 lower-case string."""
- return self._print(hash_id, RHPR_BASE32)
-
- def base64(self, hash_id=0):
- """Returns the message hash as a Base64 string."""
- return self._print(hash_id, RHPR_BASE64)
-
- # pylint: disable=invalid-name
- def HEX(self, hash_id=0):
- """Returns the message hash as a hexadecimal upper-case string."""
- return self._print(hash_id, RHPR_HEX | RHPR_UPPERCASE)
-
- def BASE32(self, hash_id=0):
- """Returns the message hash as a Base32 upper-case string."""
- return self._print(hash_id, RHPR_BASE32 | RHPR_UPPERCASE)
- # pylint: enable=invalid-name
-
- def magnet(self, filepath):
- """Returns magnet link with all hashes computed by
- this object."""
- size = LIBRHASH.rhash_print_magnet(
- None, _s2b(filepath), self._ctx, ALL, RHPR_FILESIZE)
- buf = create_string_buffer(size)
- LIBRHASH.rhash_print_magnet(
- buf, _s2b(filepath), self._ctx, ALL, RHPR_FILESIZE)
- return buf[0:size-1].decode('utf-8')
-
- def hash(self, hash_id=0):
- """Returns the message digest for the given hash function
- as a string in the default format."""
- return self._print(hash_id, 0)
-
- def __str__(self):
- return self._print(0, 0)
-
-def hash_for_msg(message, hash_id):
- """Computes and returns the message digest (in its default format)
- of the message"""
- handle = RHash(hash_id)
- handle.update(message).finish()
- return str(handle)
-
-def hash_for_file(filename, hash_id):
- """Computes and returns the message digest (in its default format)
- of the file content"""
- handle = RHash(hash_id)
- handle.update_file(filename).finish()
- return str(handle)
-
-def magnet_for_file(filename, hash_mask):
- """Computes and returns the magnet link for the file."""
- handle = RHash(hash_mask)
- handle.update_file(filename).finish()
- return handle.magnet(filename)
+# Python Bindings for Librhash
+# Copyright (c) 2011-2012, Sergey Basalaev
+# Librhash is (c) 2011-2012, Aleksey Kravchenko
+#
+# 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.
+#
+# This library 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. Use it at your own risk!
+
+"""Python bindings for librhash
+
+Librhash is a library for computing and verifying hash sums
+that supports many hashing algorithms. The simplest way to
+calculate hash of a message or a file is by using one of
+the functions:
+
+hash_for_msg(message, hash_id)
+hash_for_file(filename, hash_id)
+magnet_for_file(filename, hash_ids)
+
+Here hash_id is one of the constants CRC32, CRC32C, MD4, MD5,
+SHA1, TIGER, TTH, BTIH, ED2K, AICH, WHIRLPOOL, RIPEMD160,
+GOST94, GOST94_CRYPTOPRO, GOST12_256, GOST12_512, HAS160,
+SHA224, SHA256, SHA384, SHA512, SHA3_224, SHA3_256, SHA3_384, SHA3_512,
+EDONR256, EDONR512, SNEFRU128, SNEFRU256.
+The first two functions will return the default text representation
+of the message digest they compute. The latter will return the
+magnet link for the file. In this function you can OR-combine
+several hash_ids, like
+
+>>> print magnet_for_file('rhash.py', CRC32 | MD5)
+magnet:?xl=6041&dn=rhash.py&xt=urn:crc32:f5866f7a&xt=urn:md5:
+f88e6c1620361da9d04e2a2a1c788059
+
+Next, this module provides a class to calculate several hashes
+simultaneously in an incremental way. Example of using it:
+
+>>> hasher = RHash(CRC32 | MD5)
+>>> hasher.update('Hello, ')
+>>> hasher << 'world' << '!'
+>>> hasher.finish()
+>>> print hasher.HEX(CRC32)
+EBE6C6E6
+>>> print hasher.hex(MD5)
+6cd3556deb0da54bca060b4c39479839
+
+In this example RHash object is first created for a set of
+hashing algorithms. Then, data for hashing is given in chunks
+with methods update(message) and update_file(filename).
+Finally, call finish() to end up all remaining calculations.
+
+To receive text represenation of the message digest use one
+of the methods hex(), HEX(), base32(), BASE32(), base64() and
+BASE64(). The hash() method outputs message digest in its
+default format. Binary message digest may be obtained with
+raw(). All of these methods accept hash_id as argument.
+It may be omitted if RHash was created to compute hash
+for only a single hashing algorithm.
+
+Method magnet(filename) will generate magnet link with all
+hashes computed by the RHash object.
+"""
+
+# public API
+__all__ = [
+ 'ALL', 'CRC32', 'CRC3C', 'MD4', 'MD5', 'SHA1', 'TIGER', 'TTH',
+ 'BTIH', 'ED2K', 'AICH', 'WHIRLPOOL', 'RIPEMD160', 'GOST94',
+ 'GOST94_CRYPTOPRO', 'GOST12_256', 'GOST12_512', 'HAS160',
+ 'SHA224', 'SHA256', 'SHA384', 'SHA512', 'EDONR256', 'EDONR512',
+ 'SHA3_224', 'SHA3_256', 'SHA3_384', 'SHA3_512', 'SNEFRU128', 'SNEFRU256',
+ 'RHash', 'hash_for_msg', 'hash_for_file', 'magnet_for_file']
+
+import sys
+from ctypes import (
+ CDLL, c_char_p, c_int, c_size_t, c_uint, c_void_p, create_string_buffer)
+
+# initialization
+if sys.platform == 'win32':
+ LIBNAME = 'librhash.dll'
+elif sys.platform == 'darwin':
+ LIBNAME = 'librhash.0.dylib'
+elif sys.platform == 'cygwin':
+ LIBNAME = 'cygrhash.dll'
+elif sys.platform == 'msys':
+ LIBNAME = 'msys-rhash.dll'
+else:
+ LIBNAME = 'librhash.so.0'
+LIBRHASH = CDLL(LIBNAME)
+LIBRHASH.rhash_library_init()
+
+# function prototypes
+LIBRHASH.rhash_init.argtypes = [c_uint]
+LIBRHASH.rhash_init.restype = c_void_p
+LIBRHASH.rhash_free.argtypes = [c_void_p]
+LIBRHASH.rhash_reset.argtypes = [c_void_p]
+LIBRHASH.rhash_update.argtypes = [c_void_p, c_char_p, c_size_t]
+LIBRHASH.rhash_final.argtypes = [c_void_p, c_char_p]
+LIBRHASH.rhash_print.argtypes = [c_char_p, c_void_p, c_uint, c_int]
+LIBRHASH.rhash_print.restype = c_size_t
+LIBRHASH.rhash_print_magnet.argtypes = [
+ c_char_p, c_char_p, c_void_p, c_uint, c_int]
+LIBRHASH.rhash_print_magnet.restype = c_size_t
+LIBRHASH.rhash_transmit.argtypes = [c_uint, c_void_p, c_size_t, c_size_t]
+
+# conversion of a string to binary data with Python 2/3 compatibility
+if sys.version < '3':
+ def _s2b(string):
+ """Python 2: just return the string"""
+ return string
+ def _msg_to_bytes(msg):
+ """convert the msg parameter to a string"""
+ if isinstance(msg, str):
+ return msg
+ return str(msg)
+else:
+ import codecs
+ def _s2b(string):
+ """Python 3: convert the string to binary data"""
+ return codecs.utf_8_encode(string)[0]
+ def _msg_to_bytes(msg):
+ """convert the msg parameter to binary data"""
+ if isinstance(msg, bytes):
+ return msg
+ if isinstance(msg, str):
+ return _s2b(msg)
+ return _s2b(str(msg))
+
+# hash_id values
+CRC32 = 0x01
+MD4 = 0x02
+MD5 = 0x04
+SHA1 = 0x08
+TIGER = 0x10
+TTH = 0x20
+BTIH = 0x40
+ED2K = 0x80
+AICH = 0x100
+WHIRLPOOL = 0x200
+RIPEMD160 = 0x400
+GOST94 = 0x800
+GOST94_CRYPTOPRO = 0x1000
+HAS160 = 0x2000
+GOST12_256 = 0x4000
+GOST12_512 = 0x8000
+SHA224 = 0x10000
+SHA256 = 0x20000
+SHA384 = 0x40000
+SHA512 = 0x80000
+EDONR256 = 0x100000
+EDONR512 = 0x200000
+SHA3_224 = 0x0400000
+SHA3_256 = 0x0800000
+SHA3_384 = 0x1000000
+SHA3_512 = 0x2000000
+CRC32C = 0x4000000
+SNEFRU128 = 0x08000000
+SNEFRU256 = 0x10000000
+ALL = SNEFRU256*2 - 1
+
+
+#rhash_print values
+RHPR_RAW = 1
+RHPR_HEX = 2
+RHPR_BASE32 = 3
+RHPR_BASE64 = 4
+RHPR_UPPERCASE = 8
+RHPR_NO_MAGNET = 0x20
+RHPR_FILESIZE = 0x40
+
+class RHash(object):
+ 'Incremental hasher'
+
+ def __init__(self, hash_ids):
+ if hash_ids == 0:
+ self._ctx = None
+ raise ValueError('Invalid argument')
+ self._ctx = LIBRHASH.rhash_init(hash_ids)
+ #switching off the autofinal feature
+ LIBRHASH.rhash_transmit(5, self._ctx, 0, 0)
+
+ def __del__(self):
+ if self._ctx != None:
+ LIBRHASH.rhash_free(self._ctx)
+
+ def reset(self):
+ """reset this object to initial state"""
+ LIBRHASH.rhash_reset(self._ctx)
+ return self
+
+ def update(self, message):
+ """update this object with new data chunk"""
+ data = _msg_to_bytes(message)
+ LIBRHASH.rhash_update(self._ctx, data, len(data))
+ return self
+
+ def __lshift__(self, message):
+ return self.update(message)
+
+ def update_file(self, filename):
+ """Update this object with data from the given file."""
+ file = open(filename, 'rb')
+ buf = file.read(8192)
+ while len(buf) > 0:
+ self.update(buf)
+ buf = file.read(8192)
+ file.close()
+ return self
+
+ def finish(self):
+ """Calculate hashes for all the data buffered by
+ the update() method.
+ """
+ LIBRHASH.rhash_final(self._ctx, None)
+ return self
+
+ def _print(self, hash_id, flags):
+ """Retrieve the message hash in required format."""
+ buf = create_string_buffer(130)
+ size = LIBRHASH.rhash_print(buf, self._ctx, hash_id, flags)
+ if (flags & 3) == RHPR_RAW:
+ return buf[0:size]
+ else:
+ return buf[0:size].decode()
+
+ def raw(self, hash_id=0):
+ """Returns the message hash as raw binary data."""
+ return self._print(hash_id, RHPR_RAW)
+
+ def hex(self, hash_id=0):
+ """Returns the message hash as a hexadecimal lower-case string."""
+ return self._print(hash_id, RHPR_HEX)
+
+ def base32(self, hash_id=0):
+ """Returns the message hash as a Base32 lower-case string."""
+ return self._print(hash_id, RHPR_BASE32)
+
+ def base64(self, hash_id=0):
+ """Returns the message hash as a Base64 string."""
+ return self._print(hash_id, RHPR_BASE64)
+
+ # pylint: disable=invalid-name
+ def HEX(self, hash_id=0):
+ """Returns the message hash as a hexadecimal upper-case string."""
+ return self._print(hash_id, RHPR_HEX | RHPR_UPPERCASE)
+
+ def BASE32(self, hash_id=0):
+ """Returns the message hash as a Base32 upper-case string."""
+ return self._print(hash_id, RHPR_BASE32 | RHPR_UPPERCASE)
+ # pylint: enable=invalid-name
+
+ def magnet(self, filepath):
+ """Returns magnet link with all hashes computed by
+ this object."""
+ size = LIBRHASH.rhash_print_magnet(
+ None, _s2b(filepath), self._ctx, ALL, RHPR_FILESIZE)
+ buf = create_string_buffer(size)
+ LIBRHASH.rhash_print_magnet(
+ buf, _s2b(filepath), self._ctx, ALL, RHPR_FILESIZE)
+ return buf[0:size-1].decode('utf-8')
+
+ def hash(self, hash_id=0):
+ """Returns the message digest for the given hash function
+ as a string in the default format."""
+ return self._print(hash_id, 0)
+
+ def __str__(self):
+ return self._print(0, 0)
+
+def hash_for_msg(message, hash_id):
+ """Computes and returns the message digest (in its default format)
+ of the message"""
+ handle = RHash(hash_id)
+ handle.update(message).finish()
+ return str(handle)
+
+def hash_for_file(filename, hash_id):
+ """Computes and returns the message digest (in its default format)
+ of the file content"""
+ handle = RHash(hash_id)
+ handle.update_file(filename).finish()
+ return str(handle)
+
+def magnet_for_file(filename, hash_mask):
+ """Computes and returns the magnet link for the file."""
+ handle = RHash(hash_mask)
+ handle.update_file(filename).finish()
+ return handle.magnet(filename)
diff --git a/bindings/python/test_rhash.py b/bindings/python/test_rhash.py
index 9482a266..3a34e17a 100644
--- a/bindings/python/test_rhash.py
+++ b/bindings/python/test_rhash.py
@@ -1,162 +1,162 @@
-# UnitTest for Librhash Python Bindings
-# Copyright (c) 2011-2012, Aleksey Kravchenko
-#
-# 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.
-#
-# This library 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. Use it at your own risk!
-"""Unit-tests for the rhash module"""
-
-import rhash
-import os
-import unittest
-
-# pylint: disable=too-many-public-methods, pointless-statement
-class TestRHash(unittest.TestCase):
- """The test-case class for the rhash module"""
-
- def test_all_hashes(self):
- """Verify all hash functions"""
- ctx = rhash.RHash(rhash.ALL)
- ctx.update('a')
- ctx.finish()
- self.assertEqual('e8b7be43', ctx.hash(rhash.CRC32))
- self.assertEqual('c1d04330', ctx.hash(rhash.CRC32C))
- self.assertEqual('bde52cb31de33e46245e05fbdbd6fb24', ctx.hash(rhash.MD4))
- self.assertEqual('0cc175b9c0f1b6a831c399e269772661', ctx.hash(rhash.MD5))
- self.assertEqual(
- '86f7e437faa5a7fce15d1ddcb9eaeaea377667b8', ctx.hash(rhash.SHA1))
- self.assertEqual(
- '77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809',
- ctx.hash(rhash.TIGER))
- self.assertEqual(
- 'czquwh3iyxbf5l3bgyugzhassmxu647ip2ike4y', ctx.hash(rhash.TTH))
- self.assertEqual(40, len(ctx.hash(rhash.BTIH)))
- self.assertEqual('bde52cb31de33e46245e05fbdbd6fb24', ctx.hash(rhash.ED2K))
- self.assertEqual('q336in72uwt7zyk5dxolt2xk5i3xmz5y', ctx.hash(rhash.AICH))
- self.assertEqual(
- '8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a',
- ctx.hash(rhash.WHIRLPOOL))
- self.assertEqual(
- '0bdc9d2d256b3ee9daae347be6f4dc835a467ffe', ctx.hash(rhash.RIPEMD160))
- self.assertEqual(
- 'd42c539e367c66e9c88a801f6649349c21871b4344c6a573f849fdce62f314dd',
- ctx.hash(rhash.GOST94))
- self.assertEqual(
- 'e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011',
- ctx.hash(rhash.GOST94_CRYPTOPRO))
- self.assertEqual(
- 'ba31099b9cc84ec2a671e9313572378920a705b363b031a1cb4fc03e01ce8df3',
- ctx.hash(rhash.GOST12_256))
- self.assertEqual(
- '8b2a40ecab7b7496bc4cc0f773595452baf658849b495acc3ba017206810efb00420ccd73fb3297e0f7890941b84ac4a8bc27e3c95e1f97c094609e2136abb7e',
- ctx.hash(rhash.GOST12_512))
- self.assertEqual(
- '4872bcbc4cd0f0a9dc7c2f7045e5b43b6c830db8',
- ctx.hash(rhash.HAS160))
- self.assertEqual(
- 'bf5ce540ae51bc50399f96746c5a15bd', ctx.hash(rhash.SNEFRU128))
- self.assertEqual(
- '45161589ac317be0ceba70db2573ddda6e668a31984b39bf65e4b664b584c63d',
- ctx.hash(rhash.SNEFRU256))
- self.assertEqual(
- 'abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5',
- ctx.hash(rhash.SHA224))
- self.assertEqual(
- 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb',
- ctx.hash(rhash.SHA256))
- self.assertEqual(
- '54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31',
- ctx.hash(rhash.SHA384))
- self.assertEqual(
- '1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75',
- ctx.hash(rhash.SHA512))
- self.assertEqual(
- '943aa9225a2cf154ec2e4dd81237720ba538ca8df2fd83c0b893c5d265f353a0',
- ctx.hash(rhash.EDONR256))
- self.assertEqual(
- 'b59ec44f7beef8a04ceed38a973d77c65e22e9458d5f67b497948da34986c093b5efc5483fbee55f2f740fcad31f18d80db44bb6b8843e7fd599188e7c07233b',
- ctx.hash(rhash.EDONR512))
- self.assertEqual(
- '9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b',
- ctx.hash(rhash.SHA3_224))
- self.assertEqual(
- '80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b',
- ctx.hash(rhash.SHA3_256))
- self.assertEqual(
- '1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9',
- ctx.hash(rhash.SHA3_384))
- self.assertEqual(
- '697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a',
- ctx.hash(rhash.SHA3_512))
- # test reset
- self.assertEqual(
- 'd41d8cd98f00b204e9800998ecf8427e',
- ctx.reset().finish().hash(rhash.MD5)) # MD5( '' )
-
- def test_update(self):
- """Test the sequential update calls"""
- ctx = rhash.RHash(rhash.CRC32 | rhash.MD5)
- ctx.update('Hello, ').update('world!').finish()
- self.assertEqual('EBE6C6E6', ctx.HEX(rhash.CRC32))
- self.assertEqual('6cd3556deb0da54bca060b4c39479839', ctx.hex(rhash.MD5))
-
- def test_shift_operator(self):
- """Test the << operator"""
- ctx = rhash.RHash(rhash.MD5)
- ctx << 'a' << 'bc'
- # MD5( 'abc' )
- self.assertEqual('900150983cd24fb0d6963f7d28e17f72', str(ctx.finish()))
-
- def test_hash_for_msg(self):
- """Test the hash_for_msg() function"""
- self.assertEqual(
- '900150983cd24fb0d6963f7d28e17f72',
- rhash.hash_for_msg('abc', rhash.MD5))
-
- def test_output_formats(self):
- """Test all output formats of a message digest"""
- ctx = rhash.RHash(rhash.MD5 | rhash.TTH).finish()
- self.assertEqual(
- '5d9ed00a030e638bdb753a6a24fb900e5a63b8e73e6c25b6',
- ctx.hex(rhash.TTH))
- self.assertEqual('2qoyzwmpaczaj2mabgmoz6ccpy', ctx.base32(rhash.MD5))
- self.assertEqual('1B2M2Y8AsgTpgAmY7PhCfg==', ctx.base64(rhash.MD5))
- self.assertEqual(
- b'\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42\x7e',
- ctx.raw(rhash.MD5))
-
- def test_magnet(self):
- """Test calculation of a magnet link"""
- ctx = rhash.RHash(rhash.MD5 | rhash.TTH)
- ctx.update('abc').finish()
- self.assertEqual(
- 'magnet:?xl=3&dn=file.txt&xt=urn:md5:900150983cd24fb0d6963f7d28e17f72&xt=urn:tree:tiger:asd4ujseh5m47pdyb46kbtsqtsgdklbhyxomuia',
- ctx.magnet('file.txt'))
-
- def test_update_file(self):
- """Test the update_file() method"""
- path = 'python_test_input_123.txt'
- file = open(path, 'wb')
- file.write(b"\0\1\2\n")
- file.close()
-
- ctx = rhash.RHash(rhash.SHA1)
- ctx.update_file(path).finish()
- self.assertEqual('e3869ec477661fad6b9fc25914bb2eee5455b483', str(ctx))
- self.assertEqual(
- 'e3869ec477661fad6b9fc25914bb2eee5455b483',
- rhash.hash_for_file(path, rhash.SHA1))
- self.assertEqual(
- 'magnet:?xl=4&dn=python_test_input_123.txt&xt=urn:tree:tiger:c6docz63fpef5pdfpz35z7mw2iozshxlpr4erza',
- rhash.magnet_for_file(path, rhash.TTH))
- os.remove(path)
-
-if __name__ == '__main__':
- unittest.main()
+# UnitTest for Librhash Python Bindings
+# Copyright (c) 2011-2012, Aleksey Kravchenko
+#
+# 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.
+#
+# This library 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. Use it at your own risk!
+"""Unit-tests for the rhash module"""
+
+import rhash
+import os
+import unittest
+
+# pylint: disable=too-many-public-methods, pointless-statement
+class TestRHash(unittest.TestCase):
+ """The test-case class for the rhash module"""
+
+ def test_all_hashes(self):
+ """Verify all hash functions"""
+ ctx = rhash.RHash(rhash.ALL)
+ ctx.update('a')
+ ctx.finish()
+ self.assertEqual('e8b7be43', ctx.hash(rhash.CRC32))
+ self.assertEqual('c1d04330', ctx.hash(rhash.CRC32C))
+ self.assertEqual('bde52cb31de33e46245e05fbdbd6fb24', ctx.hash(rhash.MD4))
+ self.assertEqual('0cc175b9c0f1b6a831c399e269772661', ctx.hash(rhash.MD5))
+ self.assertEqual(
+ '86f7e437faa5a7fce15d1ddcb9eaeaea377667b8', ctx.hash(rhash.SHA1))
+ self.assertEqual(
+ '77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809',
+ ctx.hash(rhash.TIGER))
+ self.assertEqual(
+ 'czquwh3iyxbf5l3bgyugzhassmxu647ip2ike4y', ctx.hash(rhash.TTH))
+ self.assertEqual(40, len(ctx.hash(rhash.BTIH)))
+ self.assertEqual('bde52cb31de33e46245e05fbdbd6fb24', ctx.hash(rhash.ED2K))
+ self.assertEqual('q336in72uwt7zyk5dxolt2xk5i3xmz5y', ctx.hash(rhash.AICH))
+ self.assertEqual(
+ '8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a',
+ ctx.hash(rhash.WHIRLPOOL))
+ self.assertEqual(
+ '0bdc9d2d256b3ee9daae347be6f4dc835a467ffe', ctx.hash(rhash.RIPEMD160))
+ self.assertEqual(
+ 'd42c539e367c66e9c88a801f6649349c21871b4344c6a573f849fdce62f314dd',
+ ctx.hash(rhash.GOST94))
+ self.assertEqual(
+ 'e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011',
+ ctx.hash(rhash.GOST94_CRYPTOPRO))
+ self.assertEqual(
+ 'ba31099b9cc84ec2a671e9313572378920a705b363b031a1cb4fc03e01ce8df3',
+ ctx.hash(rhash.GOST12_256))
+ self.assertEqual(
+ '8b2a40ecab7b7496bc4cc0f773595452baf658849b495acc3ba017206810efb00420ccd73fb3297e0f7890941b84ac4a8bc27e3c95e1f97c094609e2136abb7e',
+ ctx.hash(rhash.GOST12_512))
+ self.assertEqual(
+ '4872bcbc4cd0f0a9dc7c2f7045e5b43b6c830db8',
+ ctx.hash(rhash.HAS160))
+ self.assertEqual(
+ 'bf5ce540ae51bc50399f96746c5a15bd', ctx.hash(rhash.SNEFRU128))
+ self.assertEqual(
+ '45161589ac317be0ceba70db2573ddda6e668a31984b39bf65e4b664b584c63d',
+ ctx.hash(rhash.SNEFRU256))
+ self.assertEqual(
+ 'abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5',
+ ctx.hash(rhash.SHA224))
+ self.assertEqual(
+ 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb',
+ ctx.hash(rhash.SHA256))
+ self.assertEqual(
+ '54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31',
+ ctx.hash(rhash.SHA384))
+ self.assertEqual(
+ '1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75',
+ ctx.hash(rhash.SHA512))
+ self.assertEqual(
+ '943aa9225a2cf154ec2e4dd81237720ba538ca8df2fd83c0b893c5d265f353a0',
+ ctx.hash(rhash.EDONR256))
+ self.assertEqual(
+ 'b59ec44f7beef8a04ceed38a973d77c65e22e9458d5f67b497948da34986c093b5efc5483fbee55f2f740fcad31f18d80db44bb6b8843e7fd599188e7c07233b',
+ ctx.hash(rhash.EDONR512))
+ self.assertEqual(
+ '9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b',
+ ctx.hash(rhash.SHA3_224))
+ self.assertEqual(
+ '80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b',
+ ctx.hash(rhash.SHA3_256))
+ self.assertEqual(
+ '1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9',
+ ctx.hash(rhash.SHA3_384))
+ self.assertEqual(
+ '697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a',
+ ctx.hash(rhash.SHA3_512))
+ # test reset
+ self.assertEqual(
+ 'd41d8cd98f00b204e9800998ecf8427e',
+ ctx.reset().finish().hash(rhash.MD5)) # MD5( '' )
+
+ def test_update(self):
+ """Test the sequential update calls"""
+ ctx = rhash.RHash(rhash.CRC32 | rhash.MD5)
+ ctx.update('Hello, ').update('world!').finish()
+ self.assertEqual('EBE6C6E6', ctx.HEX(rhash.CRC32))
+ self.assertEqual('6cd3556deb0da54bca060b4c39479839', ctx.hex(rhash.MD5))
+
+ def test_shift_operator(self):
+ """Test the << operator"""
+ ctx = rhash.RHash(rhash.MD5)
+ ctx << 'a' << 'bc'
+ # MD5( 'abc' )
+ self.assertEqual('900150983cd24fb0d6963f7d28e17f72', str(ctx.finish()))
+
+ def test_hash_for_msg(self):
+ """Test the hash_for_msg() function"""
+ self.assertEqual(
+ '900150983cd24fb0d6963f7d28e17f72',
+ rhash.hash_for_msg('abc', rhash.MD5))
+
+ def test_output_formats(self):
+ """Test all output formats of a message digest"""
+ ctx = rhash.RHash(rhash.MD5 | rhash.TTH).finish()
+ self.assertEqual(
+ '5d9ed00a030e638bdb753a6a24fb900e5a63b8e73e6c25b6',
+ ctx.hex(rhash.TTH))
+ self.assertEqual('2qoyzwmpaczaj2mabgmoz6ccpy', ctx.base32(rhash.MD5))
+ self.assertEqual('1B2M2Y8AsgTpgAmY7PhCfg==', ctx.base64(rhash.MD5))
+ self.assertEqual(
+ b'\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42\x7e',
+ ctx.raw(rhash.MD5))
+
+ def test_magnet(self):
+ """Test calculation of a magnet link"""
+ ctx = rhash.RHash(rhash.MD5 | rhash.TTH)
+ ctx.update('abc').finish()
+ self.assertEqual(
+ 'magnet:?xl=3&dn=file.txt&xt=urn:md5:900150983cd24fb0d6963f7d28e17f72&xt=urn:tree:tiger:asd4ujseh5m47pdyb46kbtsqtsgdklbhyxomuia',
+ ctx.magnet('file.txt'))
+
+ def test_update_file(self):
+ """Test the update_file() method"""
+ path = 'python_test_input_123.txt'
+ file = open(path, 'wb')
+ file.write(b"\0\1\2\n")
+ file.close()
+
+ ctx = rhash.RHash(rhash.SHA1)
+ ctx.update_file(path).finish()
+ self.assertEqual('e3869ec477661fad6b9fc25914bb2eee5455b483', str(ctx))
+ self.assertEqual(
+ 'e3869ec477661fad6b9fc25914bb2eee5455b483',
+ rhash.hash_for_file(path, rhash.SHA1))
+ self.assertEqual(
+ 'magnet:?xl=4&dn=python_test_input_123.txt&xt=urn:tree:tiger:c6docz63fpef5pdfpz35z7mw2iozshxlpr4erza',
+ rhash.magnet_for_file(path, rhash.TTH))
+ os.remove(path)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/bindings/ruby/.gitignore b/bindings/ruby/.gitignore
index 029dc02e..2d0b29c4 100644
--- a/bindings/ruby/.gitignore
+++ b/bindings/ruby/.gitignore
@@ -1,3 +1,3 @@
-mkmf.log
-rhash.so
-Makefile
+mkmf.log
+rhash.so
+Makefile
diff --git a/bindings/ruby/extconf.rb b/bindings/ruby/extconf.rb
index cceb8bdf..8bb3562d 100644
--- a/bindings/ruby/extconf.rb
+++ b/bindings/ruby/extconf.rb
@@ -1,13 +1,13 @@
-require 'mkmf'
-
-if ENV['LIBRHASH_INC']
- $CFLAGS += ENV['LIBRHASH_INC']
-else
- have_header('rhash.h')
-end
-
-$LDFLAGS += ' ' + ENV['LIBRHASH_LD'] if ENV['LIBRHASH_LD']
-$LDFLAGS += ' -lrhash'
-
-dir_config('rhash')
-create_makefile('rhash')
+require 'mkmf'
+
+if ENV['LIBRHASH_INC']
+ $CFLAGS += ENV['LIBRHASH_INC']
+else
+ have_header('rhash.h')
+end
+
+$LDFLAGS += ' ' + ENV['LIBRHASH_LD'] if ENV['LIBRHASH_LD']
+$LDFLAGS += ' -lrhash'
+
+dir_config('rhash')
+create_makefile('rhash')
diff --git a/bindings/ruby/rhash.c b/bindings/ruby/rhash.c
index 1f408625..4702b2bb 100644
--- a/bindings/ruby/rhash.c
+++ b/bindings/ruby/rhash.c
@@ -1,381 +1,381 @@
-/*
- * Ruby Bindings for Librhash
- * Copyright (c) 2011-2012, Sergey Basalaev
- * Librhash is (c) 2011-2012, Aleksey Kravchenko
- *
- * 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.
- *
- * This library 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. Use it at your own risk!
- */
-
-#include
-#include
-
-/* RHash class. */
-static VALUE cRHash;
-
-static void rh_free(rhash ctx) {
- rhash_free(ctx);
-}
-
-/**
- * call-seq:
- * rhash.update(data) -> RHash
- * rhash << data -> RHash
- *
- * Updates this RHash
with new data chunk.
- */
-static VALUE rh_update(VALUE self, VALUE msg) {
- rhash ctx;
- Data_Get_Struct(self, struct rhash_context, ctx);
-
- if (TYPE(msg) != T_STRING) {
- msg = rb_obj_as_string(msg); /* convert to string */
- }
-
- rhash_update(ctx, RSTRING_PTR(msg), RSTRING_LEN(msg));
- return self;
-}
-
-/* declaring non-static method to fix a warning on an unused function */
-VALUE rh_update_file(VALUE self, VALUE file);
-
-/**
- * call-seq:
- * rhash.update_file(filename) -> RHash
- *
- * Updates this RHash
with data from given file.
- */
-VALUE rh_update_file(VALUE self, VALUE file) {
- // this function is actually implemented in pure Ruby below
- // this allows us to handle files in platform-independent way
- return self;
-}
-
-/**
- * call-seq:
- * rhash.finish
- *
- * Finishes calculation for all data buffered by
- * update
and stops calculation of hashes.
- */
-static VALUE rh_finish(VALUE self) {
- rhash ctx;
- Data_Get_Struct(self, struct rhash_context, ctx);
- rhash_final(ctx, NULL);
- return self;
-}
-
-/**
- * call-seq:
- * rhash.reset
- *
- * Resets this RHash to initial state.
- * The RHash becomes available to process
- * new data chunks.
- */
-static VALUE rh_reset(VALUE self) {
- rhash ctx;
- Data_Get_Struct(self, struct rhash_context, ctx);
- rhash_reset(ctx);
- return self;
-}
-
-static VALUE rh_print(VALUE self, VALUE type, int flags) {
- char buf[130];
- rhash ctx;
- Data_Get_Struct(self, struct rhash_context, ctx);
- int len = rhash_print(buf, ctx, type == Qnil ? 0 : FIX2INT(type), flags);
- return rb_str_new(buf, len);
-}
-
-/**
- * call-seq:
- * rhash.to_raw(id)
- * rhash.to_raw
- *
- * Returns value of the RHash digest as raw bytes.
- * If RHash was created with a single hashing algorithm
- * then argument may be omitted.
- */
-static VALUE rh_to_raw(int argc, VALUE* argv, VALUE self) {
- VALUE type;
- rb_scan_args(argc, argv, "01", &type);
- return rh_print(self, type, RHPR_RAW);
-}
-
-/**
- * call-seq:
- * rhash.to_hex(id)
- * rhash.to_hex
- *
- * Returns value of the RHash digest as hexadecimal string.
- * If RHash was created with a single hashing algorithm
- * then argument may be omitted.
- */
-static VALUE rh_to_hex(int argc, VALUE* argv, VALUE self) {
- VALUE type;
- rb_scan_args(argc, argv, "01", &type);
- return rh_print(self, type, RHPR_HEX);
-}
-
-/**
- * call-seq:
- * rhash.to_base32(id)
- * rhash.to_base32
- *
- * Returns value of the RHash digest as base32 string.
- * If RHash was created with a single hashing algorithm
- * then argument may be omitted.
- */
-static VALUE rh_to_base32(int argc, VALUE* argv, VALUE self) {
- VALUE type;
- rb_scan_args(argc, argv, "01", &type);
- return rh_print(self, type, RHPR_BASE32);
-}
-
-/**
- * call-seq:
- * rhash.magnet(filepath)
- * rhash.magnet
- *
- * Returns magnet link with all hashes computed by
- * the RHash object.
- * if filepath is specified, then it is url-encoded
- * and included into the resulting magnet link.
- */
-static VALUE rh_magnet(int argc, VALUE* argv, VALUE self) {
- VALUE value;
- const char* filepath = 0;
- char* buf;
- size_t buf_size;
- rhash ctx;
-
- Data_Get_Struct(self, struct rhash_context, ctx);
-
- rb_scan_args(argc, argv, "01", &value);
- if (value != Qnil) {
- if (TYPE(value) != T_STRING) value = rb_obj_as_string(value);
- filepath = RSTRING_PTR(value);
- }
-
- buf_size = rhash_print_magnet(0, filepath, ctx, RHASH_ALL_HASHES, RHPR_FILESIZE);
- buf = (char*)malloc(buf_size);
- if (!buf) return Qnil;
-
- rhash_print_magnet(buf, filepath, ctx, RHASH_ALL_HASHES, RHPR_FILESIZE);
- value = rb_str_new2(buf);
- free(buf);
- return value;
-}
-
-/**
- * call-seq:
- * rhash.to_base64(id)
- * rhash.to_base64
- *
- * Returns value of the RHash digest as base64 string.
- * If RHash was created with a single hashing algorithm
- * then argument may be omitted.
- */
-static VALUE rh_to_base64(int argc, VALUE* argv, VALUE self) {
- VALUE type;
- rb_scan_args(argc, argv, "01", &type);
- return rh_print(self, type, RHPR_BASE64);
-}
-
-/**
- * call-seq:
- * rhash.to_s(id)
- * rhash.to_s
- *
- * Returns value of the RHash digest for given algorithm
- * as string in default format. If RHash was created with
- * a single hashing algorithm then argument may be omitted.
- */
-static VALUE rh_to_s(int argc, VALUE* argv, VALUE self) {
- VALUE type;
- rb_scan_args(argc, argv, "01", &type);
- return rh_print(self, type, 0);
-}
-
-/**
- * call-seq:
- * RHash.base32?(id) -> true or false
- *
- * Returns true if default format for given hash algorithm is
- * base32 and false if it is hexadecimal.
- */
-static VALUE rh_is_base32(VALUE self, VALUE type) {
- return rhash_is_base32(FIX2INT(type)) ? Qtrue : Qfalse;
-}
-
-static VALUE rh_init(int argc, VALUE *argv, VALUE self) {
- return self;
-}
-
-/**
- * call-seq:
- * RHash.new(id, ...)
- *
- * Creates RHash object to calculate hashes for given algorithms.
- * Parameters should be constants defined in this class.
- */
-VALUE rh_new(int argc, VALUE* argv, VALUE clz) {
- int flags = 0, i;
- for (i=0; iRHash object is first created
- * for a set of hashing algorithms.
- *
- * Next, data for hashing is given in chunks with methods
- * update
and update_file
. Finally,
- * call finish
to end up all remaining calculations.
- *
- * To receive text represenation of the message digest use one
- * of methods to_hex
, to_base32
and
- * to_base64
. Binary message digest may be obtained
- * with to_raw
. All of these methods accept algorithm
- * value as argument. It may be omitted if RHash
was
- * created to compute hash for only a single hashing algorithm.
- */
-void Init_rhash() {
- rhash_library_init();
-
- cRHash = rb_define_class("RHash", rb_cObject);
-
- rb_define_singleton_method(cRHash, "new", rh_new, -1);
- rb_define_singleton_method(cRHash, "base32?", rh_is_base32, 1);
-
- rb_define_method(cRHash, "initialize", rh_init, -1);
- rb_define_method(cRHash, "update", rh_update, 1);
- rb_define_method(cRHash, "<<", rh_update, 1);
- rb_define_method(cRHash, "finish", rh_finish, 0);
- rb_define_method(cRHash, "reset", rh_reset, 0);
- rb_define_method(cRHash, "to_raw", rh_to_raw, -1);
- rb_define_method(cRHash, "to_hex", rh_to_hex, -1);
- rb_define_method(cRHash, "to_base32", rh_to_base32, -1);
- rb_define_method(cRHash, "to_base64", rh_to_base64, -1);
- rb_define_method(cRHash, "to_s", rh_to_s, -1);
- rb_define_method(cRHash, "magnet", rh_magnet, -1);
-
- rb_eval_string(
-"class RHash \n\
- def update_file(filename) \n\
- f = File.open(filename, 'rb') \n\
- while block = f.read(4096) \n\
- self.update(block) \n\
- end \n\
- f.close \n\
- self \n\
- end \n\
-end\n\
-\n\
-def RHash.hash_for_msg(msg, hash_id)\n\
- RHash.new(hash_id).update(msg).finish.to_s\n\
-end\n\
-\n\
-def RHash.hash_for_file(filename, hash_id)\n\
- RHash.new(hash_id).update_file(filename).finish.to_s\n\
-end\n\
-\n\
-def RHash.magnet_for_file(filename, *hash_ids)\n\
- RHash.new(*hash_ids).update_file(filename).finish.magnet(filename)\n\
-end");
-
- /** CRC32 checksum. */
- rb_define_const(cRHash, "CRC32", INT2FIX(RHASH_CRC32));
- /** CRC32C checksum. */
- rb_define_const(cRHash, "CRC32C", INT2FIX(RHASH_CRC32C));
- /** MD4 hash. */
- rb_define_const(cRHash, "MD4", INT2FIX(RHASH_MD4));
- /** MD5 hash. */
- rb_define_const(cRHash, "MD5", INT2FIX(RHASH_MD5));
- /** SHA-1 hash. */
- rb_define_const(cRHash, "SHA1", INT2FIX(RHASH_SHA1));
- /** Tiger hash. */
- rb_define_const(cRHash, "TIGER", INT2FIX(RHASH_TIGER));
- /** Tiger tree hash */
- rb_define_const(cRHash, "TTH", INT2FIX(RHASH_TTH));
- /** BitTorrent info hash. */
- rb_define_const(cRHash, "BTIH", INT2FIX(RHASH_BTIH));
- /** EDonkey 2000 hash. */
- rb_define_const(cRHash, "ED2K", INT2FIX(RHASH_ED2K));
- /** eMule AICH. */
- rb_define_const(cRHash, "AICH", INT2FIX(RHASH_AICH));
- /** Whirlpool hash. */
- rb_define_const(cRHash, "WHIRLPOOL", INT2FIX(RHASH_WHIRLPOOL));
- /** RIPEMD-160 hash. */
- rb_define_const(cRHash, "RIPEMD160", INT2FIX(RHASH_RIPEMD160));
- /** GOST R 34.11-94. */
- rb_define_const(cRHash, "GOST94", INT2FIX(RHASH_GOST94));
- /** GOST R 34.11-94 - CryptoPro. */
- rb_define_const(cRHash, "GOST94_CRYPTOPRO", INT2FIX(RHASH_GOST94_CRYPTOPRO));
- /** GOST R 34.11-2012 - 256-bit. */
- rb_define_const(cRHash, "GOST12_256", INT2FIX(RHASH_GOST12_256));
- /** GOST R 34.11-2012 - 512 bit. */
- rb_define_const(cRHash, "GOST12_512", INT2FIX(RHASH_GOST12_512));
- /** HAS-160 hash. */
- rb_define_const(cRHash, "HAS160", INT2FIX(RHASH_HAS160));
- /** SHA-224 hash. */
- rb_define_const(cRHash, "SHA224", INT2FIX(RHASH_SHA224));
- /** SHA-256 hash. */
- rb_define_const(cRHash, "SHA256", INT2FIX(RHASH_SHA256));
- /** SHA-384 hash. */
- rb_define_const(cRHash, "SHA384", INT2FIX(RHASH_SHA384));
- /** SHA-512 hash. */
- rb_define_const(cRHash, "SHA512", INT2FIX(RHASH_SHA512));
- /** EDON-R 256. */
- rb_define_const(cRHash, "EDONR256", INT2FIX(RHASH_EDONR256));
- /** EDON-R 512. */
- rb_define_const(cRHash, "EDONR512", INT2FIX(RHASH_EDONR512));
- /** SHA3-224 hash. */
- rb_define_const(cRHash, "SHA3_224", INT2FIX(RHASH_SHA3_224));
- /** SHA3-256 hash. */
- rb_define_const(cRHash, "SHA3_256", INT2FIX(RHASH_SHA3_256));
- /** SHA3-384 hash. */
- rb_define_const(cRHash, "SHA3_384", INT2FIX(RHASH_SHA3_384));
- /** SHA3-512 hash. */
- rb_define_const(cRHash, "SHA3_512", INT2FIX(RHASH_SHA3_512));
- /** Snefru-128 hash. */
- rb_define_const(cRHash, "SNEFRU128", INT2FIX(RHASH_SNEFRU128));
- /** Snefru-256 hash. */
- rb_define_const(cRHash, "SNEFRU256", INT2FIX(RHASH_SNEFRU256));
- /** Create RHash with this parameter to compute hashes for all available algorithms. */
- rb_define_const(cRHash, "ALL", INT2FIX(RHASH_ALL_HASHES));
-}
-
+/*
+ * Ruby Bindings for Librhash
+ * Copyright (c) 2011-2012, Sergey Basalaev
+ * Librhash is (c) 2011-2012, Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This library 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. Use it at your own risk!
+ */
+
+#include
+#include
+
+/* RHash class. */
+static VALUE cRHash;
+
+static void rh_free(rhash ctx) {
+ rhash_free(ctx);
+}
+
+/**
+ * call-seq:
+ * rhash.update(data) -> RHash
+ * rhash << data -> RHash
+ *
+ * Updates this RHash
with new data chunk.
+ */
+static VALUE rh_update(VALUE self, VALUE msg) {
+ rhash ctx;
+ Data_Get_Struct(self, struct rhash_context, ctx);
+
+ if (TYPE(msg) != T_STRING) {
+ msg = rb_obj_as_string(msg); /* convert to string */
+ }
+
+ rhash_update(ctx, RSTRING_PTR(msg), RSTRING_LEN(msg));
+ return self;
+}
+
+/* declaring non-static method to fix a warning on an unused function */
+VALUE rh_update_file(VALUE self, VALUE file);
+
+/**
+ * call-seq:
+ * rhash.update_file(filename) -> RHash
+ *
+ * Updates this RHash
with data from given file.
+ */
+VALUE rh_update_file(VALUE self, VALUE file) {
+ // this function is actually implemented in pure Ruby below
+ // this allows us to handle files in platform-independent way
+ return self;
+}
+
+/**
+ * call-seq:
+ * rhash.finish
+ *
+ * Finishes calculation for all data buffered by
+ * update
and stops calculation of hashes.
+ */
+static VALUE rh_finish(VALUE self) {
+ rhash ctx;
+ Data_Get_Struct(self, struct rhash_context, ctx);
+ rhash_final(ctx, NULL);
+ return self;
+}
+
+/**
+ * call-seq:
+ * rhash.reset
+ *
+ * Resets this RHash to initial state.
+ * The RHash becomes available to process
+ * new data chunks.
+ */
+static VALUE rh_reset(VALUE self) {
+ rhash ctx;
+ Data_Get_Struct(self, struct rhash_context, ctx);
+ rhash_reset(ctx);
+ return self;
+}
+
+static VALUE rh_print(VALUE self, VALUE type, int flags) {
+ char buf[130];
+ rhash ctx;
+ Data_Get_Struct(self, struct rhash_context, ctx);
+ int len = rhash_print(buf, ctx, type == Qnil ? 0 : FIX2INT(type), flags);
+ return rb_str_new(buf, len);
+}
+
+/**
+ * call-seq:
+ * rhash.to_raw(id)
+ * rhash.to_raw
+ *
+ * Returns value of the RHash digest as raw bytes.
+ * If RHash was created with a single hashing algorithm
+ * then argument may be omitted.
+ */
+static VALUE rh_to_raw(int argc, VALUE* argv, VALUE self) {
+ VALUE type;
+ rb_scan_args(argc, argv, "01", &type);
+ return rh_print(self, type, RHPR_RAW);
+}
+
+/**
+ * call-seq:
+ * rhash.to_hex(id)
+ * rhash.to_hex
+ *
+ * Returns value of the RHash digest as hexadecimal string.
+ * If RHash was created with a single hashing algorithm
+ * then argument may be omitted.
+ */
+static VALUE rh_to_hex(int argc, VALUE* argv, VALUE self) {
+ VALUE type;
+ rb_scan_args(argc, argv, "01", &type);
+ return rh_print(self, type, RHPR_HEX);
+}
+
+/**
+ * call-seq:
+ * rhash.to_base32(id)
+ * rhash.to_base32
+ *
+ * Returns value of the RHash digest as base32 string.
+ * If RHash was created with a single hashing algorithm
+ * then argument may be omitted.
+ */
+static VALUE rh_to_base32(int argc, VALUE* argv, VALUE self) {
+ VALUE type;
+ rb_scan_args(argc, argv, "01", &type);
+ return rh_print(self, type, RHPR_BASE32);
+}
+
+/**
+ * call-seq:
+ * rhash.magnet(filepath)
+ * rhash.magnet
+ *
+ * Returns magnet link with all hashes computed by
+ * the RHash object.
+ * if filepath is specified, then it is url-encoded
+ * and included into the resulting magnet link.
+ */
+static VALUE rh_magnet(int argc, VALUE* argv, VALUE self) {
+ VALUE value;
+ const char* filepath = 0;
+ char* buf;
+ size_t buf_size;
+ rhash ctx;
+
+ Data_Get_Struct(self, struct rhash_context, ctx);
+
+ rb_scan_args(argc, argv, "01", &value);
+ if (value != Qnil) {
+ if (TYPE(value) != T_STRING) value = rb_obj_as_string(value);
+ filepath = RSTRING_PTR(value);
+ }
+
+ buf_size = rhash_print_magnet(0, filepath, ctx, RHASH_ALL_HASHES, RHPR_FILESIZE);
+ buf = (char*)malloc(buf_size);
+ if (!buf) return Qnil;
+
+ rhash_print_magnet(buf, filepath, ctx, RHASH_ALL_HASHES, RHPR_FILESIZE);
+ value = rb_str_new2(buf);
+ free(buf);
+ return value;
+}
+
+/**
+ * call-seq:
+ * rhash.to_base64(id)
+ * rhash.to_base64
+ *
+ * Returns value of the RHash digest as base64 string.
+ * If RHash was created with a single hashing algorithm
+ * then argument may be omitted.
+ */
+static VALUE rh_to_base64(int argc, VALUE* argv, VALUE self) {
+ VALUE type;
+ rb_scan_args(argc, argv, "01", &type);
+ return rh_print(self, type, RHPR_BASE64);
+}
+
+/**
+ * call-seq:
+ * rhash.to_s(id)
+ * rhash.to_s
+ *
+ * Returns value of the RHash digest for given algorithm
+ * as string in default format. If RHash was created with
+ * a single hashing algorithm then argument may be omitted.
+ */
+static VALUE rh_to_s(int argc, VALUE* argv, VALUE self) {
+ VALUE type;
+ rb_scan_args(argc, argv, "01", &type);
+ return rh_print(self, type, 0);
+}
+
+/**
+ * call-seq:
+ * RHash.base32?(id) -> true or false
+ *
+ * Returns true if default format for given hash algorithm is
+ * base32 and false if it is hexadecimal.
+ */
+static VALUE rh_is_base32(VALUE self, VALUE type) {
+ return rhash_is_base32(FIX2INT(type)) ? Qtrue : Qfalse;
+}
+
+static VALUE rh_init(int argc, VALUE *argv, VALUE self) {
+ return self;
+}
+
+/**
+ * call-seq:
+ * RHash.new(id, ...)
+ *
+ * Creates RHash object to calculate hashes for given algorithms.
+ * Parameters should be constants defined in this class.
+ */
+VALUE rh_new(int argc, VALUE* argv, VALUE clz) {
+ int flags = 0, i;
+ for (i=0; iRHash object is first created
+ * for a set of hashing algorithms.
+ *
+ * Next, data for hashing is given in chunks with methods
+ * update
and update_file
. Finally,
+ * call finish
to end up all remaining calculations.
+ *
+ * To receive text represenation of the message digest use one
+ * of methods to_hex
, to_base32
and
+ * to_base64
. Binary message digest may be obtained
+ * with to_raw
. All of these methods accept algorithm
+ * value as argument. It may be omitted if RHash
was
+ * created to compute hash for only a single hashing algorithm.
+ */
+void Init_rhash() {
+ rhash_library_init();
+
+ cRHash = rb_define_class("RHash", rb_cObject);
+
+ rb_define_singleton_method(cRHash, "new", rh_new, -1);
+ rb_define_singleton_method(cRHash, "base32?", rh_is_base32, 1);
+
+ rb_define_method(cRHash, "initialize", rh_init, -1);
+ rb_define_method(cRHash, "update", rh_update, 1);
+ rb_define_method(cRHash, "<<", rh_update, 1);
+ rb_define_method(cRHash, "finish", rh_finish, 0);
+ rb_define_method(cRHash, "reset", rh_reset, 0);
+ rb_define_method(cRHash, "to_raw", rh_to_raw, -1);
+ rb_define_method(cRHash, "to_hex", rh_to_hex, -1);
+ rb_define_method(cRHash, "to_base32", rh_to_base32, -1);
+ rb_define_method(cRHash, "to_base64", rh_to_base64, -1);
+ rb_define_method(cRHash, "to_s", rh_to_s, -1);
+ rb_define_method(cRHash, "magnet", rh_magnet, -1);
+
+ rb_eval_string(
+"class RHash \n\
+ def update_file(filename) \n\
+ f = File.open(filename, 'rb') \n\
+ while block = f.read(4096) \n\
+ self.update(block) \n\
+ end \n\
+ f.close \n\
+ self \n\
+ end \n\
+end\n\
+\n\
+def RHash.hash_for_msg(msg, hash_id)\n\
+ RHash.new(hash_id).update(msg).finish.to_s\n\
+end\n\
+\n\
+def RHash.hash_for_file(filename, hash_id)\n\
+ RHash.new(hash_id).update_file(filename).finish.to_s\n\
+end\n\
+\n\
+def RHash.magnet_for_file(filename, *hash_ids)\n\
+ RHash.new(*hash_ids).update_file(filename).finish.magnet(filename)\n\
+end");
+
+ /** CRC32 checksum. */
+ rb_define_const(cRHash, "CRC32", INT2FIX(RHASH_CRC32));
+ /** CRC32C checksum. */
+ rb_define_const(cRHash, "CRC32C", INT2FIX(RHASH_CRC32C));
+ /** MD4 hash. */
+ rb_define_const(cRHash, "MD4", INT2FIX(RHASH_MD4));
+ /** MD5 hash. */
+ rb_define_const(cRHash, "MD5", INT2FIX(RHASH_MD5));
+ /** SHA-1 hash. */
+ rb_define_const(cRHash, "SHA1", INT2FIX(RHASH_SHA1));
+ /** Tiger hash. */
+ rb_define_const(cRHash, "TIGER", INT2FIX(RHASH_TIGER));
+ /** Tiger tree hash */
+ rb_define_const(cRHash, "TTH", INT2FIX(RHASH_TTH));
+ /** BitTorrent info hash. */
+ rb_define_const(cRHash, "BTIH", INT2FIX(RHASH_BTIH));
+ /** EDonkey 2000 hash. */
+ rb_define_const(cRHash, "ED2K", INT2FIX(RHASH_ED2K));
+ /** eMule AICH. */
+ rb_define_const(cRHash, "AICH", INT2FIX(RHASH_AICH));
+ /** Whirlpool hash. */
+ rb_define_const(cRHash, "WHIRLPOOL", INT2FIX(RHASH_WHIRLPOOL));
+ /** RIPEMD-160 hash. */
+ rb_define_const(cRHash, "RIPEMD160", INT2FIX(RHASH_RIPEMD160));
+ /** GOST R 34.11-94. */
+ rb_define_const(cRHash, "GOST94", INT2FIX(RHASH_GOST94));
+ /** GOST R 34.11-94 - CryptoPro. */
+ rb_define_const(cRHash, "GOST94_CRYPTOPRO", INT2FIX(RHASH_GOST94_CRYPTOPRO));
+ /** GOST R 34.11-2012 - 256-bit. */
+ rb_define_const(cRHash, "GOST12_256", INT2FIX(RHASH_GOST12_256));
+ /** GOST R 34.11-2012 - 512 bit. */
+ rb_define_const(cRHash, "GOST12_512", INT2FIX(RHASH_GOST12_512));
+ /** HAS-160 hash. */
+ rb_define_const(cRHash, "HAS160", INT2FIX(RHASH_HAS160));
+ /** SHA-224 hash. */
+ rb_define_const(cRHash, "SHA224", INT2FIX(RHASH_SHA224));
+ /** SHA-256 hash. */
+ rb_define_const(cRHash, "SHA256", INT2FIX(RHASH_SHA256));
+ /** SHA-384 hash. */
+ rb_define_const(cRHash, "SHA384", INT2FIX(RHASH_SHA384));
+ /** SHA-512 hash. */
+ rb_define_const(cRHash, "SHA512", INT2FIX(RHASH_SHA512));
+ /** EDON-R 256. */
+ rb_define_const(cRHash, "EDONR256", INT2FIX(RHASH_EDONR256));
+ /** EDON-R 512. */
+ rb_define_const(cRHash, "EDONR512", INT2FIX(RHASH_EDONR512));
+ /** SHA3-224 hash. */
+ rb_define_const(cRHash, "SHA3_224", INT2FIX(RHASH_SHA3_224));
+ /** SHA3-256 hash. */
+ rb_define_const(cRHash, "SHA3_256", INT2FIX(RHASH_SHA3_256));
+ /** SHA3-384 hash. */
+ rb_define_const(cRHash, "SHA3_384", INT2FIX(RHASH_SHA3_384));
+ /** SHA3-512 hash. */
+ rb_define_const(cRHash, "SHA3_512", INT2FIX(RHASH_SHA3_512));
+ /** Snefru-128 hash. */
+ rb_define_const(cRHash, "SNEFRU128", INT2FIX(RHASH_SNEFRU128));
+ /** Snefru-256 hash. */
+ rb_define_const(cRHash, "SNEFRU256", INT2FIX(RHASH_SNEFRU256));
+ /** Create RHash with this parameter to compute hashes for all available algorithms. */
+ rb_define_const(cRHash, "ALL", INT2FIX(RHASH_ALL_HASHES));
+}
+
diff --git a/bindings/ruby/test_rhash.rb b/bindings/ruby/test_rhash.rb
index 6115710a..92fab1ea 100644
--- a/bindings/ruby/test_rhash.rb
+++ b/bindings/ruby/test_rhash.rb
@@ -1,75 +1,75 @@
-#!/usr/bin/ruby
-
-require "test/unit"
-require "rhash"
-
-class TestRHash < Test::Unit::TestCase
-
- def test_all_hashes
- r = RHash.new(RHash::ALL)
- r.update("a").finish()
-
- assert_equal("e8b7be43", r.to_s(RHash::CRC32))
- assert_equal("c1d04330", r.to_s(RHash::CRC32C))
- assert_equal("bde52cb31de33e46245e05fbdbd6fb24", r.to_s(RHash::MD4))
- assert_equal("0cc175b9c0f1b6a831c399e269772661", r.to_s(RHash::MD5))
- assert_equal("86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", r.to_s(RHash::SHA1))
- assert_equal("77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", r.to_s(RHash::TIGER))
- assert_equal("czquwh3iyxbf5l3bgyugzhassmxu647ip2ike4y", r.to_s(RHash::TTH))
- assert_equal(40, r.to_s(RHash::BTIH).length())
- assert_equal("bde52cb31de33e46245e05fbdbd6fb24", r.to_s(RHash::ED2K))
- assert_equal("q336in72uwt7zyk5dxolt2xk5i3xmz5y", r.to_s(RHash::AICH))
- assert_equal("8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a", r.to_s(RHash::WHIRLPOOL))
- assert_equal("0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", r.to_s(RHash::RIPEMD160))
- assert_equal("d42c539e367c66e9c88a801f6649349c21871b4344c6a573f849fdce62f314dd", r.to_s(RHash::GOST94))
- assert_equal("e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011", r.to_s(RHash::GOST94_CRYPTOPRO))
- assert_equal("ba31099b9cc84ec2a671e9313572378920a705b363b031a1cb4fc03e01ce8df3", r.to_s(RHash::GOST12_256))
- assert_equal("8b2a40ecab7b7496bc4cc0f773595452baf658849b495acc3ba017206810efb00420ccd73fb3297e0f7890941b84ac4a8bc27e3c95e1f97c094609e2136abb7e", r.to_s(RHash::GOST12_512))
- assert_equal("4872bcbc4cd0f0a9dc7c2f7045e5b43b6c830db8", r.to_s(RHash::HAS160))
- assert_equal("bf5ce540ae51bc50399f96746c5a15bd", r.to_s(RHash::SNEFRU128))
- assert_equal("45161589ac317be0ceba70db2573ddda6e668a31984b39bf65e4b664b584c63d", r.to_s(RHash::SNEFRU256))
- assert_equal("abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", r.to_s(RHash::SHA224))
- assert_equal("ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", r.to_s(RHash::SHA256))
- assert_equal("54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", r.to_s(RHash::SHA384))
- assert_equal("1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", r.to_s(RHash::SHA512))
- assert_equal("943aa9225a2cf154ec2e4dd81237720ba538ca8df2fd83c0b893c5d265f353a0", r.to_s(RHash::EDONR256))
- assert_equal("b59ec44f7beef8a04ceed38a973d77c65e22e9458d5f67b497948da34986c093b5efc5483fbee55f2f740fcad31f18d80db44bb6b8843e7fd599188e7c07233b", r.to_s(RHash::EDONR512))
- assert_equal("9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b", r.to_s(RHash::SHA3_224))
- assert_equal("80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b", r.to_s(RHash::SHA3_256))
- assert_equal("1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9", r.to_s(RHash::SHA3_384))
- assert_equal("697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a", r.to_s(RHash::SHA3_512))
-
- assert_equal("d41d8cd98f00b204e9800998ecf8427e", r.reset().finish().to_s(RHash::MD5)) # MD5( "" )
- end
-
- def test_shift_operator
- r = RHash.new(RHash::MD5)
- r << "a" << "bc"
- assert_equal("900150983cd24fb0d6963f7d28e17f72", r.finish().to_s()) # MD5( "abc" )
- end
-
- def test_output
- r = RHash.new(RHash::MD5, RHash::TTH)
- r.finish()
- assert_equal("5d9ed00a030e638bdb753a6a24fb900e5a63b8e73e6c25b6", r.to_hex(RHash::TTH))
- assert_equal("2qoyzwmpaczaj2mabgmoz6ccpy", r.to_base32(RHash::MD5))
- assert_equal("1B2M2Y8AsgTpgAmY7PhCfg==", r.to_base64(RHash::MD5))
- assert_equal(["d41d8cd98f00b204e9800998ecf8427e"].pack('H*'), r.to_raw(RHash::MD5))
- end
-
- def test_magnet
- r = RHash.new(RHash::MD5, RHash::TTH)
- r.update("abc").finish()
- assert_equal("magnet:?xl=3&dn=file.txt&xt=urn:md5:900150983cd24fb0d6963f7d28e17f72&xt=urn:tree:tiger:asd4ujseh5m47pdyb46kbtsqtsgdklbhyxomuia", r.magnet("file.txt"))
- end
-
- def test_update_file
- path = "ruby_test_input_123.txt"
- File.open(path, 'wb') { |f| f.write("\0\1\2\n") }
- r = RHash.new(RHash::SHA1)
- r.update_file(path).finish()
- assert_equal("e3869ec477661fad6b9fc25914bb2eee5455b483", r.to_s(RHash::SHA1))
- File.delete(path)
- end
-
-end
+#!/usr/bin/ruby
+
+require "test/unit"
+require "rhash"
+
+class TestRHash < Test::Unit::TestCase
+
+ def test_all_hashes
+ r = RHash.new(RHash::ALL)
+ r.update("a").finish()
+
+ assert_equal("e8b7be43", r.to_s(RHash::CRC32))
+ assert_equal("c1d04330", r.to_s(RHash::CRC32C))
+ assert_equal("bde52cb31de33e46245e05fbdbd6fb24", r.to_s(RHash::MD4))
+ assert_equal("0cc175b9c0f1b6a831c399e269772661", r.to_s(RHash::MD5))
+ assert_equal("86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", r.to_s(RHash::SHA1))
+ assert_equal("77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", r.to_s(RHash::TIGER))
+ assert_equal("czquwh3iyxbf5l3bgyugzhassmxu647ip2ike4y", r.to_s(RHash::TTH))
+ assert_equal(40, r.to_s(RHash::BTIH).length())
+ assert_equal("bde52cb31de33e46245e05fbdbd6fb24", r.to_s(RHash::ED2K))
+ assert_equal("q336in72uwt7zyk5dxolt2xk5i3xmz5y", r.to_s(RHash::AICH))
+ assert_equal("8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a", r.to_s(RHash::WHIRLPOOL))
+ assert_equal("0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", r.to_s(RHash::RIPEMD160))
+ assert_equal("d42c539e367c66e9c88a801f6649349c21871b4344c6a573f849fdce62f314dd", r.to_s(RHash::GOST94))
+ assert_equal("e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011", r.to_s(RHash::GOST94_CRYPTOPRO))
+ assert_equal("ba31099b9cc84ec2a671e9313572378920a705b363b031a1cb4fc03e01ce8df3", r.to_s(RHash::GOST12_256))
+ assert_equal("8b2a40ecab7b7496bc4cc0f773595452baf658849b495acc3ba017206810efb00420ccd73fb3297e0f7890941b84ac4a8bc27e3c95e1f97c094609e2136abb7e", r.to_s(RHash::GOST12_512))
+ assert_equal("4872bcbc4cd0f0a9dc7c2f7045e5b43b6c830db8", r.to_s(RHash::HAS160))
+ assert_equal("bf5ce540ae51bc50399f96746c5a15bd", r.to_s(RHash::SNEFRU128))
+ assert_equal("45161589ac317be0ceba70db2573ddda6e668a31984b39bf65e4b664b584c63d", r.to_s(RHash::SNEFRU256))
+ assert_equal("abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", r.to_s(RHash::SHA224))
+ assert_equal("ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", r.to_s(RHash::SHA256))
+ assert_equal("54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", r.to_s(RHash::SHA384))
+ assert_equal("1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", r.to_s(RHash::SHA512))
+ assert_equal("943aa9225a2cf154ec2e4dd81237720ba538ca8df2fd83c0b893c5d265f353a0", r.to_s(RHash::EDONR256))
+ assert_equal("b59ec44f7beef8a04ceed38a973d77c65e22e9458d5f67b497948da34986c093b5efc5483fbee55f2f740fcad31f18d80db44bb6b8843e7fd599188e7c07233b", r.to_s(RHash::EDONR512))
+ assert_equal("9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b", r.to_s(RHash::SHA3_224))
+ assert_equal("80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b", r.to_s(RHash::SHA3_256))
+ assert_equal("1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9", r.to_s(RHash::SHA3_384))
+ assert_equal("697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a", r.to_s(RHash::SHA3_512))
+
+ assert_equal("d41d8cd98f00b204e9800998ecf8427e", r.reset().finish().to_s(RHash::MD5)) # MD5( "" )
+ end
+
+ def test_shift_operator
+ r = RHash.new(RHash::MD5)
+ r << "a" << "bc"
+ assert_equal("900150983cd24fb0d6963f7d28e17f72", r.finish().to_s()) # MD5( "abc" )
+ end
+
+ def test_output
+ r = RHash.new(RHash::MD5, RHash::TTH)
+ r.finish()
+ assert_equal("5d9ed00a030e638bdb753a6a24fb900e5a63b8e73e6c25b6", r.to_hex(RHash::TTH))
+ assert_equal("2qoyzwmpaczaj2mabgmoz6ccpy", r.to_base32(RHash::MD5))
+ assert_equal("1B2M2Y8AsgTpgAmY7PhCfg==", r.to_base64(RHash::MD5))
+ assert_equal(["d41d8cd98f00b204e9800998ecf8427e"].pack('H*'), r.to_raw(RHash::MD5))
+ end
+
+ def test_magnet
+ r = RHash.new(RHash::MD5, RHash::TTH)
+ r.update("abc").finish()
+ assert_equal("magnet:?xl=3&dn=file.txt&xt=urn:md5:900150983cd24fb0d6963f7d28e17f72&xt=urn:tree:tiger:asd4ujseh5m47pdyb46kbtsqtsgdklbhyxomuia", r.magnet("file.txt"))
+ end
+
+ def test_update_file
+ path = "ruby_test_input_123.txt"
+ File.open(path, 'wb') { |f| f.write("\0\1\2\n") }
+ r = RHash.new(RHash::SHA1)
+ r.update_file(path).finish()
+ assert_equal("e3869ec477661fad6b9fc25914bb2eee5455b483", r.to_s(RHash::SHA1))
+ File.delete(path)
+ end
+
+end
diff --git a/bindings/version.properties b/bindings/version.properties
index e7e280f5..da2ff6c8 100644
--- a/bindings/version.properties
+++ b/bindings/version.properties
@@ -1 +1 @@
-version=1.3.8
+version=1.3.8
diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt
new file mode 100644
index 00000000..9dbbeefe
--- /dev/null
+++ b/build/CMakeLists.txt
@@ -0,0 +1,743 @@
+cmake_minimum_required(VERSION 3.2.3)
+project(RHash)
+#Do not prefix BUILD_SHARED_LIBS and BUILD_STATIC_LIBS because those are standard cmake options
+#We only put them in the menu for convenience.
+option(BUILD_SHARED_LIBS "Build shared LibRHash libraries" ON)
+option(BUILD_STATIC_LIBS "Build static LibRHash libraries" ON)
+
+option(RHASH_USE_OPENSSL "Build Rhash with OpenSSL Crypto support" ON)
+option(RHASH_OPENSSL_RUNTIME "load OpenSSL at runtime if present" ON)
+option(RHASH_BUILD_EXE "Build rhash executable" ON)
+option(RHASH_USE_GETTEXT "Build rhash executable with i18n support with gettext" ON)
+option(RHASH_BUILD_LIB_DOCS "Build libRhash documentation with Doxygen" ON)
+option(RHASH_WITH_PKGCONFIG_SUPPORT "Generate and install .pc files" ON)
+option(RHASH_INCLUDE_WINDIST_FILES "Include Windows distribution files" ON)
+option(RHASH_INCLUDE_OTHER_FILES "Include other files from the distribution" ON)
+option(RHASH_TESTS_OPT_FULL "Run rhash executable all hash options test" ON)
+
+enable_testing()
+include( CTest )
+
+include(GNUInstallDirs)
+include(FindPkgConfig)
+if(RHASH_USE_OPENSSL)
+ include(FindOpenSSL)
+endif(RHASH_USE_OPENSSL)
+if(RHASH_BUILD_EXE)
+ include(FindGettext)
+ include(FindIntl)
+endif(RHASH_BUILD_EXE)
+if(RHASH_BUILD_LIB_DOCS)
+ include(FindDoxygen)
+endif(RHASH_BUILD_LIB_DOCS)
+
+set(SOVERSION 0)
+
+# Do things this way instead of using relative ../ reference
+# so that the builder's path does not appear in diagrams created by DOT
+# or any documentation generated by Doxygen. We don't want that to appear
+# in any packages that are for redistribution.
+get_filename_component(RHASH_SRC_DIR ${CMAKE_CURRENT_LIST_DIR}/.. REALPATH)
+set(RHASH_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR})
+set(RHASH_LIB_DIR ${RHASH_SRC_DIR}/librhash)
+set(RHASH_LIB_HEADERS
+ ${RHASH_LIB_DIR}/algorithms.h
+ ${RHASH_LIB_DIR}/byte_order.h
+ ${RHASH_LIB_DIR}/plug_openssl.h
+ ${RHASH_LIB_DIR}/rhash.h
+ ${RHASH_LIB_DIR}/rhash_timing.h
+ ${RHASH_LIB_DIR}/rhash_torrent.h
+ ${RHASH_LIB_DIR}/aich.h
+ ${RHASH_LIB_DIR}/crc32.h
+ ${RHASH_LIB_DIR}/ed2k.h
+ ${RHASH_LIB_DIR}/edonr.h
+ ${RHASH_LIB_DIR}/hex.h
+ ${RHASH_LIB_DIR}/md4.h
+ ${RHASH_LIB_DIR}/md5.h
+ ${RHASH_LIB_DIR}/sha1.h
+ ${RHASH_LIB_DIR}/sha256.h
+ ${RHASH_LIB_DIR}/sha512.h
+ ${RHASH_LIB_DIR}/sha3.h
+ ${RHASH_LIB_DIR}/ripemd-160.h
+ ${RHASH_LIB_DIR}/gost.h
+ ${RHASH_LIB_DIR}/has160.h
+ ${RHASH_LIB_DIR}/snefru.h
+ ${RHASH_LIB_DIR}/tiger.h
+ ${RHASH_LIB_DIR}/tth.h
+ ${RHASH_LIB_DIR}/torrent.h
+ ${RHASH_LIB_DIR}/ustd.h
+ ${RHASH_LIB_DIR}/util.h
+ ${RHASH_LIB_DIR}/whirlpool.h)
+
+set(RHASH_LIB_SOURCES
+ ${RHASH_LIB_DIR}/algorithms.c
+ ${RHASH_LIB_DIR}/byte_order.c
+ ${RHASH_LIB_DIR}/plug_openssl.c
+ ${RHASH_LIB_DIR}/rhash.c
+ ${RHASH_LIB_DIR}/rhash_timing.c
+ ${RHASH_LIB_DIR}/rhash_torrent.c
+ ${RHASH_LIB_DIR}/aich.c
+ ${RHASH_LIB_DIR}/crc32.c
+ ${RHASH_LIB_DIR}/ed2k.c
+ ${RHASH_LIB_DIR}/edonr.c
+ ${RHASH_LIB_DIR}/hex.c
+ ${RHASH_LIB_DIR}/md4.c
+ ${RHASH_LIB_DIR}/md5.c
+ ${RHASH_LIB_DIR}/sha1.c
+ ${RHASH_LIB_DIR}/sha256.c
+ ${RHASH_LIB_DIR}/sha512.c
+ ${RHASH_LIB_DIR}/sha3.c
+ ${RHASH_LIB_DIR}/ripemd-160.c
+ ${RHASH_LIB_DIR}/gost.c
+ ${RHASH_LIB_DIR}/has160.c
+ ${RHASH_LIB_DIR}/snefru.c
+ ${RHASH_LIB_DIR}/tiger.c
+ ${RHASH_LIB_DIR}/tiger_sbox.c
+ ${RHASH_LIB_DIR}/tth.c
+ ${RHASH_LIB_DIR}/torrent.c
+ ${RHASH_LIB_DIR}/whirlpool.c
+ ${RHASH_LIB_DIR}/whirlpool_sbox.c)
+set(RHASH_LIB_PUBLIC_HEADERS
+ ${RHASH_LIB_DIR}/rhash.h
+ ${RHASH_LIB_DIR}/rhash_torrent.h)
+set(RHASH_LIB_TEXT_SOURCES
+ ${RHASH_LIB_DIR}/test_hashes.c
+ ${RHASH_LIB_DIR}/test_hashes.h)
+set(RHASH_LIB_DEPEND_LIBS "")
+set(RHASH_EXE_HEADERS
+ ${RHASH_SRC_DIR}/calc_sums.h
+ ${RHASH_SRC_DIR}/hash_print.h
+ ${RHASH_SRC_DIR}/common_func.h
+ ${RHASH_SRC_DIR}/hash_update.h
+ ${RHASH_SRC_DIR}/file.h
+ ${RHASH_SRC_DIR}/file_mask.h
+ ${RHASH_SRC_DIR}/file_set.h
+ ${RHASH_SRC_DIR}/find_file.h
+ ${RHASH_SRC_DIR}/hash_check.h
+ ${RHASH_SRC_DIR}/output.h
+ ${RHASH_SRC_DIR}/parse_cmdline.h
+ ${RHASH_SRC_DIR}/rhash_main.h
+ ${RHASH_SRC_DIR}/win_utils.h
+ ${RHASH_SRC_DIR}/platform.h
+ ${RHASH_SRC_DIR}/version.h)
+set(RHASH_WIN_BAT_FILES
+ ${RHASH_SRC_DIR}/dist/MD5.bat
+ ${RHASH_SRC_DIR}/dist/magnet.bat)
+set(RHASH_WIN_DIST_FILES ${RHASH_WIN_BAT_FILES}
+ ${CMAKE_CURRENT_LIST_DIR}/icon.ico)
+set(RHASH_EXE_SOURCES
+ ${RHASH_SRC_DIR}/calc_sums.c
+ ${RHASH_SRC_DIR}/hash_print.c
+ ${RHASH_SRC_DIR}/common_func.c
+ ${RHASH_SRC_DIR}/hash_update.c
+ ${RHASH_SRC_DIR}/file.c
+ ${RHASH_SRC_DIR}/file_mask.c
+ ${RHASH_SRC_DIR}/file_set.c
+ ${RHASH_SRC_DIR}/find_file.c
+ ${RHASH_SRC_DIR}/hash_check.c
+ ${RHASH_SRC_DIR}/output.c
+ ${RHASH_SRC_DIR}/parse_cmdline.c
+ ${RHASH_SRC_DIR}/rhash_main.c
+ ${RHASH_SRC_DIR}/win_utils.c)
+set(RHASH_PO_DIR ${RHASH_SRC_DIR}/po)
+set(RHASH_I18N_FILES
+ ${RHASH_PO_DIR}/ca.po
+ ${RHASH_PO_DIR}/de.po
+ ${RHASH_PO_DIR}/en_AU.po
+ ${RHASH_PO_DIR}/es.po
+ ${RHASH_PO_DIR}/fr.po
+ ${RHASH_PO_DIR}/gl.po
+ ${RHASH_PO_DIR}/it.po
+ ${RHASH_PO_DIR}/ro.po
+ ${RHASH_PO_DIR}/ru.po)
+set(RHASH_SOURCE_RHASH_DIST_DIR ${RHASH_SRC_DIR}/dist)
+set(RHASH_BUILD_DIST_DIR ${RHASH_BUILD_DIR}/dist)
+set(RHASH_RHASH_SPECFILE_IN ${RHASH_SOURCE_RHASH_DIST_DIR}/rhash.spec.in)
+set(RHASH_SPECFILE ${RHASH_BUILD_DIST_DIR}/rhash.spec)
+set(RHASH_LIBRHASH_PC ${RHASH_BUILD_DIST_DIR}/librhash.pc)
+set(RHASH_OTHER_FILES ${RHASH_SPECFILE}
+ ${RHASH_SRC_DIR}/dist/rhashrc.sample)
+
+set(RHASH_DEFAULT_SYMLINKS
+ sfv-hash
+ tiger-hash
+ tth-hash
+ whirlpool-hash
+ has160-hash
+ gost-hash
+ edonr256-hash
+ edonr512-hash
+ ed2k-link
+ magnet-link)
+file(MAKE_DIRECTORY ${RHASH_BUILD_DIST_DIR})
+
+set(RHASH_ALL_FILES
+ ${SOURCES}
+ ${HEADERS}
+ ${LIBRHASH_FILES}
+ ${RHASH_OTHER_FILES}
+ ${RHASH_WIN_DIST_FILES}
+ ${RHASH_I18N_FILES})
+
+#obtain version number from version.h
+
+# from jsoncpp CMakeLists.txt
+# Extract major, minor, patch from version text
+# Parse a version string "X.Y.Z" and outputs
+# version parts in ${OUPUT_PREFIX}_MAJOR, _MINOR, _PATCH.
+# If parse succeeds then ${OUPUT_PREFIX}_FOUND is TRUE.
+# Set variable named ${VAR_NAME} to value ${VALUE}
+FUNCTION(set_using_dynamic_name VAR_NAME VALUE)
+ SET( "${VAR_NAME}" "${VALUE}" PARENT_SCOPE)
+ENDFUNCTION()
+
+MACRO(jsoncpp_parse_version VERSION_TEXT OUPUT_PREFIX)
+ SET(VERSION_REGEX "[0-9]+\\.[0-9]+\\.[0-9]+(-[a-zA-Z0-9_]+)?")
+ IF( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} )
+ STRING(REGEX MATCHALL "[0-9]+|-([A-Za-z0-9_]+)" VERSION_PARTS ${VERSION_TEXT})
+ LIST(GET VERSION_PARTS 0 ${OUPUT_PREFIX}_MAJOR)
+ LIST(GET VERSION_PARTS 1 ${OUPUT_PREFIX}_MINOR)
+ LIST(GET VERSION_PARTS 2 ${OUPUT_PREFIX}_PATCH)
+ set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" TRUE )
+ ELSE( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} )
+ set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" FALSE )
+ ENDIF()
+ENDMACRO()
+
+file(READ ${RHASH_SRC_DIR}/version.h VERSION_CONTENTS)
+jsoncpp_parse_version( ${VERSION_CONTENTS} RHASH_VERSION )
+IF(NOT RHASH_VERSION_FOUND)
+ MESSAGE(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z")
+endif(NOT RHASH_VERSION_FOUND)
+
+message(STATUS "RHash version: ${RHASH_VERSION_MAJOR}.${RHASH_VERSION_MINOR}.${RHASH_VERSION_PATCH}")
+
+#cpack stuff
+INCLUDE(InstallRequiredSystemLibraries)
+SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Utility for computing hash sums and creating magnet links.")
+SET(CPACK_PACKAGE_VENDOR "Aleksey Kravchenko")
+SET(CPACK_PACKAGE_VERSION_MAJOR "${RHASH_VERSION_MAJOR}")
+SET(CPACK_PACKAGE_VERSION_MINOR "${RHASH_VERSION_MINOR}")
+SET(CPACK_PACKAGE_VERSION_PATCH "${RHASH_VERSION_PATCH}")
+IF(WIN32 AND NOT UNIX)
+ # There is a bug in NSI that does not handle full unix paths properly. Make
+ # sure there is at least one set of four (4) backlasshes.
+ if(CMAKE_RC_COMPILER)
+ SET(CPACK_PACKAGE_ICON "${CMake_SOURCE_DIR}/\\\\rhash.exe")
+ endif(CMAKE_RC_COMPILER)
+ SET(CPACK_NSIS_MODIFY_PATH ON)
+ SET(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\rhash.exe")
+ SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} Rhash")
+ SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\rhash.sourceforge.net/")
+ SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\rhash.sourceforge.net/")
+ SET(CPACK_NSIS_CONTACT "Aleksey Kravchenko ")
+ELSE(WIN32 AND NOT UNIX)
+ SET(CPACK_STRIP_FILES "bin/${rhash_exe}")
+ SET(CPACK_SOURCE_STRIP_FILES "")
+ENDIF(WIN32 AND NOT UNIX)
+
+include(CPack)
+
+#library and program libary settings
+set(RHASH_ADDITIONAL_LIBS "")
+set(RHASH_ADDITIONAL_DIRS "")
+set(RHASH_DEFINITIONS_FOR_ALL_TARGETS "")
+
+if(RHASH_USE_OPENSSL)
+ if (OPENSSL_FOUND)
+ message(STATUS "OpenSSL Crypto Library: ${OPENSSL_CRYPTO_LIBRARY}")
+ message(STATUS "OpenSSL Crypto Includes: ${OPENSSL_INCLUDE_DIR}")
+ message(STATUS "OpenSSL Crypto Library Version: ${OPENSSL_VERSION}")
+ list(APPEND RHASH_ADDITIONAL_DIRS ${OPENSSL_INCLUDE_DIR})
+ if (RHASH_OPENSSL_RUNTIME)
+ set(RHASH_DEFINITIONS_FOR_ALL_TARGETS ${RHASH_DEFINITIONS_FOR_ALL_TARGETS} OPENSSL_RUNTIME)
+ else()
+ list(APPEND RHASH_ADDITIONAL_LIBS ${OPENSSL_CRYPTO_LIBRARY})
+ set(RHASH_DEFINITIONS_FOR_ALL_TARGETS ${RHASH_DEFINITIONS_FOR_ALL_TARGETS} USE_OPENSSL)
+ list(APPEND RHASH_LIB_DEPEND_LIBS ${OPENSSL_CRYPTO_LIBRARY})
+ endif(RHASH_OPENSSL_RUNTIME)
+ else()
+ message(STATUS "OpenSSL Crypto Library: Not Found")
+ endif (OPENSSL_FOUND)
+else()
+ message(STATUS "OpenSSL Crypto Support: Not Selected")
+endif(RHASH_USE_OPENSSL)
+
+if(RHASH_BUILD_EXE)
+#make .rc file for .exe
+ if(CMAKE_RC_COMPILER)
+ file(COPY icon.ico DESTINATION ${RHASH_BUILD_DIR})
+ set(RHASH_FILE_CONTENTS "id ICON \"icon.ico\"
+1 VERSIONINFO
+FILEVERSION ${RHASH_VERSION_MAJOR},${RHASH_VERSION_MINOR},${RHASH_VERSION_PATCH},0
+PRODUCTVERSION ${RHASH_VERSION_MAJOR},${RHASH_VERSION_MINOR},${RHASH_VERSION_PATCH},0
+BEGIN
+ BLOCK \"StringFileInfo\"
+ BEGIN
+ BLOCK \"040904E4\"
+ BEGIN
+ VALUE \"CompanyName\", \"Aleksey Kravchenko \"
+ VALUE \"FileDescription\", \"calculate/check CRC32, MD5, SHA1, GOST, TTH, BTIH or other hash sums.\"
+ VALUE \"FileVersion\", \"${RHASH_VERSION_MAJOR}.${RHASH_VERSION_MINOR}.${RHASH_VERSION_PATCH}\"
+ VALUE \"InternalName\", \"rhash\"
+ VALUE \"LegalCopyright\", \"Copyright (c) 2005-2014 Aleksey Kravchenko \"
+ VALUE \"OriginalFilename\", \"rhash${CMAKE_EXECUTABLE_SUFFIX}\"
+ VALUE \"ProductName\", \"RHash\"
+ VALUE \"ProductVersion\", \"${RHASH_VERSION_MAJOR}.${RHASH_VERSION_MINOR}.${RHASH_VERSION_PATCH}\"
+ END
+ END
+ BLOCK \"VarFileInfo\"
+ BEGIN
+ VALUE \"Translation\", 0x409, 1252
+ END
+END")
+ FILE(WRITE ${RHASH_BUILD_DIR}/rhash.rc "${RHASH_FILE_CONTENTS}")
+ endif(CMAKE_RC_COMPILER)
+
+ if (RHASH_USE_GETTEXT)
+ if (Intl_FOUND)
+ set(RHASH_EXE_DEFS "${RHASH_EXE_DEFS} USE_GETTEXT")
+ list(APPEND RHASH_ADDITIONAL_DIRS ${Intl_INCLUDE_DIR})
+ if(Intl_LIBRARIES)
+ list(APPEND RHASH_ADDITIONAL_LIBS ${Intl_LIBRARIES})
+ endif(Intl_LIBRARIES)
+ message(STATUS "Intl Includes: ${Intl_INCLUDE_DIR}")
+ # Intl_LIBRARIES may be empty on systems that don't require you to link to an additional library.
+ if(Intl_LIBRARIES)
+ message(STATUS "Intl Library: ${Intl_LIBRARIES}")
+ elseif()
+ message(STATUS "Intl Library: Not Required")
+ endif(Intl_LIBRARIES)
+ else()
+ message(STATUS "Intl Library: Not Found")
+ endif(Intl_FOUND )
+ else()
+ message(STATUS "Intl Library Support: Not Selected")
+ endif(RHASH_USE_GETTEXT)
+ if(CMAKE_RC_COMPILER)
+ add_executable(rhash_exe ${RHASH_EXE_HEADERS} ${RHASH_EXE_SOURCES} ${RHASH_BUILD_DIR}/rhash.rc)
+ else()
+ add_executable(rhash_exe ${RHASH_EXE_HEADERS} ${RHASH_EXE_SOURCES})
+ endif(CMAKE_RC_COMPILER)
+ if(RHASH_ADDITIONAL_DIRS)
+ target_include_directories(rhash_exe PRIVATE ${RHASH_ADDITIONAL_DIRS})
+ endif(RHASH_ADDITIONAL_DIRS)
+
+ if(RHASH_ADDITIONAL_LIBS)
+ target_link_libraries(rhash_exe PUBLIC ${RHASH_ADDITIONAL_LIBS})
+ endif(RHASH_ADDITIONAL_LIBS)
+ set(RHASH_EXE_CONFDIR_MACRO "SYSCONFDIR=\"${CMAKE_INSTALL_FULL_SYSCONFDIR}\"")
+
+ target_compile_definitions(rhash_exe PRIVATE ${RHASH_EXE_DEFS} ${RHASH_EXE_CONFDIR_MACRO})
+ set_target_properties(rhash_exe PROPERTIES OUTPUT_NAME rhash)
+ install(TARGETS rhash_exe
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib
+ PUBLIC_HEADER DESTINATION include)
+
+ #Rhash man pages
+ install(FILES ${RHASH_SOURCE_RHASH_DIST_DIR}/rhash.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
+
+ add_custom_target(symlinks)
+ get_target_property(RASH_TARGET_NAME rhash_exe OUTPUT_NAME)
+
+ foreach(RHASH_CURSYM ${RHASH_DEFAULT_SYMLINKS})
+ # exe file symlink
+ add_custom_command(OUTPUT ${RHASH_BUILD_DIR}/${RHASH_CURSYM}${CMAKE_EXECUTABLE_SUFFIX}
+ DEPENDS rhash_exe
+ COMMAND ${CMAKE_COMMAND} -E copy ${RHASH_BUILD_DIR}/${RASH_TARGET_NAME}${CMAKE_EXECUTABLE_SUFFIX} ${RHASH_BUILD_DIR}/${RHASH_CURSYM}${CMAKE_EXECUTABLE_SUFFIX})
+ add_custom_target(exe_${RHASH_CURSYM} ALL DEPENDS ${RHASH_BUILD_DIR}/${RHASH_CURSYM}${CMAKE_EXECUTABLE_SUFFIX})
+ install(FILES ${RHASH_BUILD_DIR}/${RHASH_CURSYM}${CMAKE_EXECUTABLE_SUFFIX} DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
+ # man file symlinks
+ add_custom_command(OUTPUT ${RHASH_BUILD_DIR}/${RHASH_CURSYM}.1
+ COMMAND ${CMAKE_COMMAND} -E copy ${RHASH_SOURCE_RHASH_DIST_DIR}/${RASH_TARGET_NAME}.1 ${RHASH_BUILD_DIR}/${RHASH_CURSYM}.1)
+ add_custom_target(man_${RHASH_CURSYM}.1 ALL DEPENDS ${RHASH_BUILD_DIR}/${RHASH_CURSYM}.1)
+ install(FILES ${RHASH_BUILD_DIR}/${RHASH_CURSYM}.1 DESTINATION ${CMAKE_INSTALL_FULL_MANDIR}/man1)
+ endforeach(RHASH_CURSYM)
+
+ # Alternative Manpage forms
+
+ find_program(SED sed)
+ if(SED)
+ message(STATUS "SED ${SED}")
+ add_custom_command(POST_BUILD OUTPUT ${RHASH_BUILD_DIST_DIR}/rhash.1.win
+ COMMENT "Creating rhash.1.win"
+ COMMAND ${CMAKE_COMMAND} -D SED=${SED} -DSED_FILE=${RHASH_SOURCE_RHASH_DIST_DIR}/rhash.1.win.sed -D MAN_FILE=${RHASH_SOURCE_RHASH_DIST_DIR}/rhash.1 -DWIN_FILE=${RHASH_BUILD_DIST_DIR}/rhash.1.win -P ${CMAKE_CURRENT_LIST_DIR}/make_win_man.cmake)
+ add_custom_target(win_doc ALL DEPENDS ${RHASH_BUILD_DIST_DIR}/rhash.1.win)
+ install(FILES ${RHASH_BUILD_DIST_DIR}/rhash.1.win DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
+ else()
+ message(STATUS "SED Not Found")
+ endif(SED)
+
+ find_program(RMAN rman)
+ if(RMAN)
+ message(STATUS "Polyglotman (rman) ${RMAN}")
+ add_custom_command(POST_BUILD OUTPUT ${RHASH_BUILD_DIST_DIR}/rhash.1.html COMMENT "Creating rhash.1.html"
+ COMMAND ${CMAKE_COMMAND} -D RMAN=${RMAN} -D MAN_FILE=${RHASH_SOURCE_RHASH_DIST_DIR}/rhash.1 -DHTML_FILE=${RHASH_BUILD_DIST_DIR}/rhash.1.html -P ${CMAKE_CURRENT_LIST_DIR}/make_html.cmake)
+ install(FILES ${RHASH_BUILD_DIST_DIR}/rhash.1.html DESTINATION ${CMAKE_INSTALL_DOCDIR}/html)
+ if(SED)
+ add_custom_command(POST_BUILD OUTPUT ${RHASH_BUILD_DIST_DIR}/rhash.1.win.html
+ DEPENDS ${RHASH_BUILD_DIST_DIR}/rhash.1.win
+ COMMENT "Creating rhash.1.win.html"
+ COMMAND ${CMAKE_COMMAND} -D RMAN=${RMAN} -D MAN_FILE=${RHASH_BUILD_DIST_DIR}/rhash.1.win -DHTML_FILE=${RHASH_BUILD_DIST_DIR}/rhash.1.win.html -P ${CMAKE_CURRENT_LIST_DIR}/make_html.cmake)
+ install(FILES ${RHASH_BUILD_DIST_DIR}/rhash.1.win.html DESTINATION ${CMAKE_INSTALL_DOCDIR}/html)
+ add_custom_target(html_doc ALL DEPENDS ${RHASH_BUILD_DIST_DIR}/rhash.1.html ${RHASH_BUILD_DIST_DIR}/rhash.1.win.html)
+ else()
+ add_custom_target(html_doc ALL DEPENDS ${RHASH_BUILD_DIST_DIR}/rhash.1.html)
+ endif(SED)
+ else()
+ message(STATUS "Polyglotman (rman) Not Found")
+ endif(RMAN)
+
+ find_program(GROFF groff)
+ if(GROFF)
+ #dist/rhash.1.txt: dist/rhash.1
+ # -which groff &>/dev/null && (groff -t -e -mandoc -Tascii dist/rhash.1 | sed -e 's/.\[[0-9]*m//g' > $@)
+ message(STATUS "groff ${GROFF}")
+ add_custom_command(POST_BUILD OUTPUT ${RHASH_BUILD_DIST_DIR}/rhash.1.txt COMMENT "Creating rhash.1.txt"
+ COMMAND ${CMAKE_COMMAND} -D GROFF=${GROFF} -D MAN_FILE=${RHASH_SOURCE_RHASH_DIST_DIR}/rhash.1 -DTXT_FILE=${RHASH_BUILD_DIST_DIR}/rhash.1.txt -P ${CMAKE_CURRENT_LIST_DIR}/make_txt.cmake)
+ install(FILES ${RHASH_BUILD_DIST_DIR}/rhash.1.txt DESTINATION ${CMAKE_INSTALL_DOCDIR}/txt)
+ if(SED)
+ add_custom_command(POST_BUILD OUTPUT ${RHASH_BUILD_DIST_DIR}/rhash.1.win.txt D
+ EPENDS ${RHASH_BUILD_DIST_DIR}/rhash.1.win COMMENT "Creating rhash.1.win.txt"
+ COMMAND ${CMAKE_COMMAND} -D GROFF=${GROFF} -D MAN_FILE=${RHASH_BUILD_DIST_DIR}/rhash.1.win -DTXT_FILE=${RHASH_BUILD_DIST_DIR}/rhash.1.win.txt -P ${CMAKE_CURRENT_LIST_DIR}/make_txt.cmake)
+ install(FILES ${RHASH_BUILD_DIST_DIR}/rhash.1.win.txt DESTINATION ${CMAKE_INSTALL_DOCDIR}/txt)
+ add_custom_target(txt_doc ALL DEPENDS ${RHASH_BUILD_DIST_DIR}/rhash.1.txt ${RHASH_BUILD_DIST_DIR}/rhash.1.win.txt)
+ else()
+ add_custom_target(txt_doc ALL DEPENDS ${RHASH_BUILD_DIST_DIR}/rhash.1.txt ${RHASH_BUILD_DIST_DIR}/rhash.1.win.txt)
+ endif(SED)
+ else()
+ message(STATUS "groff Not Found")
+ endif(GROFF)
+
+ #rhashrc
+ add_custom_command(OUTPUT ${RHASH_BUILD_DIST_DIR}/rhashrc COMMENT "Creating rhashrc"
+ COMMAND ${CMAKE_COMMAND} -D SOURCE_FILE=${RHASH_SOURCE_RHASH_DIST_DIR}/rhashrc.sample -DDEST_FILE=${RHASH_BUILD_DIST_DIR}/rhashrc -P ${CMAKE_CURRENT_LIST_DIR}/stripCR.cmake)
+ add_custom_target(system-conf ALL DEPENDS ${RHASH_BUILD_DIST_DIR}/rhashrc)
+ install(FILES ${RHASH_BUILD_DIST_DIR}/rhashrc DESTINATION ${CMAKE_INSTALL_SYSCONFDIR})
+ #While this is a misc. file, it only is applicable if the executable is installed.
+ if(RHASH_INCLUDE_OTHER_FILES)
+ install(FILES ${RHASH_SOURCE_RHASH_DIST_DIR}/rhashrc.sample DESTINATION ${CMAKE_INSTALL_DOCDIR})
+ endif(RHASH_INCLUDE_OTHER_FILES)
+
+ #Gettext support
+ if (RHASH_USE_GETTEXT)
+ if(GETTEXT_FOUND)
+ message(STATUS "Gettext version ${GETTEXT_VERSION_STRING}")
+ message(STATUS "Gettext (msgmerge) ${GETTEXT_MSGMERGE_EXECUTABLE}")
+ message(STATUS "Gettext (msgfmt) ${GETTEXT_MSGFMT_EXECUTABLE}")
+ foreach(RHASH_PO_FILE ${RHASH_I18N_FILES})
+ get_filename_component(CUR_LANG ${RHASH_PO_FILE} NAME_WE)
+ GETTEXT_PROCESS_PO_FILES(${CUR_LANG} ALL INSTALL_DESTINATION ${CMAKE_INSTALL_FULL_LOCALEDIR} RHASH_PO_FILES ${RHASH_PO_FILE})
+ endforeach(RHASH_PO_FILE)
+ else()
+ message(STATUS "Gettext: Not Found")
+ endif(GETTEXT_FOUND)
+ else()
+ message(STATUS "i18n support with Gettext: Not Selected")
+ endif(RHASH_USE_GETTEXT)
+endif(RHASH_BUILD_EXE)
+
+set(RHASH_LIB_DEPEND_LIBS "${RHASH_LIB_DEPEND_LIBS};${CMAKE_DL_LIBS}")
+
+if(BUILD_SHARED_LIBS)
+ if(CMAKE_RC_COMPILER)
+ # Make .rc file
+ set(RHASH_FILE_CONTENTS "1 VERSIONINFO
+FILEVERSION ${RHASH_VERSION_MAJOR},${RHASH_VERSION_MINOR},${RHASH_VERSION_PATCH},0
+PRODUCTVERSION ${RHASH_VERSION_MAJOR},${RHASH_VERSION_MINOR},${RHASH_VERSION_PATCH},0
+BEGIN
+ BLOCK \"StringFileInfo\"
+ BEGIN
+ BLOCK \"040904E4\"
+ BEGIN
+ VALUE \"CompanyName\", \"Aleksey Kravchenko \"
+ VALUE \"FileDescription\", \"LibRHash shared library\"
+ VALUE \"FileVersion\", \"${RHASH_VERSION_MAJOR}.${RHASH_VERSION_MINOR}.${RHASH_VERSION_PATCH}\"
+ VALUE \"InternalName\", \"${CMAKE_SHARED_MODULE_PREFIX}rhash\"
+ VALUE \"LegalCopyright\", \"Copyright (c) 2005-2014 Aleksey Kravchenko \"
+ VALUE \"OriginalFilename\", \"${CMAKE_SHARED_MODULE_PREFIX}rhash${CMAKE_SHARED_LIBRARY_SUFFIX}\"
+ VALUE \"ProductName\", \"RHash\"
+ VALUE \"ProductVersion\", \"${RHASH_VERSION_MAJOR}.${RHASH_VERSION_MINOR}.${RHASH_VERSION_PATCH}\"
+ END
+ END
+ BLOCK \"VarFileInfo\"
+ BEGIN
+ VALUE \"Translation\", 0x409, 1252
+ END
+END")
+ FILE(WRITE ${RHASH_BUILD_DIR}/librhash.rc "${RHASH_FILE_CONTENTS}")
+
+ add_library(rhash_lib SHARED ${RHASH_LIB_SOURCES} ${RHASH_BUILD_DIR}/librhash.rc)
+ else()
+ add_library(rhash_lib SHARED ${RHASH_LIB_SOURCES})
+ endif(CMAKE_RC_COMPILER)
+ set_target_properties(rhash_lib PROPERTIES OUTPUT_NAME rhash)
+ if (WIN32 OR CYGWIN OR MSYS OR WINCE)
+ set_target_properties(rhash_lib PROPERTIES PUBLIC_HEADER "${RHASH_LIB_PUBLIC_HEADERS}")
+ else()
+ set_target_properties(rhash_lib PROPERTIES PUBLIC_HEADER "${RHASH_LIB_PUBLIC_HEADERS}" SOVERSION ${SOVERSION})
+ endif (WIN32 OR CYGWIN OR MSYS OR WINCE)
+ target_compile_definitions(rhash_lib PRIVATE ${RHASH_DEFINITIONS_FOR_ALL_TARGETS} RHASH_EXPORTS )
+ target_link_libraries(rhash_lib PUBLIC ${RHASH_ADDITIONAL_LIBS} ${CMAKE_DL_LIBS})
+ install(TARGETS rhash_lib
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib
+ PUBLIC_HEADER DESTINATION include)
+ add_executable(test_shared_exe ${RHASH_LIB_TEXT_SOURCES} )
+ target_link_libraries(test_shared_exe PUBLIC rhash_lib)
+ set_target_properties(test_shared_exe PROPERTIES OUTPUT_NAME test_shared)
+ add_test(NAME test_shared_library COMMAND $)
+ if(RHASH_BUILD_EXE)
+ target_link_libraries(rhash_exe PUBLIC rhash_lib)
+ endif(RHASH_BUILD_EXE)
+endif(BUILD_SHARED_LIBS)
+
+if(BUILD_STATIC_LIBS)
+ add_library(rhash_lib_static STATIC ${RHASH_LIB_SOURCES})
+ set_target_properties(rhash_lib_static PROPERTIES OUTPUT_NAME rhash)
+ if (WIN32 OR CYGWIN OR MSYS OR WINCE)
+ set_target_properties(rhash_lib_static PROPERTIES PUBLIC_HEADER "${RHASH_LIB_PUBLIC_HEADERS}")
+ else()
+ set_target_properties(rhash_lib_static PROPERTIES PUBLIC_HEADER "${RHASH_LIB_PUBLIC_HEADERS}" SOVERSION ${SOVERSION})
+ endif (WIN32 OR CYGWIN OR MSYS OR WINCE)
+ target_compile_definitions(rhash_lib_static PRIVATE ${RHASH_DEFINITIONS_FOR_ALL_TARGETS})
+ target_link_libraries(rhash_lib_static PUBLIC "${RHASH_LIB_DEPEND_LIBS}")
+ install(TARGETS rhash_lib_static
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib
+ PUBLIC_HEADER DESTINATION include)
+ if (RHASH_BUILD_EXE)
+ if (NOT(BUILD_SHARED_LIBS))
+ target_link_libraries(rhash_exe PUBLIC rhash_lib_static)
+ else()
+ target_link_libraries(rhash_exe PUBLIC rhash_lib)
+ endif(NOT(BUILD_SHARED_LIBS))
+ endif(RHASH_BUILD_EXE)
+ add_executable(test_exe_static ${RHASH_LIB_TEXT_SOURCES})
+ target_link_libraries(test_exe_static PUBLIC rhash_lib_static)
+ add_test(NAME test_static_library COMMAND $ )
+ set_target_properties(test_exe_static PROPERTIES OUTPUT_NAME test_static)
+endif(BUILD_STATIC_LIBS)
+
+#Make pkg-config
+set(PC_EXC "${CMAKE_INSTALL_PREFIX}")
+set(PC_INC "${CMAKE_INSTALL_FULL_INCLUDEDIR}")
+set(PC_LIB "${CMAKE_INSTALL_FULL_LIBDIR}")
+if("${PC_EXC}" STREQUAL "${CMAKE_INSTALL_PREFIX}")
+ set(PC_EXC "\$\{prefix\}")
+endif()
+if ("${PC_INC}" STREQUAL "${CMAKE_INSTALL_PREFIX}/include")
+ set(PC_INC "\$\{prefix\}/include")
+endif()
+if ("${PC_LIB}" STREQUAL "${CMAKE_INSTALL_PREFIX}/lib")
+ set(PC_LIB "\$\{exec_prefix\}/lib")
+endif()
+
+if(RHASH_WITH_PKGCONFIG_SUPPORT)
+ # This stuff is necessary to ensure that the dependency list
+ # in our .pc file is in the proper format
+ set(RHASH_PKGCONF_RHASH_DEPS "")
+ foreach(RHASH_LIB_DEP ${RHASH_LIB_DEPEND_LIBS})
+ set(RHASH_PKGCONF_RHASH_DEPS "${RHASH_PKGCONF_RHASH_DEPS} -l${RHASH_LIB_DEP}")
+ endforeach(RHASH_LIB_DEP)
+
+ set(PKGCONFIG_CONTENTS "prefix=${CMAKE_INSTALL_PREFIX}\r
+exec_prefix=${PC_EXC}
+libdir=${PC_LIB}
+includedir=${PC_INC}
+
+Name: librash
+Description: LibRHash shared library
+Version: ${RHASH_VERSION_MAJOR}.${RHASH_VERSION_MINOR}.${RHASH_VERSION_PATCH}
+Cflags: -I\$\{includedir\}
+Libs: -L\${libdir\} -lrhash
+Libs.private: ${RHASH_PKGCONF_RHASH_DEPS}
+")
+ file(WRITE ${RHASH_LIBRHASH_PC} ${PKGCONFIG_CONTENTS})
+ install(FILES ${RHASH_LIBRHASH_PC} DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+endif(RHASH_WITH_PKGCONFIG_SUPPORT)
+
+if(RHASH_INCLUDE_OTHER_FILES)
+ # rpm spec file
+ file(READ "${RHASH_RHASH_SPECFILE_IN}" RHASH_FILE_CONTENTS)
+ string(REPLACE "@VERSION@" "${RHASH_VERSION_MAJOR}.${RHASH_VERSION_MINOR}.${RHASH_VERSION_PATCH}" RHASH_FILE_CONTENTS "${RHASH_FILE_CONTENTS}")
+ file(WRITE ${RHASH_SPECFILE} "${RHASH_FILE_CONTENTS}")
+ install(FILES ${RHASH_SPECFILE} DESTINATION ${CMAKE_INSTALL_DOCDIR})
+endif(RHASH_INCLUDE_OTHER_FILES)
+
+if(RHASH_BUILD_LIB_DOCS)
+#Note that we use this to ensure that the Doxyfile has the appropriate properly formatted settings
+#including _NOT_FOUND messages.
+ set(RHASH_HAVE_DOT "NO")
+#This is somewhat messy because I couldn't figure out how to use the FindDoxygen module using FindPackage
+#and some stuff might not be available in older versions of CMake. I also wanted to provide Doxygen with as
+#much of it's helper program functionality as I could. Some I had to do manually for compatability with older
+#cmake versions.
+ if(DOXYGEN_FOUND)
+ message(STATUS "doxygen ${DOXYGEN_EXECUTABLE}")
+ message(STATUS "doxygen version ${DOXYGEN_VERSION}")
+ #based from: https://vicrucann.github.io/tutorials/quick-cmake-doxygen/
+ # set input and output files
+ set(RHASH_DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
+ if(DOXYGEN_DOT_FOUND)
+ set(RHASH_HAVE_DOT "YES")
+ set(RHASH_DOT_EXECUTABLE ${DOXYGEN_DOT_EXECUTABLE})
+ message(STATUS "Graphviz (dot) ${DOXYGEN_DOT_EXECUTABLE}")
+ else()
+ set(RHASH_HAVE_DOT "NO")
+ unset(RHASH_DOT_EXECUTABLE)
+ message(STATUS "Graphviz (dot) Not Found")
+ endif(DOXYGEN_DOT_FOUND)
+ set(RHASH_DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
+
+ # Optional - use mscgen
+ find_program(MSCGEN mscgen)
+ if(MSCGEN)
+ message(STATUS "mscgen ${MSCGEN}")
+ # Doxygen will use this dir to find mscgen
+ get_filename_component(RHASH_MSCGEN_PATH ${MSCGEN} DIRECTORY)
+ else()
+ message(STATUS "mscgen Not Found")
+ unset(RHASH_MSCGEN_PATH)
+ endif(MSCGEN)
+
+ # Optional - use dia
+ find_program(DIA dia)
+ if(DIA)
+ message(STATUS "dia ${DIA}")
+ # Doxygen will use this dir to find mscgen
+ get_filename_component(RHASH_DIA_PATH ${DIA} DIRECTORY)
+ else()
+ message(STATUS "dia Not Found")
+ unset(RHASH_DIA_PATH)
+ endif(DIA)
+ # request to configure the file
+ configure_file(${RHASH_DOXYGEN_IN} ${RHASH_DOXYGEN_OUT} @ONLY)
+ # note the option ALL which allows to build the docs together with the application
+ add_custom_target( doc_doxygen ALL
+ COMMAND ${DOXYGEN_EXECUTABLE} ${RHASH_DOXYGEN_OUT}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Generating API documentation with Doxygen"
+ VERBATIM )
+ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc_doxygen/html DESTINATION ${CMAKE_INSTALL_DOCDIR})
+ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc_doxygen/man/ DESTINATION ${CMAKE_INSTALL_MANDIR})
+ else()
+ message(STATUS "doxygen Not Found")
+ endif(DOXYGEN_FOUND)
+endif(RHASH_BUILD_LIB_DOCS)
+
+if(RHASH_INCLUDE_WINDIST_FILES)
+ # RHASH_WIN_DIST_FILES
+ foreach (RHASH_CURDIST ${RHASH_WIN_DIST_FILES})
+ install(FILES ${RHASH_CURDIST} DESTINATION ${CMAKE_INSTALL_FULL_DOCDIR})
+ endforeach(RHASH_CURDIST)
+ # Win32 .bat files
+ if(WIN32)
+ foreach (RHASH_CURDIST ${RHASH_WIN_BAT_FILES})
+ install(FILES ${RHASH_CURDIST} DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
+ endforeach(RHASH_CURDIST)
+ endif(WIN32)
+endif(RHASH_INCLUDE_WINDIST_FILES)
+
+# bindings
+add_custom_command(PRE_BUILD OUTPUT bindings
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
+ ${CMAKE_SOURCE_DIR}/../bindings ${RHASH_BUILD_DIST_DIR}/bindings)
+add_custom_command(PRE_BUILD OUTPUT bindings/version.properties
+ COMMAND ${CMAKE_COMMAND} -D VERSION=${RHASH_VERSION_MAJOR}.${RHASH_VERSION_MINOR}.${RHASH_VERSION_PATCH}
+ -DVERSION_PROP_FILE=${RHASH_BUILD_DIST_DIR}/bindings/version.properties
+ -P ${CMAKE_CURRENT_LIST_DIR}/make_version_properties.cmake)
+add_custom_target(bindings_dir ALL DEPENDS bindings bindings/version.properties)
+
+if(RHASH_BUILD_EXE)
+ set(RHASH_TEST_RHASH_EXE "$")
+ set(RHASH_TMPDIR "${CMAKE_BINARY_DIR}/tests")
+set(RHASH_TEST_DATA_FILE "test1K.data")
+set(RHASH_BIN_DATA_FILE "binary.data")
+set(CREATE_DIRECTORY ${CMAKE_BINARY_DIR}/tests)
+#These two files have to be copied to the temp dir so links can work
+#in our tests.
+file(COPY "${RHASH_SRC_DIR}/tests/test1K.data" DESTINATION "${RHASH_TMPDIR}")
+file(COPY "${RHASH_SRC_DIR}/tests/test1K.data" DESTINATION ${CMAKE_SOURCE_DIR}/tests)
+file(COPY "${CMAKE_SOURCE_DIR}/tests/binary.data" DESTINATION "${RHASH_TMPDIR}")
+
+ add_test(NAME test_string1 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_string1.cmake)
+
+add_test(NAME test_with_1Kb_data_file WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_with_1Kb_data_file.cmake)
+
+add_test(NAME test_handling_empty_files WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_handling_empty_files.cmake)
+
+add_test(NAME test_default_format WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_default_format.cmake)
+
+add_test(NAME test_x_b_B_modifiers WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_x_b_B_modifiers.cmake)
+
+#This one requires RHASH_BIN_DATA_FILE isntead of RHASH_TEST_DATA_FILE
+add_test(NAME test_special_characters WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_BIN_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_special_characters.cmake)
+
+if (RHASH_TESTS_OPT_FULL)
+add_test(NAME test_all_hash_options WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_ignoring_of_log_files.cmake)
+
+endif(RHASH_TESTS_OPT_FULL)
+
+add_test(NAME test_eDonkey_link WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_eDonkey_link.cmake)
+
+add_test(NAME test_checking_all_hashes WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_checking_all_hashes.cmake)
+
+add_test(NAME test_checking_magnet_link WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_checking_magnet_link.cmake)
+
+add_test(NAME test_bsd_format_checking WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_bsd_format_checking.cmake)
+
+add_test(NAME test_checking_w_o_filename WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_checking_w_o_filename.cmake)
+
+add_test(NAME test_checking_embedded_crc WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_checking_embedded_crc.cmake)
+
+add_test(NAME test_wrong_sums_detection WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_wrong_sums_detection.cmake)
+
+add_test(NAME test_accept_options WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_accept_options.cmake)
+
+add_test(NAME test_ignoring_of_log_files WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_ignoring_of_log_files.cmake)
+
+add_test(NAME test_creating_torrent_file WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_creating_torrent_file.cmake)
+
+add_test(NAME test_exit_code WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+COMMAND ${CMAKE_COMMAND} -DRHASH=${RHASH_TEST_RHASH_EXE} -DTEST_DATA_FILE=${RHASH_TEST_DATA_FILE} -DTMPDIR=${RHASH_TMPDIR} -P ${CMAKE_SOURCE_DIR}/tests/test_exit_code.cmake)
+
+endif(RHASH_BUILD_EXE)
+
+ #dump GNUInstallDirs vars
+message(STATUS "CMAKE_INSTALL_FULL_BINDIR ${CMAKE_INSTALL_FULL_BINDIR}")
+message(STATUS "CMAKE_INSTALL_FULL_SBINDIR ${CMAKE_INSTALL_FULL_SBINDIR}")
+message(STATUS "CMAKE_INSTALL_FULL_LIBEXECDIR ${CMAKE_INSTALL_FULL_LIBEXECDIR}")
+message(STATUS "CMAKE_INSTALL_FULL_SYSCONFDIR ${CMAKE_INSTALL_FULL_SYSCONFDIR}")
+message(STATUS "CMAKE_INSTALL_FULL_SHAREDSTATEDIR ${CMAKE_INSTALL_FULL_SHAREDSTATEDIR}")
+message(STATUS "CMAKE_INSTALL_FULL_LOCALSTATEDIR ${CMAKE_INSTALL_FULL_LOCALSTATEDIR}")
+message(STATUS "CMAKE_INSTALL_FULL_LIBDIR ${CMAKE_INSTALL_FULL_LIBDIR}")
+message(STATUS "CMAKE_INSTALL_FULL_INCLUDEDIR ${CMAKE_INSTALL_FULL_INCLUDEDIR}")
+message(STATUS "CMAKE_INSTALL_FULL_OLDINCLUDEDIR ${CMAKE_INSTALL_FULL_OLDINCLUDEDIR}")
+message(STATUS "CMAKE_INSTALL_FULL_DATAROOTDIR ${CMAKE_INSTALL_FULL_DATAROOTDIR}")
+message(STATUS "CMAKE_INSTALL_FULL_DATADIR ${CMAKE_INSTALL_FULL_DATADIR}")
+message(STATUS "CMAKE_INSTALL_FULL_INCLUDEDIR ${CMAKE_INSTALL_FULL_INFODIR}")
+message(STATUS "CMAKE_INSTALL_FULL_LOCALEDIR ${CMAKE_INSTALL_FULL_LOCALEDIR}")
+message(STATUS "CMAKE_INSTALL_FULL_MANDIR ${CMAKE_INSTALL_FULL_MANDIR}")
+message(STATUS "CMAKE_INSTALL_FULL_DOCDIR ${CMAKE_INSTALL_FULL_DOCDIR}")
\ No newline at end of file
diff --git a/build/Doxyfile.in b/build/Doxyfile.in
new file mode 100644
index 00000000..8d09e723
--- /dev/null
+++ b/build/Doxyfile.in
@@ -0,0 +1,27 @@
+PROJECT_NAME = @PROJECT_NAME@
+PROJECT_NUMBER = "@RHASH_VERSION_MAJOR@.@RHASH_VERSION_MINOR@.@RHASH_VERSION_PATCH@"
+PROJECT_LOGO = @CMAKE_CURRENT_LIST_DIR@/icon.png
+DOXYFILE_ENCODING = UTF-8
+OUTPUT_LANGUAGE = English
+TAB_SIZE = 8
+OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/doc_doxygen/
+GENERATE_MAN = YES
+INPUT = \
+"@RHASH_LIB_DIR@/rhash.h" \
+"@RHASH_LIB_DIR@/rhash_timing.h"
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = \
+ "@CMake_SOURCE_DIR@/" \
+ "@CMake_BINARY_DIR@/" \
+ "@CMAKE_CURRENT_BINARY_DIR@/doc_doxygen/" \
+ "@RHASH_LIB_DIR@/"
+HAVE_DOT = @RHASH_HAVE_DOT@
+DOT_PATH = @DOXYGEN_DOT_EXECUTABLE@
+MSCGEN_PATH = @RHASH_MSCGEN_PATH@
+DIA_PATH = @RHASH_DIA_PATH@
+CLASS_DIAGRAMS = YES
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
\ No newline at end of file
diff --git a/build/icon.ico b/build/icon.ico
new file mode 100644
index 00000000..ea1f7ecb
Binary files /dev/null and b/build/icon.ico differ
diff --git a/build/icon.png b/build/icon.png
new file mode 100644
index 00000000..60144d34
Binary files /dev/null and b/build/icon.png differ
diff --git a/build/make_html.cmake b/build/make_html.cmake
new file mode 100644
index 00000000..2cf06f31
--- /dev/null
+++ b/build/make_html.cmake
@@ -0,0 +1,26 @@
+# make_html.cmake
+# Do something like this:
+
+#dist/rhash.1.html: dist/rhash.1
+# -which rman 2>/dev/null && (rman -fHTML -roff dist/rhash.1 | sed -e '/ $@)
+
+#Parameters:
+# RMAN - fully-qualified name to Polyglot program (or rman)
+# MAN_FILE = fully-qualified name for MAN file to convert
+# HTML_FILE = fully-qualified name for output .HTML file
+if (NOT HTML_FILE)
+ message(FATAL_ERROR "HTML_FILE parameter is empty")
+endif(NOT HTML_FILE)
+
+if(RMAN)
+ file(TO_NATIVE_PATH ${MAN_FILE} NATIVE_MAN_FILE)
+ execute_process(COMMAND ${RMAN} -fHTML -roff ${NATIVE_MAN_FILE} OUTPUT_VARIABLE FILE_CONTENTS)
+#I'm not entirely clear what this does:
+#sed -e '/" "" "${FILE_CONTENTS}")
+ file(WRITE ${HTML_FILE} "${FILE_CONTENTS}")
+endif(RMAN)
diff --git a/build/make_txt.cmake b/build/make_txt.cmake
new file mode 100644
index 00000000..e7110fd2
--- /dev/null
+++ b/build/make_txt.cmake
@@ -0,0 +1,23 @@
+# make_txt.cmake
+# Do something like this:
+
+#dist/rhash.1.txt: dist/rhash.1
+# -which groff &>/dev/null && (groff -t -e -mandoc -Tascii dist/rhash.1 | sed -e 's/.\[[0-9]*m//g' > $@)
+
+#Parameters:
+# GROFF - fully-qualified name to Polyglot program (or rman)
+# MAN_FILE = fully-qualified name for MAN file to convert
+# TXT_FILE = fully-qualified name for output .TXT file
+if (NOT TXT_FILE)
+ message(FATAL_ERROR "TXT_FILE parameter is empty")
+endif(NOT TXT_FILE)
+
+if(GROFF)
+# file(TO_NATIVE_PATH ${MAN_FILE} NATIVE_MAN_FILE)
+
+#groff will output warnings such as:
+# invalid input character code `13'
+ execute_process(COMMAND ${GROFF} -t -e -mandoc -Tascii ${MAN_FILE} OUTPUT_VARIABLE FILE_CONTENTS ERROR_VARIABLE ERROR_CONTENTS)
+ string(REGEX REPLACE FILE_CONTENTS ".[[0-9]*m" "" "${FILE_CONTENTS}")
+ file(WRITE ${TXT_FILE} "${FILE_CONTENTS}")
+endif(GROFF)
diff --git a/build/make_version_properties.cmake b/build/make_version_properties.cmake
new file mode 100644
index 00000000..a9a24abb
--- /dev/null
+++ b/build/make_version_properties.cmake
@@ -0,0 +1,8 @@
+# make_version_properties.cmake
+#
+#VERSION_PROP_FILE = file that contains version property
+#VERSION = version as 1.x.x
+#
+#This script ensures that the property file contains the appropriate version number
+
+File(WRITE ${VERSION_PROP_FILE} "version=${VERSION}")
diff --git a/build/make_win_man.cmake b/build/make_win_man.cmake
new file mode 100644
index 00000000..cf04af1c
--- /dev/null
+++ b/build/make_win_man.cmake
@@ -0,0 +1,31 @@
+# make_win_man.cmake
+# Do something like this:
+
+#sed -f dist/rhash.1.win.sed dist/rhash.1 > dist/rhash.1.win
+
+#Parameters:
+# SED - fully-qualified name to sed
+# SED_FILE = fully-qualified name execute "sed"
+# MAN_FILE = fully-qualified name for MAN file to convert
+# WIN_FILE = fully-qualified name for output .HTML file
+
+if (NOT SED)
+ message(FATAL_ERROR "SED parameter is empty")
+endif(NOT SED)
+if (NOT WIN_FILE)
+ message(FATAL_ERROR "WIN_FILE parameter is empty")
+endif(NOT WIN_FILE)
+if (NOT MAN_FILE)
+ message(FATAL_ERROR "MAN_FILE parameter is empty")
+endif(NOT MAN_FILE)
+if (NOT SED_FILE)
+ message(FATAL_ERROR "SED_FILE parameter is empty")
+endif(NOT SED_FILE)
+
+get_filename_component(DEST_WIN_DIR ${WIN_FILE} DIRECTORY)
+get_filename_component(DEST_WIN_FN ${MAN_FILE} NAME)
+message(STATUS ${DEST_WIN_DIR})
+message(STATUS ${DEST_WIN_FN})
+file(COPY ${MAN_FILE} DESTINATION ${DEST_WIN_DIR})
+file(RENAME ${DEST_WIN_DIR}/${DEST_WIN_FN} ${WIN_FILE})
+execute_process(COMMAND ${SED} -f ${SED_FILE} -i ${WIN_FILE})
diff --git a/build/stripCR.cmake b/build/stripCR.cmake
new file mode 100644
index 00000000..9ac56e84
--- /dev/null
+++ b/build/stripCR.cmake
@@ -0,0 +1,10 @@
+#stripCR.cmake
+#
+#Strips carriage returns char(13) and writes file to DEST_FILE
+#
+#SOURCE_FILE = fully-qualified name of source file
+#DEST_FILE = fully-qualified name of destination file
+
+file(READ ${SOURCE_FILE} FILE_CONTENTS)
+string(REGEX REPLACE FILE_CONTENTS "\r" "" "${FILE_CONTENTS}")
+file(WRITE ${DEST_FILE} "${FILE_CONTENTS}")
\ No newline at end of file
diff --git a/build/tests/CMakeTestMacros.cmake b/build/tests/CMakeTestMacros.cmake
new file mode 100644
index 00000000..85eccab7
--- /dev/null
+++ b/build/tests/CMakeTestMacros.cmake
@@ -0,0 +1,62 @@
+#CMakeTestMacros.cmake
+
+macro(report_failed_test)
+ message("EXPECTED")
+ if(TEST_EXPECTED)
+ message("${TEST_EXPECTED}")
+ else(TEST_EXPECTED)
+ message("test1K.data *OK")
+ endif(TEST_EXPECTED)
+ message("GOT")
+ message("Variables")
+ message("RHASH")
+ message("${RHASH}")
+ message(TEST_RESULT)
+ message("${TEST_RESULT}")
+ message("TEST_ERROR_RESULT")
+ message("${TEST_ERROR_RESULT}")
+ message("TEST_ERR_VAR")
+ message("${TEST_ERR_VAR}")
+ message(SEND_ERROR "FAILED!!!")
+endmacro(report_failed_test)
+
+macro(checkrun)
+ if((TEST_ERR_VAR GREATER 0) OR TEST_ERROR_RESULT)
+ report_failed_test()
+ endif((TEST_ERR_VAR GREATER 0) OR TEST_ERROR_RESULT)
+endmacro(checkrun)
+
+macro(checkrun_exitcod_2)
+ if(TEST_ERR_VAR GREATER 2)
+ report_failed_test()
+ endif(TEST_ERR_VAR GREATER 2)
+ if(TEST_ERR_VAR LESS 2)
+ report_failed_test()
+ endif(TEST_ERR_VAR LESS 2)
+endmacro(checkrun_exitcod_2)
+
+macro(check_POS_OK)
+ if(_POS_OK)
+ else(_POS_OK)
+ report_failed_test()
+ endif(_POS_OK)
+endmacro(check_POS_OK)
+
+macro(check_test_res_equality)
+ if("${TEST_RESULT}" STREQUAL "${TEST_EXPECTED}")
+ else("${TEST_RESULT}" STREQUAL "${TEST_EXPECTED}")
+ report_failed_test()
+ endif("${TEST_RESULT}" STREQUAL "${TEST_EXPECTED}")
+endmacro(check_test_res_equality)
+
+macro(checktestfail)
+string(REGEX MATCH "test_.*OK" _POS_OK "${TEST_RESULT}")
+ check_POS_OK()
+endmacro(checktestfail)
+
+macro(checktestfail_ERR)
+checkrun()
+string(REGEX MATCH "test_.*ERR" _POS_OK "${TEST_RESULT}")
+check_POS_OK()
+endmacro(checktestfail_ERR)
+
diff --git a/build/tests/binary.data b/build/tests/binary.data
new file mode 100644
index 00000000..016f2657
--- /dev/null
+++ b/build/tests/binary.data
@@ -0,0 +1 @@
+3 \ 4
\ No newline at end of file
diff --git a/build/tests/test1K.data b/build/tests/test1K.data
new file mode 100644
index 00000000..c8b49c8c
Binary files /dev/null and b/build/tests/test1K.data differ
diff --git a/build/tests/test_accept_options.cmake b/build/tests/test_accept_options.cmake
new file mode 100644
index 00000000..1805e83b
--- /dev/null
+++ b/build/tests/test_accept_options.cmake
@@ -0,0 +1,82 @@
+#test_wrong_sums_detection.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+
+#new_test "test *accept options: "
+#rm -rf test_dir/
+#mkdir test_dir 2>/dev/null && touch test_dir/file.txt test_dir/file.bin
+#JPM Note - this fails to work. MSYS seems to handle this correctly (at least here.
+#SLASH="/"
+#if [ -n "$MSYSTEM" ]; then
+# case "$MSYSTEM" in
+# MINGW32|MINGW64)
+# SLASH=//;
+# ;;
+# *)
+# SLASH="/";
+# esac
+#else
+# SLASH="/";
+#TEST_RESULT=$( $rhash -rC --simple --accept=.bin --path-separator=$SLASH test_dir )
+#check "$TEST_RESULT" "00000000 test_dir/file.bin" .
+#TEST_RESULT=$( $rhash -rC --simple --accept=.txt --path-separator=\\ test_dir )
+#check "$TEST_RESULT" "00000000 test_dir\\file.txt" .
+## test --crc-accept and also --path-separator options
+## note: path-separator doesn't affect the following '( Verifying )' message
+#TEST_RESULT=$( $rhash -rc --crc-accept=.bin test_dir 2>/dev/null | sed -n '/Verifying/s/-//gp' )
+#match "$TEST_RESULT" "( Verifying test_dir.file\\.bin )"
+#rm -rf test_dir/
+#
+#Note that for this test, we will ignore the concerns about MSYS's shell since we are NOT using
+#a shell to pass commands. That's a virtue with this rewrite because you should be able to run
+#the tests irregardless of the shell itself (hopefully, this makes things more cross-platform).
+
+include(CMakeTestMacros.cmake)
+SET(TEST_STR "a")
+SET(TEST_FILE "test-empty.file")
+
+IF(EXISTS "${TMPDIR}/test_dir")
+ FILE(REMOVE_RECURSE "${TMPDIR}/test_dir")
+ENDIF(EXISTS "${TMPDIR}/test_dir")
+file(MAKE_DIRECTORY "${TMPDIR}/test_dir")
+file(WRITE "${TMPDIR}/test_dir/file.bin" "")
+file(WRITE "${TMPDIR}/test_dir/file.txt" "")
+
+#Note that cmake itself can not do a stdin test
+#and I don't want to use a shell for it since
+#shell samantics are so different.
+
+Set(TEST_EXPECTED "00000000 ${TMPDIR}/test_dir/file.bin\n")
+execute_process(COMMAND ${RHASH} -rC --simple --accept=.bin --path-separator=/ "${TMPDIR}/test_dir"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT)
+checkrun()
+check_test_res_equality()
+
+Set(TEST_EXPECTED "00000000 ${TMPDIR}/test_dir/file.txt\n")
+string(REPLACE "/" "\\" TEST_EXPECTED "${TEST_EXPECTED}")
+execute_process(COMMAND ${RHASH} -rC --simple --accept=.txt --path-separator=\\ "${TMPDIR}/test_dir"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checkrun()
+check_test_res_equality()
+
+## test --crc-accept and also --path-separator options
+## note: path-separator doesn't affect the following '( Verifying )' message
+#TEST_RESULT=$( $rhash -rc --crc-accept=.bin test_dir 2>/dev/null | sed -n '/Verifying/s/-//gp' )
+#match "$TEST_RESULT" "( Verifying test_dir.file\\.bin )"
+#rm -rf test_dir/
+
+set(TEST_EXPECTED "Verifying ${TMPDIR}/test_dir/file.bin")
+execute_process(COMMAND ${RHASH} -rc --crc-accept=.bin "${TMPDIR}/test_dir/file.bin"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checkrun()
+#JPM - Regex in cmake sometimes requires \\\ instead of \ due to how strings parsing works.
+string(REGEX REPLACE "\\\n" "" TEST_RESULT "${TEST_RESULT}")
+string(REGEX REPLACE "-.*\\\( " "" TEST_RESULT "${TEST_RESULT}")
+string(REGEX REPLACE " \\\)-.*" "" TEST_RESULT "${TEST_RESULT}")
+check_test_res_equality()
+
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
+
+ FILE(REMOVE_RECURSE "${TMPDIR}/test_dir")
diff --git a/build/tests/test_all_hash_options.cmake b/build/tests/test_all_hash_options.cmake
new file mode 100644
index 00000000..dcebd520
--- /dev/null
+++ b/build/tests/test_all_hash_options.cmake
@@ -0,0 +1,44 @@
+#test_all_hash_options.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+#
+#HASHOPT="`$rhash --list-hashes|sed 's/ .*$//;/[^3]-/s/-\([0-9R]\)/\1/'|tr A-Z a-z`"
+#
+#if [ -n "$OPT_FULL" ]; then
+# new_test "test all hash options: "
+# errors=0
+# for opt in $HASHOPT ; do
+# TEST_RESULT=$( printf "a" | $rhash --$opt --simple - )
+# match "$TEST_RESULT" "\b[0-9a-z]\{8,128\}\b" . || errors=$((errors+1))
+# done
+# check $errors 0
+#fi
+
+set(TEST_EXPECTED "test.string F0099E81 B78F440152DBAD00E77017074DC15417 EA8511AE2CA899D68DB423AD751B446C6F958507 R37TT7VDWGK26FUDTFANGUJBFKYDGAV4ARK3EEI 9EDCAE6F50EFE09F0837DA66A8B88C13 5KCRDLRMVCM5NDNUEOWXKG2ENRXZLBIH 01D00FBBA6A0903499385151BF678CDF4294986CF5B76A6A5660AC5834FA429E12861BC5174C7648CA4086B0FCE3F211F80423824E9A9589A20FC43A81D8B752 3D3E1DB92A2030B1287769AAD2190DD69EED5911644EC6E7BB7AEAB5FC701BE3")
+include(CMakeTestMacros.cmake)
+SET(TEST_STR "a")
+SET(TEST_FILE "a")
+
+execute_process(
+ COMMAND ${RHASH} --list-hashes OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT)
+checkrun()
+FILE(WRITE "${TMPDIR}/${TEST_FILE}" "${TEST_STR}")
+string(TOLOWER TEST_RESULT "TEST_RESULT")
+
+string(REPLACE "\n" ";" HASHOPTS "${TEST_RESULT}")
+string(REPLACE "-" "" HASHOPTS "${HASHOPTS}")
+
+foreach OPT ${HASHOPTS})
+execute_process(
+ COMMAND ${RHASH} --${_OPT} --simple "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT
+)
+checkrun()
+string(REGEX MATCH "\b[0-9a-z]\{8,128\}\b" _POS_OK ${TEST_RESULT})
+check_POS_OK()
+endeach(OPT)
+
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
+
diff --git a/build/tests/test_bsd_format_checking.cmake b/build/tests/test_bsd_format_checking.cmake
new file mode 100644
index 00000000..cc97ee5d
--- /dev/null
+++ b/build/tests/test_bsd_format_checking.cmake
@@ -0,0 +1,35 @@
+#test_bsd_format_checking.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+#
+#new_test "test bsd format checking: "
+#TEST_RESULT=$( $rhash --bsd -a test1K.data | $rhash -vc - 2>&1 | grep -i -e warn -e err )
+#check "$TEST_RESULT" ""
+
+SET(TEST_FILE "a")
+include(CMakeTestMacros.cmake)
+
+execute_process(COMMAND ${RHASH} --bsd -a "${TEST_DATA_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT)
+checkrun()
+
+#rhash -vc
+FILE(WRITE "${TMPDIR}/${TEST_FILE}" "${TEST_RESULT}")
+execute_process(COMMAND ${RHASH} -vc "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checkrun()
+
+string(FIND "warn" _POS_MSG "${TEST_ERROR_RESULT}")
+if(NOT _POS_MSG)
+ string(FIND "err" _POS_MSG "${TEST_ERROR_RESULT}")
+endif(NOT _POS_MSG)
+
+if(_POS_MSG)
+ report_failed_test()
+else(_POS_MSG)
+ message("OK")
+endif(_POS_MSG)
+
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
diff --git a/build/tests/test_checking_all_hashes.cmake b/build/tests/test_checking_all_hashes.cmake
new file mode 100644
index 00000000..810ffcf4
--- /dev/null
+++ b/build/tests/test_checking_all_hashes.cmake
@@ -0,0 +1,34 @@
+#test_checking_all_hashes.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+#
+#new_test "test checking all hashes: "
+#TEST_RESULT=$( $rhash --simple -a test1K.data | $rhash -vc - 2>/dev/null | grep test1K.data )
+#match "$TEST_RESULT" "^test1K.data *OK"
+
+SET(TEST_FILE "a")
+set(TEST_EXPECTED "${TEST_DATA_FILE} b70b4c26 5ae257c47e9be1243ee32aabe408fb6b b2ea9f7fcea831a4a63b213f41a8855b 5b00669c480d5cffbdfa8bdba99561160f2d1b77 d25963c1686c96fb8881f6d10c439a7fe853c906e4eb3662 4oqy25un2xhidqpv5u6bxaz47inucygibk7lfni 33e75b119aa12c75391d662b341ee0af8203ec13 5ae257c47e9be1243ee32aabe408fb6b lmagnhcibvop7pp2rpn2tflbcyhs2g3x d606b7f44bd288759f8869d880d9d4a2f159d739005e72d00f93b814e8c04e657f40c838e4d6f9030a8c9e0308a4e3b450246250243b2f09e09fa5a24761e26b 29ea7f13cac242905ae2dc1a36d5985815b30356 890bb3ee5dbe4da22d6719a14efd9109b220607e1086c1abbb51eeac2b044cbb d9c92e33ab144bbb2262a5221739600062831664d16716d03751fba7d952cc06 1a3ff10095b61f4ce0cbde76f615284e52133b99 7479ed8c193a23af522f1b8c1a853758 4c2f2a13ac7745d117838b0be8ebb39bedd5d44b332ae8c973ac07efb50abac0 6290817f6001432cd441058d2bb82d88b3f32425ade4c93d56207838 785b0751fc2c53dc14a4ce3d800e69ef9ce1009eb327ccf458afe09c242c26c9 55fd17eeb1611f9193f6ac600238ce63aa298c2e332f042b80c8f691f800e4c7505af20c1a86a31f08504587395f081f 37f652be867f28ed033269cbba201af2112c2b3fd334a89fd2f757938ddee815787cc61d6e24a8a33340d0f7e86ffc058816b88530766ba6e231620a130b566c 069744670fd47d89f59489a45ee0d6b8f597c7c74895914997dedde4c60396f1 cd0f7ecf145c769e462cb3d1cda0a7fb5503c11b0e29e0fe9071c27e07a74f2448686a2e54619dcee8ffcbc1012f6b393faf5e40de01f76f8c75689684c161e2 5b37c09e5b5cf21b0d8097e9479fe6982003b617d41ab2293d77bf22 b6c70631c6ff932b9f380d9cde8750eb9bea393817a9aea410c2119eb7b9b870 bfdb44fcb75b4a02db0487b0c607630283ae792bbef4797bd993009a2fd15cf2425b1a9f82f25f6cdc7cac15be3d572e b052fd4a09f988bbe4112d9a3eca8ccc517e56da866c1609504c37871146da80731bb681674a2000a41bcb78230b3d9069eb42820293ce23cba294550a1d4d3b\n")
+include(CMakeTestMacros.cmake)
+
+execute_process(
+COMMAND ${RHASH} --simple -a "${TEST_DATA_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT)
+checkrun()
+
+if("${TEST_RESULT}" STREQUAL "${TEST_EXPECTED}")
+else("${TEST_RESULT}" STREQUAL "${TEST_EXPECTED}")
+ report_failed_test()
+endif("${TEST_RESULT}" STREQUAL "${TEST_EXPECTED}")
+
+#rhash -vc
+FILE(WRITE "${TMPDIR}/${TEST_FILE}" "${TEST_RESULT}")
+execute_process(COMMAND ${RHASH} -vc "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checkrun()
+
+string(REGEX MATCH "test1K.data *OK" _POS_OK ${TEST_RESULT})
+check_POS_OK()
+
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
diff --git a/build/tests/test_checking_embedded_crc.cmake b/build/tests/test_checking_embedded_crc.cmake
new file mode 100644
index 00000000..c1abe0ff
--- /dev/null
+++ b/build/tests/test_checking_embedded_crc.cmake
@@ -0,0 +1,62 @@
+#test_checking_magnet_link.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+#
+
+include(CMakeTestMacros.cmake)
+
+SET(TEST_FILE "a")
+SET(TEST_FILE_A "test_[D3D99E8B].data")
+SET(TEST_FILE_B "test_[D3D99E8C].data")
+file(WRITE "${TMPDIR}/${TEST_FILE_A}" "A")
+file(WRITE "${TMPDIR}/${TEST_FILE_B}" "A")
+
+# first verify checking an existing crc32 while '--embed-crc' option is set
+#TEST_RESULT=$( $rhash -C --simple 'test_[D3D99E8B].data' | $rhash -vc --embed-crc - 2>/dev/null | grep data )
+#match "$TEST_RESULT" "^test_.*OK" .
+
+execute_process(
+COMMAND ${RHASH} -C --simple "${TMPDIR}/${TEST_FILE_A}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT)
+checkrun()
+
+file(WRITE "${TMPDIR}/${TEST_FILE}" "${TEST_RESULT}")
+
+#rhash -vc --embed-crc
+execute_process(
+COMMAND ${RHASH} -vc --embed-crc "${TMPDIR}/${TEST_FILE}" OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checktestfail()
+
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
+## second verify --check-embedded option
+#TEST_RESULT=$( $rhash --check-embedded 'test_[D3D99E8B].data' 2>/dev/null | grep data )
+#match "$TEST_RESULT" "test_.*OK" .
+#TEST_RESULT=$( $rhash --check-embedded 'test_[D3D99E8C].data' 2>/dev/null | grep data )
+#match "$TEST_RESULT" "test_.*ERR" .
+#mv 'test_[D3D99E8B].data' 'test.data'
+
+execute_process(
+ COMMAND ${RHASH} --check-embedded "${TMPDIR}/${TEST_FILE_A}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checktestfail()
+
+execute_process(
+ COMMAND ${RHASH} --check-embedded "${TMPDIR}/${TEST_FILE_B}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checktestfail_ERR()
+file(RENAME "${TMPDIR}/${TEST_FILE_B}" "${TMPDIR}/test.data")
+
+# at last test --embed-crc with --embed-crc-delimiter options
+#TEST_RESULT=$( $rhash --simple --embed-crc --embed-crc-delimiter=_ 'test.data' 2>/dev/null )
+#check "$TEST_RESULT" "d3d99e8b test_[D3D99E8B].data"
+#rm 'test_[D3D99E8B].data' 'test_[D3D99E8C].data'
+execute_process(
+ COMMAND ${RHASH} --simple --embed-crc --embed-crc-delimiter=_ "test.data"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+
+string(FIND "d3d99e8b test_[D3D99E8B].data" _POS_OK "${TEST_RESULT}")
+check_POS_OK()
+FILE(REMOVE "${TMPDIR}/${TEST_FILE_A}")
+FILE(REMOVE "${TMPDIR}/${TEST_FILE_B}")
diff --git a/build/tests/test_checking_magnet_link.cmake b/build/tests/test_checking_magnet_link.cmake
new file mode 100644
index 00000000..bc4f6cf0
--- /dev/null
+++ b/build/tests/test_checking_magnet_link.cmake
@@ -0,0 +1,67 @@
+#test_checking_magnet_link.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+#
+#new_test "test checking magnet link: "
+#TEST_RESULT=$( $rhash --magnet -a test1K.data | $rhash -vc - 2>&1 | grep -i -e warn -e test1K.data )
+#TEST_EXPECTED="^test1K.data *OK"
+#match "$TEST_RESULT" "$TEST_EXPECTED"
+
+SET(TEST_FILE "a")
+set(TEST_EXPECTED "magnet:?xl=1024&dn=test1K.data&xt=urn:crc32:b70b4c26&xt=urn:md4:5ae257c47e9be1243ee32aabe408fb6b&xt=urn:md5:b2ea9f7fcea831a4a63b213f41a8855b&xt=urn:sha1:lmagnhcibvop7pp2rpn2tflbcyhs2g3x&xt=urn:tiger:d25963c1686c96fb8881f6d10c439a7fe853c906e4eb3662&xt=urn:tree:tiger:4oqy25un2xhidqpv5u6bxaz47inucygibk7lfni&xt=urn:btih:gptvwem2uewhkoi5myvtihxav6bah3at&xt=urn:ed2k:5ae257c47e9be1243ee32aabe408fb6b&xt=urn:aich:lmagnhcibvop7pp2rpn2tflbcyhs2g3x&xt=urn:whirlpool:d606b7f44bd288759f8869d880d9d4a2f159d739005e72d00f93b814e8c04e657f40c838e4d6f9030a8c9e0308a4e3b450246250243b2f09e09fa5a24761e26b&xt=urn:ripemd160:29ea7f13cac242905ae2dc1a36d5985815b30356&xt=urn:gost:890bb3ee5dbe4da22d6719a14efd9109b220607e1086c1abbb51eeac2b044cbb&xt=urn:gost-cryptopro:d9c92e33ab144bbb2262a5221739600062831664d16716d03751fba7d952cc06&xt=urn:has160:1a3ff10095b61f4ce0cbde76f615284e52133b99&xt=urn:snefru128:7479ed8c193a23af522f1b8c1a853758&xt=urn:snefru256:4c2f2a13ac7745d117838b0be8ebb39bedd5d44b332ae8c973ac07efb50abac0&xt=urn:sha224:6290817f6001432cd441058d2bb82d88b3f32425ade4c93d56207838&xt=urn:sha256:785b0751fc2c53dc14a4ce3d800e69ef9ce1009eb327ccf458afe09c242c26c9&xt=urn:sha384:55fd17eeb1611f9193f6ac600238ce63aa298c2e332f042b80c8f691f800e4c7505af20c1a86a31f08504587395f081f&xt=urn:sha512:37f652be867f28ed033269cbba201af2112c2b3fd334a89fd2f757938ddee815787cc61d6e24a8a33340d0f7e86ffc058816b88530766ba6e231620a130b566c&xt=urn:edon-r256:069744670fd47d89f59489a45ee0d6b8f597c7c74895914997dedde4c60396f1&xt=urn:edon-r512:cd0f7ecf145c769e462cb3d1cda0a7fb5503c11b0e29e0fe9071c27e07a74f2448686a2e54619dcee8ffcbc1012f6b393faf5e40de01f76f8c75689684c161e2&xt=urn:sha3-224:5b37c09e5b5cf21b0d8097e9479fe6982003b617d41ab2293d77bf22&xt=urn:sha3-256:b6c70631c6ff932b9f380d9cde8750eb9bea393817a9aea410c2119eb7b9b870&xt=urn:sha3-384:bfdb44fcb75b4a02db0487b0c607630283ae792bbef4797bd993009a2fd15cf2425b1a9f82f25f6cdc7cac15be3d572e&xt=urn:sha3-512:b052fd4a09f988bbe4112d9a3eca8ccc517e56da866c1609504c37871146da80731bb681674a2000a41bcb78230b3d9069eb42820293ce23cba294550a1d4d3b\n")
+macro(checkrun)
+ if(TEST_ERROR_RESULT)
+ message(SEND_ERROR "${TEST_ERROR_RESULT}")
+ endif(TEST_ERROR_RESULT)
+
+ if(TEST_ERR_VAR GREATER 0)
+ message(SEND_ERROR "${TEST_ERR_VAR}")
+ endif(TEST_ERR_VAR GREATER 0)
+endmacro(checkrun)
+
+macro(report_failed_test)
+ message("EXPECTED")
+ message("test1K.data *OK")
+ message("GOT")
+ message("Variables")
+ message("RHASH")
+ message("${RHASH}")
+ message(TEST_RESULT)
+ message("${TEST_RESULT}")
+ message("TEST_ERROR_RESULT")
+ message("${TEST_ERROR_RESULT}")
+ message("TEST_ERR_VAR")
+ message("${TEST_ERR_VAR}")
+ message(SEND_ERROR "FAILED!!!")
+endmacro(report_failed_test)
+
+macro(check_POS_OK)
+ if(_POS_OK)
+ else(_POS_OK)
+ report_failed_test()
+ endif(_POS_OK)
+endmacro(check_POS_OK)
+
+execute_process(
+COMMAND ${RHASH} --magnet -a "${TEST_DATA_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT)
+checkrun()
+
+if("${TEST_RESULT}" STREQUAL "${TEST_EXPECTED}")
+else("${TEST_RESULT}" STREQUAL "${TEST_EXPECTED}")
+ report_failed_test()
+endif("${TEST_RESULT}" STREQUAL "${TEST_EXPECTED}")
+
+#rhash -vc
+FILE(WRITE "${TMPDIR}/${TEST_FILE}" "${TEST_RESULT}")
+execute_process(
+COMMAND ${RHASH} -vc "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checkrun()
+
+string(REGEX MATCH "test1K.data *OK" _POS_OK ${TEST_RESULT})
+check_POS_OK()
+
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
diff --git a/build/tests/test_checking_w_o_filename.cmake b/build/tests/test_checking_w_o_filename.cmake
new file mode 100644
index 00000000..91d3d993
--- /dev/null
+++ b/build/tests/test_checking_w_o_filename.cmake
@@ -0,0 +1,44 @@
+#test_checking_w_o_filename.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+#
+#new_test "test checking w/o filename: "
+#$rhash -p '%c\n%m\n%e\n%h\n%g\n%t\n%a\n' test1K.data > test1K.data.hash
+#TEST_RESULT=$( $rhash -vc test1K.data.hash 2>&1 | grep -i -e warn -e err )
+#TEST_EXPECTED=""
+#check "$TEST_RESULT" "$TEST_EXPECTED"
+include(CMakeTestMacros.cmake)
+SET(TEST_FILE "test1K.data.hash")
+get_filename_component(_FNAME "${TEST_DATA_FILE}" NAME)
+execute_process(
+COMMAND ${RHASH} -p "%c\n%m\n%e\n%h\n%g\n%t\n%a\n" "${_FNAME}"
+ OUTPUT_VARIABLE TEST_RESULT
+ RESULT_VARIABLE TEST_ERR_VAR
+ ERROR_VARIABLE TEST_ERROR_RESULT)
+checkrun()
+
+#rhash -vc
+FILE(WRITE "${TMPDIR}/${TEST_FILE}" "${TEST_RESULT}")
+execute_process(COMMAND ${RHASH} -vc "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT
+ RESULT_VARIABLE TEST_ERR_VAR
+ ERROR_VARIABLE TEST_ERROR_RESULT)
+#TEST_ERROR_RESULT may not be empty
+if(TEST_ERR_VAR GREATER 0)
+ report_failed_test()
+endif(TEST_ERR_VAR GREATER 0)
+
+string(FIND "warn" _POS_MSG "${TEST_ERROR_RESULT}")
+if(NOT _POS_MSG)
+ string(FIND "err" _POS_MSG "${TEST_ERROR_RESULT}")
+endif(NOT _POS_MSG)
+
+if(_POS_MSG)
+ report_failed_test()
+else(_POS_MSG)
+ message("OK")
+endif(_POS_MSG)
+
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
diff --git a/build/tests/test_creating_torrent_file.cmake b/build/tests/test_creating_torrent_file.cmake
new file mode 100644
index 00000000..e458d928
--- /dev/null
+++ b/build/tests/test_creating_torrent_file.cmake
@@ -0,0 +1,27 @@
+#test_creating_torrent_file.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+
+#new_test "test creating torrent file: "
+#TEST_RESULT=$( $rhash --btih --torrent --bt-private --bt-piece-length=512 --bt-announce=http://tracker.org/ 'test1K.data' 2>/dev/null )
+#check "$TEST_RESULT" "29f7e9ef0f41954225990c513cac954058721dd2 test1K.data"
+#rm test1K.data.torrent
+
+include(CMakeTestMacros.cmake)
+SET(TEST_STR "")
+SET(TEST_EXPECTED "29f7e9ef0f41954225990c513cac954058721dd2 test1K.data\n")
+
+message(STATUS "RHASH = ${RHASH}")
+message(STATUS "TEST_DATA_FILE = ${TEST_DATA_FILE}")
+message(STATUS "TMPDIR = ${TMPDIR}")
+
+
+execute_process(COMMAND ${RHASH} --btih --torrent --bt-private --bt-piece-length=512 --bt-announce=http://tracker.org/ "${TEST_DATA_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checkrun()
+check_test_res_equality()
+
+FILE(REMOVE "${TEST_DATA_FILE}.torrent")
+
diff --git a/build/tests/test_default_format.cmake b/build/tests/test_default_format.cmake
new file mode 100644
index 00000000..9f4498b8
--- /dev/null
+++ b/build/tests/test_default_format.cmake
@@ -0,0 +1,68 @@
+#test_default_format.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+
+# Test the SFV format using test1K.data from the previous test
+#new_test "test default format: "
+#$rhash test1K.data | (
+# read l; match_line "$l" "^; Generated by RHash"
+# read l; match_line "$l" "^; Written by"
+# read l; match_line "$l" "^;\$"
+# read l; match_line "$l" "^; *1024 [0-9:\.]\{8\} [0-9-]\{10\} test1K.data\$"
+# read l; match_line "$l" "^test1K.data B70B4C26\$"
+#) > match_err.log
+#[ ! -s match_err.log ] && echo "Ok" || echo "Failed" && cat match_err.log
+#rm -f match_err.log
+
+#Note that this looks odd but we are using CMake lists
+#where a ";" separates each item
+SET(EXPECTED "")
+LIST(APPEND EXPECTED "")
+LIST(APPEND EXPECTED " Generated by RHash")
+LIST(APPEND EXPECTED " Written by")
+LIST(APPEND EXPECTED "\n")
+LIST(APPEND EXPECTED " *1024 [0-9:.]{8} [0-9-]{10} test1K.data\ntest1K.data B70B4C26\n")
+
+#Note that cmake itself can not do a stdin test
+#and I don't want to use a shell for it since
+#shell samantics are so different.
+execute_process(
+COMMAND ${RHASH} -p "%m" "${TEST_DATA_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT
+ RESULT_VARIABLE TEST_ERR_VAR
+ ERROR_VARIABLE TEST_ERROR_RESULT)
+
+if(TEST_ERROR_RESULT)
+ message(SEND_ERROR "${TEST_ERROR_RESULT}")
+endif(TEST_ERROR_RESULT)
+
+if(TEST_ERR_VAR GREATER 0)
+ message(SEND_ERROR "${TEST_ERR_VAR}")
+endif(TEST_ERR_VAR GREATER 0)
+
+foreach(LINE ${TEST_RESULT})
+ LIST(GET EXPECTED 0 _EXPECTED_LINE)
+ LIST(REMOVE_AT EXPECTED 0)
+ if( ("${LINE}" STREQUAL "") AND ("${_EXPECTED_LINE}" STREQUAL "") )
+ string(REGEX MATCH "${_EXPECTED_LINE}" _MATCH "${LINE}")
+ if(_MATCH)
+ else(_MATCH)
+ message("EXPECTED")
+ message("${_EXPECTED_LINE}")
+ message("GOT")
+ message("Variables")
+ message("RHASH")
+ message("${RHASH}")
+ message("TEST_RESULT")
+ message("${TEST_RESULT}")
+ message("TEST_ERROR_RESULT")
+ message("${TEST_ERROR_RESULT}")
+ message("TEST_ERR_VAR")
+ message("${TEST_ERR_VAR}")
+ message(SEND_ERROR "FAILED!!!")
+ break()
+ endif(_MATCH)
+ endif ( ("${LINE}" STREQUAL "") AND ("${_EXPECTED_LINE}" STREQUAL "") )
+endforeach(LINE TEST_RESULT)
diff --git a/build/tests/test_eDonkey_link.cmake b/build/tests/test_eDonkey_link.cmake
new file mode 100644
index 00000000..4c13ddad
--- /dev/null
+++ b/build/tests/test_eDonkey_link.cmake
@@ -0,0 +1,49 @@
+#test_eDonkey_link.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+
+#new_test "test eDonkey link: "
+#TEST_RESULT=$( printf "a" | $rhash -p '%f %L %l\n' - )
+#TEST_EXPECTED="(stdin) ed2k://|file|(stdin)|1|BDE52CB31DE33E46245E05FBDBD6FB24|h=Q336IN72UWT7ZYK5DXOLT2XK5I3XMZ5Y|/ ed2k://|file|(stdin)|1|bde52cb31de33e46245e05fbdbd6fb24|h=q336in72uwt7zyk5dxolt2xk5i3xmz5y|/"
+#check "$TEST_RESULT" "$TEST_EXPECTED" .
+# here we should test checking of ed2k links but it is currently unsupported
+#TEST_RESULT=$( $rhash -L test1K.data | $rhash -vc - 2>/dev/null | grep test1K.data )
+#match "$TEST_RESULT" "^test1K.data *OK"
+include(CMakeTestMacros.cmake)
+set(TEST_EXPECTED "a ed2k://|file|a|1|BDE52CB31DE33E46245E05FBDBD6FB24|h=Q336IN72UWT7ZYK5DXOLT2XK5I3XMZ5Y|/ ed2k://|file|a|1|bde52cb31de33e46245e05fbdbd6fb24|h=q336in72uwt7zyk5dxolt2xk5i3xmz5y|/\n")
+
+set(TEST_STR "a")
+SET(TEST_FILE "a")
+
+FILE(WRITE "${TMPDIR}/${TEST_FILE}" "${TEST_STR}")
+
+execute_process(
+COMMAND ${RHASH} -p "%f %L %l\n" "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT)
+checkrun()
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
+check_test_res_equality()
+
+set(TEST_EXPECTED "ed2k://|file|test1K.data|1024|5ae257c47e9be1243ee32aabe408fb6b|h=lmagnhcibvop7pp2rpn2tflbcyhs2g3x|/")
+# here we should test checking of ed2k links but it is currently unsupported
+#TEST_RESULT=$( $rhash -L test1K.data | $rhash -vc - 2>/dev/null | grep test1K.data )
+#match "$TEST_RESULT" "^test1K.data *OK"
+execute_process(
+COMMAND ${RHASH} -L "${TEST_DATA_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT)
+checkrun()
+check_test_res_equality()
+
+#rhash -vc
+FILE(WRITE "${TMPDIR}/${TEST_FILE}" "${TEST_RESULT}")
+execute_process(
+COMMAND ${RHASH} -vc "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checkrun()
+
+string(REGEX MATCH "test1K.data *OK" _POS_OK ${TEST_RESULT})
+check_POS_OK()
+
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
diff --git a/build/tests/test_exit_code.cmake b/build/tests/test_exit_code.cmake
new file mode 100644
index 00000000..128ea705
--- /dev/null
+++ b/build/tests/test_exit_code.cmake
@@ -0,0 +1,36 @@
+#test_ignoring_of_log_files.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+
+
+#new_test "test exit code: "
+#rm -f none-existent.file
+#test -f none-existent.file && print_failed .
+#$rhash -H none-existent.file 2>/dev/null
+#check "$?" "2" .
+#$rhash -c none-existent.file 2>/dev/null
+#check "$?" "2" .
+#$rhash -H test1K.data >/dev/null
+#check "$?" "0"
+
+include(CMakeTestMacros.cmake)
+SET(TEST_STR "")
+SET(TEST_FILE "none-existent.file")
+SET(TEST_EXPECTED "")
+
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
+
+execute_process(COMMAND ${RHASH} -H "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checkrun_exitcod_2()
+
+execute_process(COMMAND -c "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checkrun_exitcod_2()
+
+execute_process(COMMAND -c "${TMPDIR}/${TEST_DATA_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checkrun()
+
diff --git a/build/tests/test_handling_empty_files.cmake b/build/tests/test_handling_empty_files.cmake
new file mode 100644
index 00000000..4a815e28
--- /dev/null
+++ b/build/tests/test_handling_empty_files.cmake
@@ -0,0 +1,42 @@
+#test_handling_empty_files.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+
+#new_test "test handling empty files: "
+#printf "" > test-empty.file
+#TEST_RESULT=$( $rhash -p "%m" test-empty.file )
+#check "$TEST_RESULT" "d41d8cd98f00b204e9800998ecf8427e" .
+## now test processing of empty stdin
+#TEST_RESULT=$( printf "" | $rhash -p "%m" - )
+#check "$TEST_RESULT" "d41d8cd98f00b204e9800998ecf8427e" .
+## test verification of empty file
+#TEST_RESULT=$( $rhash -c test-empty.file | grep "^[^-]" )
+#check "$TEST_RESULT" "Everything OK"
+#rm test-empty.file
+
+set(TEST_EXPECTED "d41d8cd98f00b204e9800998ecf8427e")
+include(CMakeTestMacros.cmake)
+SET(TEST_STR "test_string1")
+SET(TEST_FILE "test-empty.file")
+
+FILE(WRITE "${TMPDIR}/${TEST_FILE}" "")
+
+#Note that cmake itself can not do a stdin test
+#and I don't want to use a shell for it since
+#shell samantics are so different.
+execute_process(COMMAND ${RHASH} -p "%m" "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT)
+checkrun()
+check_test_res_equality()
+
+execute_process(
+COMMAND ${RHASH} -c "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT)
+checkrun()
+
+string(REGEX MATCH "^[^-]" _POS_OK ${TEST_RESULT})
+check_POS_OK()
+
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
diff --git a/build/tests/test_ignoring_of_log_files.cmake b/build/tests/test_ignoring_of_log_files.cmake
new file mode 100644
index 00000000..2f67934c
--- /dev/null
+++ b/build/tests/test_ignoring_of_log_files.cmake
@@ -0,0 +1,36 @@
+#test_ignoring_of_log_files.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+
+#new_test "test ignoring of log files: "
+#touch test_file1.out test_file2.out
+#TEST_RESULT=$( $rhash -C --simple test_file1.out test_file2.out -o test_file1.out -l test_file2.out 2>/dev/null )
+#check "$TEST_RESULT" "" .
+#TEST_RESULT=$( $rhash -c test_file1.out test_file2.out -o test_file1.out -l test_file2.out 2>/dev/null )
+#check "$TEST_RESULT" ""
+#rm test_file1.out test_file2.out
+
+
+include(CMakeTestMacros.cmake)
+SET(TEST_STR "")
+SET(TEST_FILE_1 "test_file1.out")
+SET(TEST_FILE_2 "test_file1.out")
+SET(TEST_EXPECTED "")
+
+FILE(WRITE "${TMPDIR}/${TEST_FILE_1}" "")
+FILE(WRITE "${TMPDIR}/${TEST_FILE_2}" "")
+
+execute_process(COMMAND ${RHASH} --simple "${TMPDIR}/${TEST_FILE_1}" "${TMPDIR}/${TEST_FILE_2}" -o "${TMPDIR}/${TEST_FILE_1}" -l "${TMPDIR}/${TEST_FILE_2}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checkrun()
+check_test_res_equality()
+#file(WRITE "${TMPDIR}/test1K.data.hash" "${TEST_OUTPUT}")
+execute_process(COMMAND ${RHASH} -c "${TMPDIR}/${TEST_FILE_1}" "${TMPDIR}/${TEST_FILE_2}" -o "${TMPDIR}/${TEST_FILE_1}" -l "${TMPDIR}/${TEST_FILE_2}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checkrun()
+check_test_res_equality()
+
+FILE(REMOVE "${TMPDIR}/${TEST_FILE_1}")
+FILE(REMOVE "${TMPDIR}/${TEST_FILE_2}")
diff --git a/build/tests/test_special_characters.cmake b/build/tests/test_special_characters.cmake
new file mode 100644
index 00000000..5d6d7868
--- /dev/null
+++ b/build/tests/test_special_characters.cmake
@@ -0,0 +1,52 @@
+#test_x_b_B_modifiers.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - binary.data
+#TMPDIR - temporary directory for test
+#
+#new_test "test special characters: "
+#TEST_RESULT=$( echo | $rhash -p '\63\1\277\x0f\x1\t\\ \x34\r' - )
+#TEST_EXPECTED=$( printf '\63\1\277\17\1\t\\ 4\r' )
+#check "$TEST_RESULT" "$TEST_EXPECTED"
+
+SET(TEST_FILE "bin.data.out")
+
+execute_process(
+COMMAND ${RHASH} -p "\\63\\1\\277\\x0f\\x1\\t\\\\ \\x34\\r" ${TEST_DATA_FILE}
+ OUTPUT_VARIABLE TEST_RESULT
+ RESULT_VARIABLE TEST_ERR_VAR
+ ERROR_VARIABLE TEST_ERROR_RESULT
+)
+#This bit is not optimal but cmake string comparisons
+#do not work well and I couldn't find functionality to convert to hex.
+file(WRITE "${TMPDIR}/${TEST_FILE}" "${TEST_RESULT}")
+file(READ "${TMPDIR}/${TEST_FILE}" TEST_RESULT HEX)
+file(REMOVE "${TMPDIR}/${TEST_FILE}")
+file(READ "${TEST_DATA_FILE}" TEST_EXPECTED HEX)
+
+if(TEST_ERROR_RESULT)
+ message(SEND_ERROR "${TEST_ERROR_RESULT}")
+endif(TEST_ERROR_RESULT)
+
+if(TEST_ERR_VAR GREATER 0)
+ message(SEND_ERROR "${TEST_ERR_VAR}")
+endif(TEST_ERR_VAR GREATER 0)
+
+if("${TEST_EXPECTED}" STREQUAL "${TEST_RESULT}")
+ message("OK")
+else(_POS_OK)
+ message("EXPECTED")
+ message("${TEST_EXPECTED}")
+ message("GOT")
+ message("Variables")
+ message("RHASH")
+ message("${RHASH}")
+ message(TEST_RESULT)
+ message("${TEST_RESULT}")
+ message("TEST_ERROR_RESULT")
+ message("${TEST_ERROR_RESULT}")
+ message("TEST_ERR_VAR")
+ message("${TEST_ERR_VAR}")
+ message(SEND_ERROR "FAILED!!!")
+endif("${TEST_EXPECTED}" STREQUAL "${TEST_RESULT}")
+
diff --git a/build/tests/test_string1.cmake b/build/tests/test_string1.cmake
new file mode 100644
index 00000000..cfedd86b
--- /dev/null
+++ b/build/tests/test_string1.cmake
@@ -0,0 +1,28 @@
+#test_string1.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+#
+#new_test "test with text string: "
+#TEST_STR="test_string1"
+#TEST_RESULT=$( printf "$TEST_STR" | $rhash -CHMETAGW --sfv - | tail -1 )
+#TEST_EXPECTED="(stdin) F0099E81 B78F440152DBAD00E77017074DC15417 EA8511AE2CA899D68DB423AD751B446C6F958507 R37TT7VDWGK26FUDTFANGUJBFKYDGAV4ARK3EEI 9EDCAE6F50EFE09F0837DA66A8B88C13 5KCRDLRMVCM5NDNUEOWXKG2ENRXZLBIH 01D00FBBA6A0903499385151BF678CDF4294986CF5B76A6A5660AC5834FA429E12861BC5174C7648CA4086B0FCE3F211F80423824E9A9589A20FC43A81D8B752 3D3E1DB92A2030B1287769AAD2190DD69EED5911644EC6E7BB7AEAB5FC701BE3"
+#check "$TEST_RESULT" "$TEST_EXPECTED"
+
+set(TEST_EXPECTED "test.string F0099E81 B78F440152DBAD00E77017074DC15417 EA8511AE2CA899D68DB423AD751B446C6F958507 R37TT7VDWGK26FUDTFANGUJBFKYDGAV4ARK3EEI 9EDCAE6F50EFE09F0837DA66A8B88C13 5KCRDLRMVCM5NDNUEOWXKG2ENRXZLBIH 01D00FBBA6A0903499385151BF678CDF4294986CF5B76A6A5660AC5834FA429E12861BC5174C7648CA4086B0FCE3F211F80423824E9A9589A20FC43A81D8B752 3D3E1DB92A2030B1287769AAD2190DD69EED5911644EC6E7BB7AEAB5FC701BE3")
+include(CMakeTestMacros.cmake)
+SET(TEST_STR "test_string1")
+SET(TEST_FILE "test.string")
+
+FILE(WRITE "${TMPDIR}/${TEST_FILE}" "${TEST_STR}")
+execute_process(
+ COMMAND ${RHASH} -CHMETAGW --sfv "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT
+ RESULT_VARIABLE TEST_ERR_VAR
+ ERROR_VARIABLE TEST_ERROR_RESULT
+)
+checkrun()
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
+string(REGEX MATCH "${TEST_EXPECTED}" _POS_OK ${TEST_RESULT})
+check_POS_OK()
diff --git a/build/tests/test_with_1Kb_data_file.cmake b/build/tests/test_with_1Kb_data_file.cmake
new file mode 100644
index 00000000..60f719a5
--- /dev/null
+++ b/build/tests/test_with_1Kb_data_file.cmake
@@ -0,0 +1,42 @@
+#test_with_1Kb_data_file
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+#
+#new_test "test with 1Kb data file: "
+#TEST_RESULT=$( $rhash --printf "%f %C %M %H %E %G %T %A %W\n" test1K.data 2>/dev/null )
+#TEST_EXPECTED="test1K.data B70B4C26 B2EA9F7FCEA831A4A63B213F41A8855B 5B00669C480D5CFFBDFA8BDBA99561160F2D1B77 5AE257C47E9BE1243EE32AABE408FB6B 890BB3EE5DBE4DA22D6719A14EFD9109B220607E1086C1ABBB51EEAC2B044CBB 4OQY25UN2XHIDQPV5U6BXAZ47INUCYGIBK7LFNI LMAGNHCIBVOP7PP2RPN2TFLBCYHS2G3X D606B7F44BD288759F8869D880D9D4A2F159D739005E72D00F93B814E8C04E657F40C838E4D6F9030A8C9E0308A4E3B450246250243B2F09E09FA5A24761E26B"
+#check "$TEST_RESULT" "$TEST_EXPECTED" .
+# test reversed GOST hashes and verification of them
+#TEST_RESULT=$( $rhash --simple --gost --gost-cryptopro --gost-reverse test1K.data )
+#TEST_EXPECTED="test1K.data bb4c042bacee51bbabc186107e6020b20991fd4ea119672da24dbe5deeb30b89 06cc52d9a7fb5137d01667d1641683620060391722a56222bb4b14ab332ec9d9"
+#check "$TEST_RESULT" "$TEST_EXPECTED" .
+#TEST_RESULT=$( $rhash --simple --gost --gost-cryptopro --gost-reverse test1K.data | $rhash -vc - 2>/dev/null | grep test1K.data )
+#match "$TEST_RESULT" "^test1K.data *OK"
+include(CMakeTestMacros.cmake)
+set(TEST_EXPECTED "test1K.data B70B4C26 B2EA9F7FCEA831A4A63B213F41A8855B 5B00669C480D5CFFBDFA8BDBA99561160F2D1B77 5AE257C47E9BE1243EE32AABE408FB6B 890BB3EE5DBE4DA22D6719A14EFD9109B220607E1086C1ABBB51EEAC2B044CBB 4OQY25UN2XHIDQPV5U6BXAZ47INUCYGIBK7LFNI LMAGNHCIBVOP7PP2RPN2TFLBCYHS2G3X D606B7F44BD288759F8869D880D9D4A2F159D739005E72D00F93B814E8C04E657F40C838E4D6F9030A8C9E0308A4E3B450246250243B2F09E09FA5A24761E26B\n")
+
+#\n
+execute_process(
+COMMAND ${RHASH} --printf "%f %C %M %H %E %G %T %A %W\n" "${TEST_DATA_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checkrun()
+check_test_res_equality()
+# test reversed GOST hashes and verification of them
+set(TEST_EXPECTED "${TEST_DATA_FILE} bb4c042bacee51bbabc186107e6020b20991fd4ea119672da24dbe5deeb30b89 06cc52d9a7fb5137d01667d1641683620060391722a56222bb4b14ab332ec9d9\n")
+SET(TEST_STR "test_string1")
+SET(TEST_FILE "test.results")
+execute_process(COMMAND ${RHASH} --simple --gost --gost-cryptopro --gost-reverse "${TEST_DATA_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT)
+checkrun()
+check_test_res_equality()
+
+#rhash -vc
+FILE(WRITE "${TMPDIR}/${TEST_FILE}" "${TEST_RESULT}")
+execute_process(COMMAND ${RHASH} -vc "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR)
+checkrun()
+string(REGEX MATCH "test1K.data *OK" _POS_OK ${TEST_RESULT})
+check_POS_OK()
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
diff --git a/build/tests/test_with_text_string.cmake b/build/tests/test_with_text_string.cmake
new file mode 100644
index 00000000..78a93b33
--- /dev/null
+++ b/build/tests/test_with_text_string.cmake
@@ -0,0 +1,41 @@
+#test_with_text_string.cmake
+#
+#Parameters:
+#
+# RHASH = rhash executable
+# TDATA = test data file test1K.data
+#
+#do something like this:
+#
+#====
+#new_test "test with text string: "
+#TEST_STR="test_string1"
+#TEST_RESULT=$( printf "$TEST_STR" | $rhash -CHMETAGW --sfv - | tail -1 )
+#TEST_EXPECTED="(stdin) F0099E81 B78F440152DBAD00E77017074DC15417 EA8511AE2CA899D68DB423AD751B446C6F958507 R37TT7VDWGK26FUDTFANGUJBFKYDGAV4ARK3EEI 9EDCAE6F50EFE09F0837DA66A8B88C13 5KCRDLRMVCM5NDNUEOWXKG2ENRXZLBIH 01D00FBBA6A0903499385151BF678CDF4294986CF5B76A6A5660AC5834FA429E12861BC5174C7648CA4086B0FCE3F211F80423824E9A9589A20FC43A81D8B752 3D3E1DB92A2030B1287769AAD2190DD69EED5911644EC6E7BB7AEAB5FC701BE3"
+#check "$TEST_RESULT" "$TEST_EXPECTED"
+#
+#===
+
+message("RHASH - ${RHASH}")
+message("TDATA - ${TDATA}")
+
+set(EXPECTED_RES "(test.file) F0099E81 B78F440152DBAD00E77017074DC15417 EA8511AE2CA899D68DB423AD751B446C6F958507 R37TT7VDWGK26FUDTFANGUJBFKYDGAV4ARK3EEI 9EDCAE6F50EFE09F0837DA66A8B88C13 5KCRDLRMVCM5NDNUEOWXKG2ENRXZLBIH 01D00FBBA6A0903499385151BF678CDF4294986CF5B76A6A5660AC5834FA429E12861BC5174C7648CA4086B0FCE3F211F80423824E9A9589A20FC43A81D8B752 3D3E1DB92A2030B1287769AAD2190DD69EED5911644EC6E7BB7AEAB5FC701BE3")
+file(WRITE test.file "test_string1")
+execute_process(COMMAND ${RHASH} -CHMETAGW --sfv test.file
+ RESULT_VARIABLE RES_VAR
+ OUTPUT_VARIABLE STD_OUT
+ ERROR_VARIABLE ERR_OUT)
+if ((NOT "${RES_VAR}" STREQUAL "0") AND (NOT "${RES_VAR}" STREQUAL ""))
+ message("Result code: ${RES_VAR}")
+ message(FATAL_ERROR "stdout: ${STD_OUT}\rstderr: ${ERR_OUT}")
+endif((NOT "${RES_VAR}" STREQUAL "0") AND (NOT "${RES_VAR}" STREQUAL ""))
+
+file(REMOVE test.file)
+
+string(FIND ${EXPECTED_RES} ${RES_VAR} _LOC)
+
+if (NOT _LOC STRGREATER -1)
+ message(FATAL_ERROR "FAILED ${RES_VAR} ${EXPECTED_RES}")
+endif()
+
+
diff --git a/build/tests/test_wrong_sums_detection.cmake b/build/tests/test_wrong_sums_detection.cmake
new file mode 100644
index 00000000..6cd14f2c
--- /dev/null
+++ b/build/tests/test_wrong_sums_detection.cmake
@@ -0,0 +1,38 @@
+#test_wrong_sums_detection.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+
+#new_test "test wrong sums detection: "
+#printf WRONG | $rhash -p '%c\n%m\n%e\n%h\n%g\n%t\n%a\n%w\n' - > test1K.data.hash
+#TEST_RESULT=$( $rhash -vc test1K.data.hash 2>&1 | grep 'OK' )
+#check "$TEST_RESULT" ""
+#rm test1K.data.hash
+
+
+include(CMakeTestMacros.cmake)
+SET(TEST_STR "a")
+SET(TEST_FILE "test-empty.file")
+
+FILE(WRITE "${TMPDIR}/${TEST_FILE}" "WRONG")
+
+#Note that cmake itself can not do a stdin test
+#and I don't want to use a shell for it since
+#shell samantics are so different.
+execute_process(COMMAND ${RHASH} -p "%c\n%m\n%e\n%h\n%g\n%t\n%a\n%w\n" "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT)
+checkrun()
+file(WRITE "${TMPDIR}/test1K.data.hash" "${TEST_OUTPUT}")
+execute_process(COMMAND ${RHASH} -vc "${TMPDIR}/test1K.data.hash"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT)
+#TEST_ERROR_RESULT may not be empty
+if(TEST_ERR_VAR GREATER 0)
+ report_failed_test()
+endif(TEST_ERR_VAR GREATER 0)
+
+string(REGEX MATCH "OK" _POS_OK ${TEST_RESULT})
+check_POS_OK()
+
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
+file(REMOVE "${TMPDIR}/test1K.data.hash")
diff --git a/build/tests/test_x_b_B_modifiers.cmake b/build/tests/test_x_b_B_modifiers.cmake
new file mode 100644
index 00000000..5c9f0c73
--- /dev/null
+++ b/build/tests/test_x_b_B_modifiers.cmake
@@ -0,0 +1,25 @@
+#test_x_b_B_modifiers.cmake
+#
+#RHASH - Test executable
+#TEST_DATA_FILE - test1K.data
+#TMPDIR - temporary directory for test
+#
+#new_test "test %x, %b, %B modifiers: "
+#TEST_RESULT=$( printf "a" | $rhash -p '%f %s %xC %bc %bM %Bh %bE %bg %xT %xa %bW\n' - )
+#TEST_EXPECTED="(stdin) 1 E8B7BE43 5c334qy BTAXLOOA6G3KQMODTHRGS5ZGME hvfkN/qlp/zhXR3cuerq6jd2Z7g= XXSSZMY54M7EMJC6AX55XVX3EQ 2qwfhhrwprtotsekqapwmsjutqqyog2ditdkk47yjh644yxtctoq 16614B1F68C5C25EAF6136286C9C12932F4F73E87E90A273 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 RLFCMATZFLWG6ENGOIDFGH5X27YN75MUCMKF42LTYRIADUAIPNBNCG6GIVATV37WHJBDSGRZCRNFSGUSEAGVMAMV4U5UPBME7WXCGGQ"
+#check "$TEST_RESULT" "$TEST_EXPECTED"
+
+set(TEST_EXPECTED "test.string 1 E8B7BE43 5c334qy BTAXLOOA6G3KQMODTHRGS5ZGME hvfkN/qlp/zhXR3cuerq6jd2Z7g= XXSSZMY54M7EMJC6AX55XVX3EQ 2qwfhhrwprtotsekqapwmsjutqqyog2ditdkk47yjh644yxtctoq 16614B1F68C5C25EAF6136286C9C12932F4F73E87E90A273 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 RLFCMATZFLWG6ENGOIDFGH5X27YN75MUCMKF42LTYRIADUAIPNBNCG6GIVATV37WHJBDSGRZCRNFSGUSEAGVMAMV4U5UPBME7WXCGGQ")
+
+SET(TEST_STR "test_string1")
+SET(TEST_FILE "test.string")
+include(CMakeTestMacros.cmake)
+
+FILE(WRITE "${TMPDIR}/${TEST_FILE}" "a")
+execute_process(COMMAND ${RHASH} -p "%f %s %xC %bc %bM %Bh %bE %bg %xT %xa %bW\n" "${TMPDIR}/${TEST_FILE}"
+ OUTPUT_VARIABLE TEST_RESULT RESULT_VARIABLE TEST_ERR_VAR ERROR_VARIABLE TEST_ERROR_RESULT)
+FILE(REMOVE "${TMPDIR}/${TEST_FILE}")
+checkrun()
+
+string(REGEX MATCH "${TEST_EXPECTED}" _POS_OK ${TEST_RESULT})
+check_POS_OK()
diff --git a/calc_sums.c b/calc_sums.c
index 1c7c9668..35294791 100644
--- a/calc_sums.c
+++ b/calc_sums.c
@@ -1,824 +1,824 @@
-/* calc_sums.c - crc calculating and printing functions */
-
-#include "platform.h" /* unlink() on unix */
-#include
-#include
-#include /* free() */
-#include
-#include
-#ifdef _WIN32
-# include /* _O_BINARY */
-# include
-#endif
-
-#include "calc_sums.h"
-#include "common_func.h"
-#include "hash_print.h"
-#include "output.h"
-#include "parse_cmdline.h"
-#include "rhash_main.h"
-#include "win_utils.h"
-#include "librhash/rhash.h"
-#include "librhash/rhash_torrent.h"
-
-/**
- * Initialize BTIH hash function. Unlike other algorithms BTIH
- * requires more data for correct computation.
- *
- * @param info the file data
- */
-static void init_btih_data(struct file_info *info)
-{
- assert((info->rctx->hash_id & RHASH_BTIH) != 0);
-
- rhash_torrent_add_file(info->rctx, file_info_get_utf8_print_path(info), info->size);
- rhash_torrent_set_program_name(info->rctx, get_bt_program_name());
-
- if (opt.flags & OPT_BT_PRIVATE) {
- rhash_torrent_set_options(info->rctx, RHASH_TORRENT_OPT_PRIVATE);
- }
-
- if (opt.bt_announce) {
- size_t i;
- for (i = 0; i < opt.bt_announce->size; i++) {
- rhash_torrent_add_announce(info->rctx, (const char*)opt.bt_announce->array[i]);
- }
- }
-
- if (opt.bt_piece_length) {
- rhash_torrent_set_piece_length(info->rctx, opt.bt_piece_length);
- }
- else if (opt.bt_batch_file && rhash_data.batch_size) {
- rhash_torrent_set_batch_size(info->rctx, rhash_data.batch_size);
- }
-}
-
-/**
- * (Re)-initialize RHash context, to calculate hash sums.
- *
- * @param info the file data
- */
-static void re_init_rhash_context(struct file_info *info)
-{
- if (rhash_data.rctx != 0) {
- if (opt.mode & (MODE_CHECK | MODE_CHECK_EMBEDDED)) {
- /* a set of hash sums can change from file to file */
- rhash_free(rhash_data.rctx);
- rhash_data.rctx = 0;
- } else {
- info->rctx = rhash_data.rctx;
-
- if (opt.bt_batch_file) {
- /* add another file to the torrent batch */
- rhash_torrent_add_file(info->rctx, file_info_get_utf8_print_path(info), info->size);
- return;
- } else {
- rhash_reset(rhash_data.rctx);
- }
- }
- }
-
- if (rhash_data.rctx == 0) {
- rhash_data.rctx = rhash_init(info->sums_flags);
- info->rctx = rhash_data.rctx;
- }
-
- if (info->sums_flags & RHASH_BTIH) {
- /* re-initialize BitTorrent data */
- init_btih_data(info);
- }
-}
-
-/**
- * Calculate hash sums simultaneously, according to the info->sums_flags.
- * Calculated hashes are stored in info->rctx.
- *
- * @param info file data. The info->full_path can be "-" to denote stdin
- * @return 0 on success, -1 on fail with error code stored in errno
- */
-static int calc_sums(struct file_info *info)
-{
- FILE* fd = 0;
- int res;
-
- assert(info->file);
- if (FILE_ISSTDIN(info->file)) {
- fd = stdin;
-#ifdef _WIN32
- /* using 0 instead of _fileno(stdin). _fileno() is undefined under 'gcc -ansi' */
- if (setmode(0, _O_BINARY) < 0)
- return -1;
-#endif
- } else {
- if ((opt.mode & (MODE_CHECK | MODE_CHECK_EMBEDDED)) && FILE_ISDIR(info->file)) {
- errno = EISDIR;
- return -1;
- }
-
- info->size = info->file->size; /* total size, in bytes */
-
- if (!info->sums_flags)
- return 0;
-
- if (!FILE_ISDATA(info->file)) {
- fd = file_fopen(info->file, FOpenRead | FOpenBin);
- /* quietly skip files exclusively opened by another process */
- if (!fd)
- return -1;
- }
- }
-
- re_init_rhash_context(info);
- /* store initial msg_size, for correct calculation of percents */
- info->msg_offset = info->rctx->msg_size;
-
- /* read and hash file content */
- if (FILE_ISDATA(info->file))
- res = rhash_update(info->rctx, info->file->data, info->file->size);
- else {
- if (percents_output->update != 0) {
- rhash_set_callback(info->rctx, (rhash_callback_t)percents_output->update, info);
- }
- res = rhash_file_update(info->rctx, fd);
- }
- if (res != -1 && !opt.bt_batch_file)
- rhash_final(info->rctx, 0); /* finalize hashing */
-
- /* store really processed data size */
- info->size = info->rctx->msg_size - info->msg_offset;
- rhash_data.total_size += info->size;
-
- if (fd && !FILE_ISSTDIN(info->file))
- fclose(fd);
- return res;
-}
-
-/**
- * Free memory allocated by given file_info structure.
- *
- * @param info pointer the structure to de-initialize
- */
-void file_info_destroy(struct file_info* info)
-{
- free(info->utf8_print_path);
- free(info->allocated_ptr);
-}
-
-/**
- * Store print_path in a file_info struct, replacing if needed
- * system path separators with specified by user command line option.
- *
- * @param info pointer to the the file_info structure to change
- * @param print_path the print path to store
- */
-static void file_info_set_print_path(struct file_info* info, const char* print_path)
-{
- char *p;
- char wrong_sep;
-
- /* check if path separator was specified by command line options */
- if (opt.path_separator) {
- wrong_sep = (opt.path_separator == '/' ? '\\' : '/');
- if ((p = (char*)strchr(print_path, wrong_sep)) != NULL) {
- info->allocated_ptr = rsh_strdup(print_path);
- info->print_path = info->allocated_ptr;
- p = info->allocated_ptr + (p - print_path);
-
- /* replace wrong_sep in the print_path with separator defined by options */
- for (; *p; p++) {
- if (*p == wrong_sep)
- *p = opt.path_separator;
- }
- return;
- }
- }
-
- /* if path was not replaces, than just store the value */
- info->print_path = print_path;
-}
-
-/**
- * Return utf8 version of print_path.
- *
- * @param info file information
- * @return utf8 string on success, NULL if couldn't convert.
- */
-const char* file_info_get_utf8_print_path(struct file_info* info)
-{
- if (info->utf8_print_path == NULL) {
- if (is_utf8())
- return info->print_path;
- info->utf8_print_path = to_utf8(info->print_path);
- }
- return info->utf8_print_path;
-}
-
-/* functions to calculate and print file sums */
-
-/**
- * Search for a crc32 hash sum in the given file name.
- *
- * @param filepath the path to the file.
- * @param crc32 pointer to integer to receive parsed hash sum.
- * @return non zero if crc32 was found, zero otherwise.
- */
-static int find_embedded_crc32(const char* filepath, unsigned* crc32)
-{
- const char* e = filepath + strlen(filepath) - 10;
- unsigned char raw[4];
-
- /* search for the sum enclosed in brackets */
- for (; e >= filepath && !IS_PATH_SEPARATOR(*e); e--) {
- if ((*e == '[' && e[9] == ']') || (*e == '(' && e[9] == ')')) {
- const char *p = e + 8;
- for (; p > e && IS_HEX(*p); p--);
- if (p == e) {
- rhash_hex_to_byte(e + 1, raw, 8);
- *crc32 = ((unsigned)raw[0] << 24) | ((unsigned)raw[1] << 16) |
- ((unsigned)raw[2] << 8) | (unsigned)raw[3];
- return 1;
- }
- e -= 9;
- }
- }
- return 0;
-}
-
-/**
- * Rename given file inserting its crc32 sum enclosed into square braces
- * and placing it right before the file extension.
- *
- * @param info pointer to the data of the file to rename.
- * @return 0 on success, -1 on fail with error code in errno
- */
-int rename_file_by_embeding_crc32(struct file_info *info)
-{
- size_t len = strlen(info->full_path);
- const char* p = info->full_path + len;
- const char* c = p - 1;
- char* new_path;
- char* insertion_point;
- unsigned crc32;
- assert((info->rctx->hash_id & RHASH_CRC32) != 0);
-
- /* check if the filename contains a CRC32 sum */
- if (find_embedded_crc32(info->print_path, &crc32)) {
- /* compare with calculated CRC32 */
- if (crc32 != get_crc32(info->rctx)) {
- char crc32_str[9];
- rhash_print(crc32_str, info->rctx, RHASH_CRC32, RHPR_UPPERCASE);
- /* TRANSLATORS: sample filename with embedded CRC32: file_[A1B2C3D4].mkv */
- log_warning(_("wrong embedded CRC32, should be %s\n"), crc32_str);
- } else return 0;
- }
-
- /* find file extension (as the place to insert the hash sum) */
- for (; c >= info->full_path && !IS_PATH_SEPARATOR(*c); c--) {
- if (*c == '.') {
- p = c;
- break;
- }
- }
-
- /* now p is the point to insert delimiter + hash string in brackets */
- new_path = (char*)rsh_malloc(len + 12);
- insertion_point = new_path + (p - info->full_path);
- memcpy(new_path, info->full_path, p - info->full_path);
- if (opt.embed_crc_delimiter && *opt.embed_crc_delimiter)
- *(insertion_point++) = *opt.embed_crc_delimiter;
- rhash_print(insertion_point+1, info->rctx, RHASH_CRC32, RHPR_UPPERCASE);
- insertion_point[0] = '[';
- insertion_point[9] = ']'; /* ']' overrides '\0' inserted by rhash_print_sum() */
- strcpy(insertion_point + 10, p); /* append file extension */
-
- /* rename the file */
- if (rename(info->full_path, new_path) < 0) {
- log_error(_("can't move %s to %s: %s\n"), info->full_path, new_path,
- strerror(errno));
- free(new_path);
- return -1;
- }
-
- /* change file name in the file info structure */
- if (info->print_path >= info->full_path && info->print_path < p) {
- file_info_set_print_path(info, new_path + len - strlen(info->print_path));
- } else {
- file_info_set_print_path(info, new_path);
- }
-
- free(info->full_path);
- info->full_path = new_path;
- return 0;
-}
-
-/**
- * Save torrent file to the given path.
- *
- * @param torrent_file the path to save torrent file to
- * @param rctx the context containing torrent data
- * @return 0 on success, -1 on fail with error code in errno
- */
-int save_torrent_to(file_t* torrent_file, rhash_context* rctx)
-{
- FILE* fd;
- int res = 0;
-
- const rhash_str* text = rhash_torrent_generate_content(rctx);
- if (!text) {
- errno = ENOMEM;
- log_file_t_error(torrent_file);
- return -1;
- }
-
- /* make backup copy of the existing torrent file */
- file_move_to_bak(torrent_file);
-
- /* write the torrent file */
- fd = file_fopen(torrent_file, FOpenWrite | FOpenBin);
- if (fd && text->length == fwrite(text->str, 1, text->length, fd) &&
- !ferror(fd) && !fflush(fd))
- {
- log_msg(_("%s saved\n"), file_cpath(torrent_file));
- } else {
- log_file_t_error(torrent_file);
- res = -1;
- }
- if (fd)
- fclose(fd);
- return res;
-}
-
-/**
- * Save torrent file.
- *
- * @param info information about the hashed file
- */
-static void save_torrent(struct file_info* info)
-{
- /* append .torrent extension to the file path */
- file_t torrent_file;
- file_path_append(&torrent_file, info->file, ".torrent");
- save_torrent_to(&torrent_file, info->rctx);
- file_cleanup(&torrent_file);
-}
-
-/**
- * Calculate and print file hash sums using printf format.
- *
- * @param out a stream to print to
- * @param file the file to calculate sums for
- * @param print_path the path to print
- * @return 0 on success, -1 on fail
- */
-int calculate_and_print_sums(FILE* out, file_t* file, const char *print_path)
-{
- struct file_info info;
- timedelta_t timer;
- int res = 0;
-
- memset(&info, 0, sizeof(info));
- info.file = file;
- info.full_path = rsh_strdup(file->path);
- file_info_set_print_path(&info, print_path);
- info.size = file->size; /* total size, in bytes */
- info.sums_flags = opt.sum_flags;
-
- /* skip directories */
- if (FILE_ISDIR(file))
- return 0;
-
- /* initialize percents output */
- init_percents(&info);
- rsh_timer_start(&timer);
-
- if (info.sums_flags) {
- /* calculate sums */
- if (calc_sums(&info) < 0) {
- /* print i/o error */
- log_file_t_error(file);
- res = -1;
- }
- if (rhash_data.interrupted) {
- report_interrupted();
- return 0;
- }
- }
-
- info.time = rsh_timer_stop(&timer);
- finish_percents(&info, res);
-
- if (opt.flags & OPT_EMBED_CRC) {
- /* rename the file */
- rename_file_by_embeding_crc32(&info);
- }
-
- if ((opt.mode & MODE_TORRENT) && !opt.bt_batch_file) {
- save_torrent(&info);
- }
-
- if ((opt.mode & MODE_UPDATE) && opt.fmt == FMT_SFV) {
- /* updating SFV file: print SFV header line */
- print_sfv_header_line(rhash_data.upd_fd, file, 0);
- if (opt.flags & OPT_VERBOSE) {
- print_sfv_header_line(rhash_data.log, file, 0);
- fflush(rhash_data.log);
- }
- file_cleanup(file);
- }
-
- if (rhash_data.print_list && res >= 0) {
- if (!opt.bt_batch_file) {
- print_line(out, rhash_data.print_list, &info);
-
- /* print calculated line to stderr or log-file if verbose */
- if ((opt.mode & MODE_UPDATE) && (opt.flags & OPT_VERBOSE)) {
- print_line(rhash_data.log, rhash_data.print_list, &info);
- }
- }
-
- if ((opt.flags & OPT_SPEED) && info.sums_flags) {
- print_file_time_stats(&info);
- }
- }
- free(info.full_path);
- file_info_destroy(&info);
- return res;
-}
-
-/**
- * Verify hash sums of the file.
- *
- * @param info structure file path to process
- * @return zero on success, -1 on file error, -2 if hash sums are different
- */
-static int verify_sums(struct file_info *info)
-{
- timedelta_t timer;
- int res = 0;
- errno = 0;
-
- /* initialize percents output */
- init_percents(info);
- rsh_timer_start(&timer);
-
- if (calc_sums(info) < 0) {
- finish_percents(info, -1);
- return -1;
- }
- info->time = rsh_timer_stop(&timer);
-
- if (rhash_data.interrupted) {
- report_interrupted();
- return 0;
- }
-
- if ((opt.flags & OPT_EMBED_CRC) &&
- find_embedded_crc32(info->print_path, &info->hc.embedded_crc32)) {
- info->hc.flags |= HC_HAS_EMBCRC32;
- assert(info->hc.hash_mask & RHASH_CRC32);
- }
-
- if (!hash_check_verify(&info->hc, info->rctx)) {
- res = -2;
- }
-
- finish_percents(info, res);
-
- if ((opt.flags & OPT_SPEED) && info->sums_flags) {
- print_file_time_stats(info);
- }
- return res;
-}
-
-/**
- * Check hash sums in a hash file.
- * Lines beginning with ';' and '#' are ignored.
- *
- * @param hash_file_path - the path of the file with hash sums to verify.
- * @param chdir - true if function should emulate chdir to directory of filepath before checking it.
- * @return zero on success, -1 on fail
- */
-int check_hash_file(file_t* file, int chdir)
-{
- FILE *fd;
- char buf[4096];
- size_t pos;
- const char *ralign;
- timedelta_t timer;
- struct file_info info;
- const char* hash_file_path = file->path;
- int res = 0, line_num = 0;
- double time;
-
- /* process --check-embedded option */
- if (opt.mode & MODE_CHECK_EMBEDDED) {
- unsigned crc32;
- if (find_embedded_crc32(hash_file_path, &crc32)) {
- /* initialize file_info structure */
- memset(&info, 0, sizeof(info));
- info.full_path = rsh_strdup(hash_file_path);
- info.file = file;
- file_info_set_print_path(&info, info.full_path);
- info.sums_flags = info.hc.hash_mask = RHASH_CRC32;
- info.hc.flags = HC_HAS_EMBCRC32;
- info.hc.embedded_crc32 = crc32;
-
- res = verify_sums(&info);
- fflush(rhash_data.out);
- if (!rhash_data.interrupted) {
- if (res == 0)
- rhash_data.ok++;
- else if (res == -1 && errno == ENOENT)
- rhash_data.miss++;
- rhash_data.processed++;
- }
-
- free(info.full_path);
- file_info_destroy(&info);
- } else {
- log_warning(_("file name doesn't contain a CRC32: %s\n"), hash_file_path);
- return -1;
- }
- return 0;
- }
-
- /* initialize statistics */
- rhash_data.processed = rhash_data.ok = rhash_data.miss = 0;
- rhash_data.total_size = 0;
-
- if (FILE_ISSTDIN(file)) {
- fd = stdin;
- } else if ( !(fd = file_fopen(file, FOpenRead | FOpenBin) )) {
- log_file_error(hash_file_path);
- return -1;
- }
-
- pos = strlen(hash_file_path)+16;
- ralign = str_set(buf, '-', (pos < 80 ? 80 - (int)pos : 2));
- rsh_fprintf(rhash_data.out, _("\n--( Verifying %s )%s\n"), hash_file_path, ralign);
- fflush(rhash_data.out);
- rsh_timer_start(&timer);
-
- /* mark the directory part of the path, by setting the pos index */
- if (chdir) {
- pos = strlen(hash_file_path);
- for (; pos > 0 && !IS_PATH_SEPARATOR(hash_file_path[pos]); pos--);
- if (IS_PATH_SEPARATOR(hash_file_path[pos]))
- pos++;
- } else pos = 0;
-
- /* read crc file line by line */
- for (line_num = 0; fgets(buf, sizeof(buf), fd); line_num++) {
- char* line = buf;
- char* path_without_ext = NULL;
-
- /* skip unicode BOM */
- if (line_num == 0 && buf[0] == (char)0xEF && buf[1] == (char)0xBB && buf[2] == (char)0xBF)
- line += 3;
-
- if (*line == 0)
- continue; /* skip empty lines */
-
- if (is_binary_string(line)) {
- log_error(_("file is binary: %s\n"), hash_file_path);
- if (fd != stdin)
- fclose(fd);
- return -1;
- }
-
- /* skip comments and empty lines */
- if (IS_COMMENT(*line) || *line == '\r' || *line == '\n')
- continue;
-
- memset(&info, 0, sizeof(info));
-
- if (!hash_check_parse_line(line, &info.hc, !feof(fd)))
- continue;
- if (info.hc.hash_mask == 0)
- continue;
-
- info.print_path = info.hc.file_path;
- info.sums_flags = info.hc.hash_mask;
-
- /* see if crc file contains a hash sum without a filename */
- if (info.print_path == NULL) {
- char* point;
- path_without_ext = rsh_strdup(hash_file_path);
- point = strrchr(path_without_ext, '.');
-
- if (point) {
- *point = '\0';
- file_info_set_print_path(&info, path_without_ext);
- }
- }
-
- if (info.print_path != NULL) {
- file_t file_to_check;
- int is_absolute = IS_PATH_SEPARATOR(info.print_path[0]);
- IF_WINDOWS(is_absolute = is_absolute || (info.print_path[0] && info.print_path[1] == ':'));
-
- /* if filename shall be prepended by a directory path */
- if (pos && !is_absolute) {
- size_t len = strlen(info.print_path);
- info.full_path = (char*)rsh_malloc(pos + len + 1);
- memcpy(info.full_path, hash_file_path, pos);
- strcpy(info.full_path + pos, info.print_path);
- } else {
- info.full_path = rsh_strdup(info.print_path);
- }
- memset(&file_to_check, 0, sizeof(file_t));
- file_to_check.path = info.full_path;
- file_stat(&file_to_check, 0);
- info.file = &file_to_check;
-
- /* verify hash sums of the file */
- res = verify_sums(&info);
-
- fflush(rhash_data.out);
- file_cleanup(&file_to_check);
- file_info_destroy(&info);
-
- if (rhash_data.interrupted) {
- free(path_without_ext);
- break;
- }
-
- /* update statistics */
- if (res == 0)
- rhash_data.ok++;
- else if (res == -1 && errno == ENOENT)
- rhash_data.miss++;
- rhash_data.processed++;
- }
- free(path_without_ext);
- }
- time = rsh_timer_stop(&timer);
-
- rsh_fprintf(rhash_data.out, "%s\n", str_set(buf, '-', 80));
- print_check_stats();
-
- if (rhash_data.processed != rhash_data.ok)
- rhash_data.error_flag = 1;
-
- if ((opt.flags & OPT_SPEED) && rhash_data.processed > 1)
- print_time_stats(time, rhash_data.total_size, 1);
-
- rhash_data.processed = 0;
- res = ferror(fd); /* check that crc file has been read without errors */
- if (fd != stdin)
- fclose(fd);
- return (res == 0 ? 0 : -1);
-}
-
-/*=========================================================================
- * Benchmark functions
- *=========================================================================*/
-
-/**
- * Hash a repeated message chunk by specified hash function.
- *
- * @param hash_id hash function identifier
- * @param message a message chunk to hash
- * @param msg_size message chunk size
- * @param count number of chunks
- * @param out computed hash
- * @return 1 on success, 0 on error
- */
-static int benchmark_loop(unsigned hash_id, const unsigned char* message, size_t msg_size, int count, unsigned char* out)
-{
- int i;
- struct rhash_context *context = rhash_init(hash_id);
- if (!context)
- return 0;
-
- /* process the repeated message buffer */
- for (i = 0; i < count && !rhash_data.interrupted; i++) {
- rhash_update(context, message, msg_size);
- }
- rhash_final(context, out);
- rhash_free(context);
- return 1;
-}
-
-#if defined(_MSC_VER)
-#define ALIGN_DATA(n) __declspec(align(n))
-#elif defined(__GNUC__)
-#define ALIGN_DATA(n) __attribute__((aligned (n)))
-#else
-#define ALIGN_DATA(n) /* do nothing */
-#endif
-
-/* define read_tsc() if possible */
-#if defined(__i386__) || defined(_M_IX86) || \
- defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
-
-#if defined( _MSC_VER ) /* if MS VC */
-# include
-# pragma intrinsic( __rdtsc )
-# define read_tsc() __rdtsc()
-# define HAVE_TSC
-#elif defined( __GNUC__ ) /* if GCC */
-static uint64_t read_tsc(void) {
- unsigned long lo, hi;
- __asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
- return (((uint64_t)hi) << 32) + lo;
-}
-# define HAVE_TSC
-#endif /* _MSC_VER, __GNUC__ */
-#endif /* x86/amd64 arch */
-
-void run_benchmark(unsigned hash_id, unsigned flags)
-{
- unsigned char ALIGN_DATA(64) message[8192]; /* 8 KiB */
- timedelta_t timer;
- int i, j;
- size_t sz_mb, msg_size;
- double time, total_time = 0;
- const int rounds = 4;
- const char* hash_name;
- unsigned char out[130];
-#ifdef HAVE_TSC
- double cpb = 0;
-#endif /* HAVE_TSC */
-
-#ifdef _WIN32
- set_benchmark_cpu_affinity(); /* set CPU affinity to improve test results */
-#endif
-
- /* set message size for fast and slow hash functions */
- msg_size = 1073741824 / 2;
- if (hash_id & (RHASH_WHIRLPOOL | RHASH_SNEFRU128 | RHASH_SNEFRU256 | RHASH_SHA3_224 | RHASH_SHA3_256 | RHASH_SHA3_384 | RHASH_SHA3_512)) {
- msg_size /= 8;
- } else if (hash_id & (RHASH_GOST94 | RHASH_GOST94_CRYPTOPRO | RHASH_SHA384 | RHASH_SHA512)) {
- msg_size /= 2;
- }
- sz_mb = msg_size / (1 << 20); /* size in MiB */
- hash_name = rhash_get_name(hash_id);
- if (!hash_name)
- hash_name = ""; /* benchmarking several hashes*/
-
- for (i = 0; i < (int)sizeof(message); i++)
- message[i] = i & 0xff;
-
- for (j = 0; j < rounds && !rhash_data.interrupted; j++) {
- rsh_timer_start(&timer);
- benchmark_loop(hash_id, message, sizeof(message), (int)(msg_size / sizeof(message)), out);
-
- time = rsh_timer_stop(&timer);
- total_time += time;
-
- if ((flags & BENCHMARK_RAW) == 0 && !rhash_data.interrupted) {
- rsh_fprintf(rhash_data.out, "%s %u MiB calculated in %.3f sec, %.3f MBps\n", hash_name, (unsigned)sz_mb, time, (double)sz_mb / time);
- fflush(rhash_data.out);
- }
- }
-
-#if defined(HAVE_TSC)
- /* measure the CPU "clocks per byte" speed */
- if ((flags & BENCHMARK_CPB) != 0 && !rhash_data.interrupted) {
- unsigned int c1 = -1, c2 = -1;
- unsigned volatile long long cy0, cy1, cy2;
- int msg_size = 128 * 1024;
-
- /* make 200 tries */
- for (i = 0; i < 200; i++) {
- cy0 = read_tsc();
- benchmark_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out);
- cy1 = read_tsc();
- benchmark_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out);
- benchmark_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out);
- cy2 = read_tsc();
-
- cy2 -= cy1;
- cy1 -= cy0;
- c1 = (unsigned int)(c1 > cy1 ? cy1 : c1);
- c2 = (unsigned int)(c2 > cy2 ? cy2 : c2);
- }
- cpb = ((c2 - c1) + 1) / (double)msg_size;
- }
-#endif /* HAVE_TSC */
-
- if (rhash_data.interrupted) {
- report_interrupted();
- return;
- }
-
- if (flags & BENCHMARK_RAW) {
- /* output result in a "raw" machine-readable format */
- rsh_fprintf(rhash_data.out, "%s\t%u\t%.3f\t%.3f", hash_name, ((unsigned)sz_mb * rounds), total_time, (double)(sz_mb * rounds) / total_time);
-#if defined(HAVE_TSC)
- if (flags & BENCHMARK_CPB) {
- rsh_fprintf(rhash_data.out, "\t%.2f", cpb);
- }
-#endif /* HAVE_TSC */
- rsh_fprintf(rhash_data.out, "\n");
- } else {
- rsh_fprintf(rhash_data.out, "%s %u MiB total in %.3f sec, %.3f MBps", hash_name, ((unsigned)sz_mb * rounds), total_time, (double)(sz_mb * rounds) / total_time);
-#if defined(HAVE_TSC)
- if (flags & BENCHMARK_CPB) {
- rsh_fprintf(rhash_data.out, ", CPB=%.2f", cpb);
- }
-#endif /* HAVE_TSC */
- rsh_fprintf(rhash_data.out, "\n");
- }
-}
+/* calc_sums.c - crc calculating and printing functions */
+
+#include "platform.h" /* unlink() on unix */
+#include
+#include
+#include /* free() */
+#include
+#include
+#ifdef _WIN32
+# include /* _O_BINARY */
+# include
+#endif
+
+#include "calc_sums.h"
+#include "common_func.h"
+#include "hash_print.h"
+#include "output.h"
+#include "parse_cmdline.h"
+#include "rhash_main.h"
+#include "win_utils.h"
+#include "librhash/rhash.h"
+#include "librhash/rhash_torrent.h"
+
+/**
+ * Initialize BTIH hash function. Unlike other algorithms BTIH
+ * requires more data for correct computation.
+ *
+ * @param info the file data
+ */
+static void init_btih_data(struct file_info *info)
+{
+ assert((info->rctx->hash_id & RHASH_BTIH) != 0);
+
+ rhash_torrent_add_file(info->rctx, file_info_get_utf8_print_path(info), info->size);
+ rhash_torrent_set_program_name(info->rctx, get_bt_program_name());
+
+ if (opt.flags & OPT_BT_PRIVATE) {
+ rhash_torrent_set_options(info->rctx, RHASH_TORRENT_OPT_PRIVATE);
+ }
+
+ if (opt.bt_announce) {
+ size_t i;
+ for (i = 0; i < opt.bt_announce->size; i++) {
+ rhash_torrent_add_announce(info->rctx, (const char*)opt.bt_announce->array[i]);
+ }
+ }
+
+ if (opt.bt_piece_length) {
+ rhash_torrent_set_piece_length(info->rctx, opt.bt_piece_length);
+ }
+ else if (opt.bt_batch_file && rhash_data.batch_size) {
+ rhash_torrent_set_batch_size(info->rctx, rhash_data.batch_size);
+ }
+}
+
+/**
+ * (Re)-initialize RHash context, to calculate hash sums.
+ *
+ * @param info the file data
+ */
+static void re_init_rhash_context(struct file_info *info)
+{
+ if (rhash_data.rctx != 0) {
+ if (opt.mode & (MODE_CHECK | MODE_CHECK_EMBEDDED)) {
+ /* a set of hash sums can change from file to file */
+ rhash_free(rhash_data.rctx);
+ rhash_data.rctx = 0;
+ } else {
+ info->rctx = rhash_data.rctx;
+
+ if (opt.bt_batch_file) {
+ /* add another file to the torrent batch */
+ rhash_torrent_add_file(info->rctx, file_info_get_utf8_print_path(info), info->size);
+ return;
+ } else {
+ rhash_reset(rhash_data.rctx);
+ }
+ }
+ }
+
+ if (rhash_data.rctx == 0) {
+ rhash_data.rctx = rhash_init(info->sums_flags);
+ info->rctx = rhash_data.rctx;
+ }
+
+ if (info->sums_flags & RHASH_BTIH) {
+ /* re-initialize BitTorrent data */
+ init_btih_data(info);
+ }
+}
+
+/**
+ * Calculate hash sums simultaneously, according to the info->sums_flags.
+ * Calculated hashes are stored in info->rctx.
+ *
+ * @param info file data. The info->full_path can be "-" to denote stdin
+ * @return 0 on success, -1 on fail with error code stored in errno
+ */
+static int calc_sums(struct file_info *info)
+{
+ FILE* fd = 0;
+ int res;
+
+ assert(info->file);
+ if (FILE_ISSTDIN(info->file)) {
+ fd = stdin;
+#ifdef _WIN32
+ /* using 0 instead of _fileno(stdin). _fileno() is undefined under 'gcc -ansi' */
+ if (setmode(0, _O_BINARY) < 0)
+ return -1;
+#endif
+ } else {
+ if ((opt.mode & (MODE_CHECK | MODE_CHECK_EMBEDDED)) && FILE_ISDIR(info->file)) {
+ errno = EISDIR;
+ return -1;
+ }
+
+ info->size = info->file->size; /* total size, in bytes */
+
+ if (!info->sums_flags)
+ return 0;
+
+ if (!FILE_ISDATA(info->file)) {
+ fd = file_fopen(info->file, FOpenRead | FOpenBin);
+ /* quietly skip files exclusively opened by another process */
+ if (!fd)
+ return -1;
+ }
+ }
+
+ re_init_rhash_context(info);
+ /* store initial msg_size, for correct calculation of percents */
+ info->msg_offset = info->rctx->msg_size;
+
+ /* read and hash file content */
+ if (FILE_ISDATA(info->file))
+ res = rhash_update(info->rctx, info->file->data, info->file->size);
+ else {
+ if (percents_output->update != 0) {
+ rhash_set_callback(info->rctx, (rhash_callback_t)percents_output->update, info);
+ }
+ res = rhash_file_update(info->rctx, fd);
+ }
+ if (res != -1 && !opt.bt_batch_file)
+ rhash_final(info->rctx, 0); /* finalize hashing */
+
+ /* store really processed data size */
+ info->size = info->rctx->msg_size - info->msg_offset;
+ rhash_data.total_size += info->size;
+
+ if (fd && !FILE_ISSTDIN(info->file))
+ fclose(fd);
+ return res;
+}
+
+/**
+ * Free memory allocated by given file_info structure.
+ *
+ * @param info pointer the structure to de-initialize
+ */
+void file_info_destroy(struct file_info* info)
+{
+ free(info->utf8_print_path);
+ free(info->allocated_ptr);
+}
+
+/**
+ * Store print_path in a file_info struct, replacing if needed
+ * system path separators with specified by user command line option.
+ *
+ * @param info pointer to the the file_info structure to change
+ * @param print_path the print path to store
+ */
+static void file_info_set_print_path(struct file_info* info, const char* print_path)
+{
+ char *p;
+ char wrong_sep;
+
+ /* check if path separator was specified by command line options */
+ if (opt.path_separator) {
+ wrong_sep = (opt.path_separator == '/' ? '\\' : '/');
+ if ((p = (char*)strchr(print_path, wrong_sep)) != NULL) {
+ info->allocated_ptr = rsh_strdup(print_path);
+ info->print_path = info->allocated_ptr;
+ p = info->allocated_ptr + (p - print_path);
+
+ /* replace wrong_sep in the print_path with separator defined by options */
+ for (; *p; p++) {
+ if (*p == wrong_sep)
+ *p = opt.path_separator;
+ }
+ return;
+ }
+ }
+
+ /* if path was not replaces, than just store the value */
+ info->print_path = print_path;
+}
+
+/**
+ * Return utf8 version of print_path.
+ *
+ * @param info file information
+ * @return utf8 string on success, NULL if couldn't convert.
+ */
+const char* file_info_get_utf8_print_path(struct file_info* info)
+{
+ if (info->utf8_print_path == NULL) {
+ if (is_utf8())
+ return info->print_path;
+ info->utf8_print_path = to_utf8(info->print_path);
+ }
+ return info->utf8_print_path;
+}
+
+/* functions to calculate and print file sums */
+
+/**
+ * Search for a crc32 hash sum in the given file name.
+ *
+ * @param filepath the path to the file.
+ * @param crc32 pointer to integer to receive parsed hash sum.
+ * @return non zero if crc32 was found, zero otherwise.
+ */
+static int find_embedded_crc32(const char* filepath, unsigned* crc32)
+{
+ const char* e = filepath + strlen(filepath) - 10;
+ unsigned char raw[4];
+
+ /* search for the sum enclosed in brackets */
+ for (; e >= filepath && !IS_PATH_SEPARATOR(*e); e--) {
+ if ((*e == '[' && e[9] == ']') || (*e == '(' && e[9] == ')')) {
+ const char *p = e + 8;
+ for (; p > e && IS_HEX(*p); p--);
+ if (p == e) {
+ rhash_hex_to_byte(e + 1, raw, 8);
+ *crc32 = ((unsigned)raw[0] << 24) | ((unsigned)raw[1] << 16) |
+ ((unsigned)raw[2] << 8) | (unsigned)raw[3];
+ return 1;
+ }
+ e -= 9;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Rename given file inserting its crc32 sum enclosed into square braces
+ * and placing it right before the file extension.
+ *
+ * @param info pointer to the data of the file to rename.
+ * @return 0 on success, -1 on fail with error code in errno
+ */
+int rename_file_by_embeding_crc32(struct file_info *info)
+{
+ size_t len = strlen(info->full_path);
+ const char* p = info->full_path + len;
+ const char* c = p - 1;
+ char* new_path;
+ char* insertion_point;
+ unsigned crc32;
+ assert((info->rctx->hash_id & RHASH_CRC32) != 0);
+
+ /* check if the filename contains a CRC32 sum */
+ if (find_embedded_crc32(info->print_path, &crc32)) {
+ /* compare with calculated CRC32 */
+ if (crc32 != get_crc32(info->rctx)) {
+ char crc32_str[9];
+ rhash_print(crc32_str, info->rctx, RHASH_CRC32, RHPR_UPPERCASE);
+ /* TRANSLATORS: sample filename with embedded CRC32: file_[A1B2C3D4].mkv */
+ log_warning(_("wrong embedded CRC32, should be %s\n"), crc32_str);
+ } else return 0;
+ }
+
+ /* find file extension (as the place to insert the hash sum) */
+ for (; c >= info->full_path && !IS_PATH_SEPARATOR(*c); c--) {
+ if (*c == '.') {
+ p = c;
+ break;
+ }
+ }
+
+ /* now p is the point to insert delimiter + hash string in brackets */
+ new_path = (char*)rsh_malloc(len + 12);
+ insertion_point = new_path + (p - info->full_path);
+ memcpy(new_path, info->full_path, p - info->full_path);
+ if (opt.embed_crc_delimiter && *opt.embed_crc_delimiter)
+ *(insertion_point++) = *opt.embed_crc_delimiter;
+ rhash_print(insertion_point+1, info->rctx, RHASH_CRC32, RHPR_UPPERCASE);
+ insertion_point[0] = '[';
+ insertion_point[9] = ']'; /* ']' overrides '\0' inserted by rhash_print_sum() */
+ strcpy(insertion_point + 10, p); /* append file extension */
+
+ /* rename the file */
+ if (rename(info->full_path, new_path) < 0) {
+ log_error(_("can't move %s to %s: %s\n"), info->full_path, new_path,
+ strerror(errno));
+ free(new_path);
+ return -1;
+ }
+
+ /* change file name in the file info structure */
+ if (info->print_path >= info->full_path && info->print_path < p) {
+ file_info_set_print_path(info, new_path + len - strlen(info->print_path));
+ } else {
+ file_info_set_print_path(info, new_path);
+ }
+
+ free(info->full_path);
+ info->full_path = new_path;
+ return 0;
+}
+
+/**
+ * Save torrent file to the given path.
+ *
+ * @param torrent_file the path to save torrent file to
+ * @param rctx the context containing torrent data
+ * @return 0 on success, -1 on fail with error code in errno
+ */
+int save_torrent_to(file_t* torrent_file, rhash_context* rctx)
+{
+ FILE* fd;
+ int res = 0;
+
+ const rhash_str* text = rhash_torrent_generate_content(rctx);
+ if (!text) {
+ errno = ENOMEM;
+ log_file_t_error(torrent_file);
+ return -1;
+ }
+
+ /* make backup copy of the existing torrent file */
+ file_move_to_bak(torrent_file);
+
+ /* write the torrent file */
+ fd = file_fopen(torrent_file, FOpenWrite | FOpenBin);
+ if (fd && text->length == fwrite(text->str, 1, text->length, fd) &&
+ !ferror(fd) && !fflush(fd))
+ {
+ log_msg(_("%s saved\n"), file_cpath(torrent_file));
+ } else {
+ log_file_t_error(torrent_file);
+ res = -1;
+ }
+ if (fd)
+ fclose(fd);
+ return res;
+}
+
+/**
+ * Save torrent file.
+ *
+ * @param info information about the hashed file
+ */
+static void save_torrent(struct file_info* info)
+{
+ /* append .torrent extension to the file path */
+ file_t torrent_file;
+ file_path_append(&torrent_file, info->file, ".torrent");
+ save_torrent_to(&torrent_file, info->rctx);
+ file_cleanup(&torrent_file);
+}
+
+/**
+ * Calculate and print file hash sums using printf format.
+ *
+ * @param out a stream to print to
+ * @param file the file to calculate sums for
+ * @param print_path the path to print
+ * @return 0 on success, -1 on fail
+ */
+int calculate_and_print_sums(FILE* out, file_t* file, const char *print_path)
+{
+ struct file_info info;
+ timedelta_t timer;
+ int res = 0;
+
+ memset(&info, 0, sizeof(info));
+ info.file = file;
+ info.full_path = rsh_strdup(file->path);
+ file_info_set_print_path(&info, print_path);
+ info.size = file->size; /* total size, in bytes */
+ info.sums_flags = opt.sum_flags;
+
+ /* skip directories */
+ if (FILE_ISDIR(file))
+ return 0;
+
+ /* initialize percents output */
+ init_percents(&info);
+ rsh_timer_start(&timer);
+
+ if (info.sums_flags) {
+ /* calculate sums */
+ if (calc_sums(&info) < 0) {
+ /* print i/o error */
+ log_file_t_error(file);
+ res = -1;
+ }
+ if (rhash_data.interrupted) {
+ report_interrupted();
+ return 0;
+ }
+ }
+
+ info.time = rsh_timer_stop(&timer);
+ finish_percents(&info, res);
+
+ if (opt.flags & OPT_EMBED_CRC) {
+ /* rename the file */
+ rename_file_by_embeding_crc32(&info);
+ }
+
+ if ((opt.mode & MODE_TORRENT) && !opt.bt_batch_file) {
+ save_torrent(&info);
+ }
+
+ if ((opt.mode & MODE_UPDATE) && opt.fmt == FMT_SFV) {
+ /* updating SFV file: print SFV header line */
+ print_sfv_header_line(rhash_data.upd_fd, file, 0);
+ if (opt.flags & OPT_VERBOSE) {
+ print_sfv_header_line(rhash_data.log, file, 0);
+ fflush(rhash_data.log);
+ }
+ file_cleanup(file);
+ }
+
+ if (rhash_data.print_list && res >= 0) {
+ if (!opt.bt_batch_file) {
+ print_line(out, rhash_data.print_list, &info);
+
+ /* print calculated line to stderr or log-file if verbose */
+ if ((opt.mode & MODE_UPDATE) && (opt.flags & OPT_VERBOSE)) {
+ print_line(rhash_data.log, rhash_data.print_list, &info);
+ }
+ }
+
+ if ((opt.flags & OPT_SPEED) && info.sums_flags) {
+ print_file_time_stats(&info);
+ }
+ }
+ free(info.full_path);
+ file_info_destroy(&info);
+ return res;
+}
+
+/**
+ * Verify hash sums of the file.
+ *
+ * @param info structure file path to process
+ * @return zero on success, -1 on file error, -2 if hash sums are different
+ */
+static int verify_sums(struct file_info *info)
+{
+ timedelta_t timer;
+ int res = 0;
+ errno = 0;
+
+ /* initialize percents output */
+ init_percents(info);
+ rsh_timer_start(&timer);
+
+ if (calc_sums(info) < 0) {
+ finish_percents(info, -1);
+ return -1;
+ }
+ info->time = rsh_timer_stop(&timer);
+
+ if (rhash_data.interrupted) {
+ report_interrupted();
+ return 0;
+ }
+
+ if ((opt.flags & OPT_EMBED_CRC) &&
+ find_embedded_crc32(info->print_path, &info->hc.embedded_crc32)) {
+ info->hc.flags |= HC_HAS_EMBCRC32;
+ assert(info->hc.hash_mask & RHASH_CRC32);
+ }
+
+ if (!hash_check_verify(&info->hc, info->rctx)) {
+ res = -2;
+ }
+
+ finish_percents(info, res);
+
+ if ((opt.flags & OPT_SPEED) && info->sums_flags) {
+ print_file_time_stats(info);
+ }
+ return res;
+}
+
+/**
+ * Check hash sums in a hash file.
+ * Lines beginning with ';' and '#' are ignored.
+ *
+ * @param hash_file_path - the path of the file with hash sums to verify.
+ * @param chdir - true if function should emulate chdir to directory of filepath before checking it.
+ * @return zero on success, -1 on fail
+ */
+int check_hash_file(file_t* file, int chdir)
+{
+ FILE *fd;
+ char buf[4096];
+ size_t pos;
+ const char *ralign;
+ timedelta_t timer;
+ struct file_info info;
+ const char* hash_file_path = file->path;
+ int res = 0, line_num = 0;
+ double time;
+
+ /* process --check-embedded option */
+ if (opt.mode & MODE_CHECK_EMBEDDED) {
+ unsigned crc32;
+ if (find_embedded_crc32(hash_file_path, &crc32)) {
+ /* initialize file_info structure */
+ memset(&info, 0, sizeof(info));
+ info.full_path = rsh_strdup(hash_file_path);
+ info.file = file;
+ file_info_set_print_path(&info, info.full_path);
+ info.sums_flags = info.hc.hash_mask = RHASH_CRC32;
+ info.hc.flags = HC_HAS_EMBCRC32;
+ info.hc.embedded_crc32 = crc32;
+
+ res = verify_sums(&info);
+ fflush(rhash_data.out);
+ if (!rhash_data.interrupted) {
+ if (res == 0)
+ rhash_data.ok++;
+ else if (res == -1 && errno == ENOENT)
+ rhash_data.miss++;
+ rhash_data.processed++;
+ }
+
+ free(info.full_path);
+ file_info_destroy(&info);
+ } else {
+ log_warning(_("file name doesn't contain a CRC32: %s\n"), hash_file_path);
+ return -1;
+ }
+ return 0;
+ }
+
+ /* initialize statistics */
+ rhash_data.processed = rhash_data.ok = rhash_data.miss = 0;
+ rhash_data.total_size = 0;
+
+ if (FILE_ISSTDIN(file)) {
+ fd = stdin;
+ } else if ( !(fd = file_fopen(file, FOpenRead | FOpenBin) )) {
+ log_file_error(hash_file_path);
+ return -1;
+ }
+
+ pos = strlen(hash_file_path)+16;
+ ralign = str_set(buf, '-', (pos < 80 ? 80 - (int)pos : 2));
+ rsh_fprintf(rhash_data.out, _("\n--( Verifying %s )%s\n"), hash_file_path, ralign);
+ fflush(rhash_data.out);
+ rsh_timer_start(&timer);
+
+ /* mark the directory part of the path, by setting the pos index */
+ if (chdir) {
+ pos = strlen(hash_file_path);
+ for (; pos > 0 && !IS_PATH_SEPARATOR(hash_file_path[pos]); pos--);
+ if (IS_PATH_SEPARATOR(hash_file_path[pos]))
+ pos++;
+ } else pos = 0;
+
+ /* read crc file line by line */
+ for (line_num = 0; fgets(buf, sizeof(buf), fd); line_num++) {
+ char* line = buf;
+ char* path_without_ext = NULL;
+
+ /* skip unicode BOM */
+ if (line_num == 0 && buf[0] == (char)0xEF && buf[1] == (char)0xBB && buf[2] == (char)0xBF)
+ line += 3;
+
+ if (*line == 0)
+ continue; /* skip empty lines */
+
+ if (is_binary_string(line)) {
+ log_error(_("file is binary: %s\n"), hash_file_path);
+ if (fd != stdin)
+ fclose(fd);
+ return -1;
+ }
+
+ /* skip comments and empty lines */
+ if (IS_COMMENT(*line) || *line == '\r' || *line == '\n')
+ continue;
+
+ memset(&info, 0, sizeof(info));
+
+ if (!hash_check_parse_line(line, &info.hc, !feof(fd)))
+ continue;
+ if (info.hc.hash_mask == 0)
+ continue;
+
+ info.print_path = info.hc.file_path;
+ info.sums_flags = info.hc.hash_mask;
+
+ /* see if crc file contains a hash sum without a filename */
+ if (info.print_path == NULL) {
+ char* point;
+ path_without_ext = rsh_strdup(hash_file_path);
+ point = strrchr(path_without_ext, '.');
+
+ if (point) {
+ *point = '\0';
+ file_info_set_print_path(&info, path_without_ext);
+ }
+ }
+
+ if (info.print_path != NULL) {
+ file_t file_to_check;
+ int is_absolute = IS_PATH_SEPARATOR(info.print_path[0]);
+ IF_WINDOWS(is_absolute = is_absolute || (info.print_path[0] && info.print_path[1] == ':'));
+
+ /* if filename shall be prepended by a directory path */
+ if (pos && !is_absolute) {
+ size_t len = strlen(info.print_path);
+ info.full_path = (char*)rsh_malloc(pos + len + 1);
+ memcpy(info.full_path, hash_file_path, pos);
+ strcpy(info.full_path + pos, info.print_path);
+ } else {
+ info.full_path = rsh_strdup(info.print_path);
+ }
+ memset(&file_to_check, 0, sizeof(file_t));
+ file_to_check.path = info.full_path;
+ file_stat(&file_to_check, 0);
+ info.file = &file_to_check;
+
+ /* verify hash sums of the file */
+ res = verify_sums(&info);
+
+ fflush(rhash_data.out);
+ file_cleanup(&file_to_check);
+ file_info_destroy(&info);
+
+ if (rhash_data.interrupted) {
+ free(path_without_ext);
+ break;
+ }
+
+ /* update statistics */
+ if (res == 0)
+ rhash_data.ok++;
+ else if (res == -1 && errno == ENOENT)
+ rhash_data.miss++;
+ rhash_data.processed++;
+ }
+ free(path_without_ext);
+ }
+ time = rsh_timer_stop(&timer);
+
+ rsh_fprintf(rhash_data.out, "%s\n", str_set(buf, '-', 80));
+ print_check_stats();
+
+ if (rhash_data.processed != rhash_data.ok)
+ rhash_data.error_flag = 1;
+
+ if ((opt.flags & OPT_SPEED) && rhash_data.processed > 1)
+ print_time_stats(time, rhash_data.total_size, 1);
+
+ rhash_data.processed = 0;
+ res = ferror(fd); /* check that crc file has been read without errors */
+ if (fd != stdin)
+ fclose(fd);
+ return (res == 0 ? 0 : -1);
+}
+
+/*=========================================================================
+ * Benchmark functions
+ *=========================================================================*/
+
+/**
+ * Hash a repeated message chunk by specified hash function.
+ *
+ * @param hash_id hash function identifier
+ * @param message a message chunk to hash
+ * @param msg_size message chunk size
+ * @param count number of chunks
+ * @param out computed hash
+ * @return 1 on success, 0 on error
+ */
+static int benchmark_loop(unsigned hash_id, const unsigned char* message, size_t msg_size, int count, unsigned char* out)
+{
+ int i;
+ struct rhash_context *context = rhash_init(hash_id);
+ if (!context)
+ return 0;
+
+ /* process the repeated message buffer */
+ for (i = 0; i < count && !rhash_data.interrupted; i++) {
+ rhash_update(context, message, msg_size);
+ }
+ rhash_final(context, out);
+ rhash_free(context);
+ return 1;
+}
+
+#if defined(_MSC_VER)
+#define ALIGN_DATA(n) __declspec(align(n))
+#elif defined(__GNUC__)
+#define ALIGN_DATA(n) __attribute__((aligned (n)))
+#else
+#define ALIGN_DATA(n) /* do nothing */
+#endif
+
+/* define read_tsc() if possible */
+#if defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
+
+#if defined( _MSC_VER ) /* if MS VC */
+# include
+# pragma intrinsic( __rdtsc )
+# define read_tsc() __rdtsc()
+# define HAVE_TSC
+#elif defined( __GNUC__ ) /* if GCC */
+static uint64_t read_tsc(void) {
+ unsigned long lo, hi;
+ __asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
+ return (((uint64_t)hi) << 32) + lo;
+}
+# define HAVE_TSC
+#endif /* _MSC_VER, __GNUC__ */
+#endif /* x86/amd64 arch */
+
+void run_benchmark(unsigned hash_id, unsigned flags)
+{
+ unsigned char ALIGN_DATA(64) message[8192]; /* 8 KiB */
+ timedelta_t timer;
+ int i, j;
+ size_t sz_mb, msg_size;
+ double time, total_time = 0;
+ const int rounds = 4;
+ const char* hash_name;
+ unsigned char out[130];
+#ifdef HAVE_TSC
+ double cpb = 0;
+#endif /* HAVE_TSC */
+
+#ifdef _WIN32
+ set_benchmark_cpu_affinity(); /* set CPU affinity to improve test results */
+#endif
+
+ /* set message size for fast and slow hash functions */
+ msg_size = 1073741824 / 2;
+ if (hash_id & (RHASH_WHIRLPOOL | RHASH_SNEFRU128 | RHASH_SNEFRU256 | RHASH_SHA3_224 | RHASH_SHA3_256 | RHASH_SHA3_384 | RHASH_SHA3_512)) {
+ msg_size /= 8;
+ } else if (hash_id & (RHASH_GOST94 | RHASH_GOST94_CRYPTOPRO | RHASH_SHA384 | RHASH_SHA512)) {
+ msg_size /= 2;
+ }
+ sz_mb = msg_size / (1 << 20); /* size in MiB */
+ hash_name = rhash_get_name(hash_id);
+ if (!hash_name)
+ hash_name = ""; /* benchmarking several hashes*/
+
+ for (i = 0; i < (int)sizeof(message); i++)
+ message[i] = i & 0xff;
+
+ for (j = 0; j < rounds && !rhash_data.interrupted; j++) {
+ rsh_timer_start(&timer);
+ benchmark_loop(hash_id, message, sizeof(message), (int)(msg_size / sizeof(message)), out);
+
+ time = rsh_timer_stop(&timer);
+ total_time += time;
+
+ if ((flags & BENCHMARK_RAW) == 0 && !rhash_data.interrupted) {
+ rsh_fprintf(rhash_data.out, "%s %u MiB calculated in %.3f sec, %.3f MBps\n", hash_name, (unsigned)sz_mb, time, (double)sz_mb / time);
+ fflush(rhash_data.out);
+ }
+ }
+
+#if defined(HAVE_TSC)
+ /* measure the CPU "clocks per byte" speed */
+ if ((flags & BENCHMARK_CPB) != 0 && !rhash_data.interrupted) {
+ unsigned int c1 = -1, c2 = -1;
+ unsigned volatile long long cy0, cy1, cy2;
+ int msg_size = 128 * 1024;
+
+ /* make 200 tries */
+ for (i = 0; i < 200; i++) {
+ cy0 = read_tsc();
+ benchmark_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out);
+ cy1 = read_tsc();
+ benchmark_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out);
+ benchmark_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out);
+ cy2 = read_tsc();
+
+ cy2 -= cy1;
+ cy1 -= cy0;
+ c1 = (unsigned int)(c1 > cy1 ? cy1 : c1);
+ c2 = (unsigned int)(c2 > cy2 ? cy2 : c2);
+ }
+ cpb = ((c2 - c1) + 1) / (double)msg_size;
+ }
+#endif /* HAVE_TSC */
+
+ if (rhash_data.interrupted) {
+ report_interrupted();
+ return;
+ }
+
+ if (flags & BENCHMARK_RAW) {
+ /* output result in a "raw" machine-readable format */
+ rsh_fprintf(rhash_data.out, "%s\t%u\t%.3f\t%.3f", hash_name, ((unsigned)sz_mb * rounds), total_time, (double)(sz_mb * rounds) / total_time);
+#if defined(HAVE_TSC)
+ if (flags & BENCHMARK_CPB) {
+ rsh_fprintf(rhash_data.out, "\t%.2f", cpb);
+ }
+#endif /* HAVE_TSC */
+ rsh_fprintf(rhash_data.out, "\n");
+ } else {
+ rsh_fprintf(rhash_data.out, "%s %u MiB total in %.3f sec, %.3f MBps", hash_name, ((unsigned)sz_mb * rounds), total_time, (double)(sz_mb * rounds) / total_time);
+#if defined(HAVE_TSC)
+ if (flags & BENCHMARK_CPB) {
+ rsh_fprintf(rhash_data.out, ", CPB=%.2f", cpb);
+ }
+#endif /* HAVE_TSC */
+ rsh_fprintf(rhash_data.out, "\n");
+ }
+}
diff --git a/calc_sums.h b/calc_sums.h
index b3552a36..3f541f73 100644
--- a/calc_sums.h
+++ b/calc_sums.h
@@ -1,64 +1,64 @@
-/* calc_sums.h */
-#ifndef CALC_SUMS_H
-#define CALC_SUMS_H
-
-#include
-#include "common_func.h"
-#include "file.h"
-#include "hash_check.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct file_t;
-
-/**
- * Information about a file to calculate/verify hashes for.
- */
-struct file_info {
- /* the file path (in system encoding). It can be changed
- * if a crc sum is embedded into the filename. */
- char* full_path;
- const char* print_path; /* the part of the path for printing */
- char* utf8_print_path; /* file path in UTF8 */
- uint64_t size; /* the size of the hashed file */
- uint64_t msg_offset; /* rctx->msg_size before hashing this file */
- double time; /* file processing time in seconds */
- struct file_t* file; /* the file being processed */
- struct rhash_context* rctx; /* state of hash algorithms */
- int error; /* -1 for i/o error, -2 for wrong sum, 0 on success */
- char* allocated_ptr;
-
- unsigned sums_flags; /* mask of ids of calculated hash functions */
- struct hash_check hc; /* hash values parsed from a hash file */
-};
-
-void file_info_destroy(struct file_info*); /* free allocated memory */
-const char* file_info_get_utf8_print_path(struct file_info*);
-
-int save_torrent_to(file_t* torrent_file, struct rhash_context* rctx);
-int calculate_and_print_sums(FILE* out, struct file_t* file, const char *print_path);
-int check_hash_file(struct file_t* file, int chdir);
-int rename_file_by_embeding_crc32(struct file_info *info);
-
-/* Benchmarking */
-
-/** Benchmarking flag: measure the CPU "clocks per byte" speed */
-#define BENCHMARK_CPB 1
-/** Benchmarking flag: print benchmark result in tab-delimited format */
-#define BENCHMARK_RAW 2
-
-/**
- * Benchmark a hash algorithm.
- *
- * @param hash_id hash algorithm identifier
- * @param flags benchmark flags, can contain BENCHMARK_CPB, BENCHMARK_RAW
- */
-void run_benchmark(unsigned hash_id, unsigned flags);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif /* __cplusplus */
-
-#endif /* CALC_SUMS_H */
+/* calc_sums.h */
+#ifndef CALC_SUMS_H
+#define CALC_SUMS_H
+
+#include
+#include "common_func.h"
+#include "file.h"
+#include "hash_check.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct file_t;
+
+/**
+ * Information about a file to calculate/verify hashes for.
+ */
+struct file_info {
+ /* the file path (in system encoding). It can be changed
+ * if a crc sum is embedded into the filename. */
+ char* full_path;
+ const char* print_path; /* the part of the path for printing */
+ char* utf8_print_path; /* file path in UTF8 */
+ uint64_t size; /* the size of the hashed file */
+ uint64_t msg_offset; /* rctx->msg_size before hashing this file */
+ double time; /* file processing time in seconds */
+ struct file_t* file; /* the file being processed */
+ struct rhash_context* rctx; /* state of hash algorithms */
+ int error; /* -1 for i/o error, -2 for wrong sum, 0 on success */
+ char* allocated_ptr;
+
+ unsigned sums_flags; /* mask of ids of calculated hash functions */
+ struct hash_check hc; /* hash values parsed from a hash file */
+};
+
+void file_info_destroy(struct file_info*); /* free allocated memory */
+const char* file_info_get_utf8_print_path(struct file_info*);
+
+int save_torrent_to(file_t* torrent_file, struct rhash_context* rctx);
+int calculate_and_print_sums(FILE* out, struct file_t* file, const char *print_path);
+int check_hash_file(struct file_t* file, int chdir);
+int rename_file_by_embeding_crc32(struct file_info *info);
+
+/* Benchmarking */
+
+/** Benchmarking flag: measure the CPU "clocks per byte" speed */
+#define BENCHMARK_CPB 1
+/** Benchmarking flag: print benchmark result in tab-delimited format */
+#define BENCHMARK_RAW 2
+
+/**
+ * Benchmark a hash algorithm.
+ *
+ * @param hash_id hash algorithm identifier
+ * @param flags benchmark flags, can contain BENCHMARK_CPB, BENCHMARK_RAW
+ */
+void run_benchmark(unsigned hash_id, unsigned flags);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* CALC_SUMS_H */
diff --git a/common_func.c b/common_func.c
index e510d6e4..60e3f535 100644
--- a/common_func.c
+++ b/common_func.c
@@ -1,667 +1,667 @@
-/* common_func.c - functions used almost everywhere */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#if defined( _WIN32) || defined(__CYGWIN__)
-# include
-#endif
-
-#include "common_func.h"
-#include "parse_cmdline.h"
-#include "version.h"
-#include "win_utils.h"
-
-/*=========================================================================
- * String functions
- *=========================================================================*/
-
-/**
- * Print a 0-terminated string representation of a 64-bit number to
- * a string buffer.
- *
- * @param dst the string buffer to write the number to
- * @param number the 64-bit number to output
- * @param min_width the minimum width, the number must take
- */
-void sprintI64(char *dst, uint64_t number, int min_width)
-{
- char buf[24]; /* internal buffer to output the number to */
- size_t len;
- char *p = buf + 23; /* start filling from the buffer end */
- *(p--) = 0; /* last symbol should be '\0' */
- if (number == 0) {
- *(p--) = '0';
- } else {
- for (; p >= buf && number != 0; p--, number /= 10) {
- *p = '0' + (char)(number % 10);
- }
- }
- len = buf + 22 - p;
- if ((size_t)min_width > len) {
- memset(dst, 0x20, min_width - len); /* fill by spaces */
- dst += min_width - len;
- }
- memcpy(dst, p+1, len+1); /* copy the number to the output buffer */
-}
-
-/**
- * Calculate length of decimal representation of given 64-bit integer.
- *
- * @param num integer to calculate the length for
- * @return length of decimal representation
- */
-int int_len(uint64_t num)
-{
- int len;
- for (len = 0; num; len++, num /= 10);
- return (len == 0 ? 1 : len); /* note: int_len(0) == 1 */
-}
-
-/**
- * Convert a byte to a hexadecimal string. The result, consisting of two
- * hexadecimal digits is stored into a buffer.
- *
- * @param dst the buffer to receive two symbols of hex representation
- * @param byte the byte to decode
- * @param upper_case flag to print string in uppercase
- * @return pointer to the next char in buffer (dst+2)
- */
-static char* print_hex_byte(char *dst, const unsigned char byte, int upper_case)
-{
- const char add = (upper_case ? 'A' - 10 : 'a' - 10);
- unsigned char c = (byte >> 4) & 15;
- *dst++ = (c > 9 ? c + add : c + '0');
- c = byte & 15;
- *dst++ = (c > 9 ? c + add : c + '0');
- return dst;
-}
-
-/* unsafe characters are "<>{}[]%#/|\^~`@:;?=&+ */
-#define IS_GOOD_URL_CHAR(c) (isalnum((unsigned char)c) || strchr("$-_.!'(),", c))
-
-/**
- * URL-encode a string.
- *
- * @param dst buffer to receive result or NULL to calculate
- * the lengths of encoded string
- * @param filename the file name
- * @return the length of the result string
- */
-int urlencode(char *dst, const char *name)
-{
- const char *start;
- if (!dst) {
- int len;
- for (len = 0; *name; name++) len += (IS_GOOD_URL_CHAR(*name) ? 1 : 3);
- return len;
- }
- /* encode URL as specified by RFC 1738 */
- for (start = dst; *name; name++) {
- if ( IS_GOOD_URL_CHAR(*name) ) {
- *dst++ = *name;
- } else {
- *dst++ = '%';
- dst = print_hex_byte(dst, *name, 'A');
- }
- }
- *dst = 0;
- return (int)(dst - start);
-}
-
-/**
- * Convert given string to lower case.
- * The result string will be allocated by malloc.
- * The allocated memory should be freed by calling free().
- *
- * @param str a string to convert
- * @return converted string allocated by malloc
- */
-char* str_tolower(const char* str)
-{
- char* buf = rsh_strdup(str);
- char* p;
- if (buf) {
- for (p = buf; *p; p++) *p = tolower(*p);
- }
- return buf;
-}
-
-/**
- * Remove spaces from the begin and the end of the string.
- *
- * @param str the modifiable buffer with the string
- * @return trimmed string
- */
-char* str_trim(char* str)
-{
- char* last = str + strlen(str) - 1;
- while (isspace((unsigned char)*str)) str++;
- while (isspace((unsigned char)*last) && last > str) *(last--) = 0;
- return str;
-}
-
-/**
- * Fill a buffer with NULL-terminated string consisting
- * solely of a given repeated character.
- *
- * @param buf the modifiable buffer to fill
- * @param ch the character to fill string with
- * @param length the length of the string to construct
- * @return the buffer
- */
-char* str_set(char* buf, int ch, int length)
-{
- memset(buf, ch, length);
- buf[length] = '\0';
- return buf;
-}
-
-/**
- * Concatenates two strings and returns allocated buffer with result.
- *
- * @param orig original string
- * @param append the string to append
- * @return the buffer
- */
-char* str_append(const char* orig, const char* append)
-{
- size_t len1 = strlen(orig);
- size_t len2 = strlen(append);
- char* res = (char*)rsh_malloc(len1 + len2 + 1);
-
- /* concatenate two strings */
- memcpy(res, orig, len1);
- memcpy(res + len1, append, len2 + 1);
- return res;
-}
-
-/**
- * Check if a string is a binary string, which means the string contain
- * a character with ACII code below 0x20 other than '\r', '\n', '\t'.
- *
- * @param str a string to check
- * @return non zero if string is binary
- */
-int is_binary_string(const char* str)
-{
- for (; *str; str++) {
- if (((unsigned char)*str) < 32 && ((1 << (unsigned char)*str) & ~0x2600)) {
- return 1;
- }
- }
- return 0;
-}
-
-/**
- * Count number of utf8 characters in a 0-terminated string
- *
- * @param str the string to measure
- * @return number of utf8 characters in the string
- */
-size_t strlen_utf8_c(const char *str)
-{
- size_t length = 0;
- for (; *str; str++) {
- if ((*str & 0xc0) != 0x80) length++;
- }
- return length;
-}
-
-/*=========================================================================
-* Program version information
-*=========================================================================*/
-
-const char* get_version_string(void)
-{
- static const char* version_string = VERSION;
- return version_string;
-}
-
-const char* get_bt_program_name(void)
-{
- static const char* bt_program_name = PROGRAM_NAME "/" VERSION;
- return bt_program_name;
-}
-
-/*=========================================================================
- * Timer functions
- *=========================================================================*/
-
-/**
- * Return real-value representing number of seconds
- * stored in the given timeval structure.
- * The function is used with timers, when printing time statistics.
- *
- * @param delta time delta to be converted
- * @return number of seconds
- */
-static double rsh_fsec(timedelta_t* timer)
-{
-#if defined( _WIN32) || defined(__CYGWIN__)
- LARGE_INTEGER freq;
- QueryPerformanceFrequency(&freq);
- return (double)*timer / freq.QuadPart;
-#else
- return ((double)timer->tv_usec / 1000000.0) + timer->tv_sec;
-#endif
-}
-
-#if defined( _WIN32) || defined(__CYGWIN__)
-#define get_timedelta(delta) QueryPerformanceCounter((LARGE_INTEGER*)delta)
-#else
-#define get_timedelta(delta) gettimeofday(delta, NULL)
-#endif
-
-void rsh_timer_start(timedelta_t* timer)
-{
- get_timedelta(timer);
-}
-
-double rsh_timer_stop(timedelta_t* timer)
-{
- timedelta_t end;
- get_timedelta(&end);
-#if defined( _WIN32) || defined(__CYGWIN__)
- *timer = end - *timer;
-#else
- timer->tv_sec = end.tv_sec - timer->tv_sec - (end.tv_usec >= timer->tv_usec ? 0 : 1);
- timer->tv_usec = end.tv_usec + (end.tv_usec >= timer->tv_usec ? 0 : 1000000 ) - timer->tv_usec;
-#endif
- return rsh_fsec(timer);
-}
-
-unsigned rhash_get_ticks(void)
-{
-#if defined( _WIN32) || defined(__CYGWIN__)
- return GetTickCount();
-#else
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
-#endif
-}
-
-/*=========================================================================
- * Custom program exit function
- *=========================================================================*/
-
-struct rhash_exit_handlers_t
-{
- unsigned handlers_count;
- exit_handler_t handlers[4];
-} rhash_exit_handlers = { 0, { 0 } };
-
-/**
-* Install a handler to be called on program exit.
-*
-* @param handler the hadler to add
-*/
-void rsh_install_exit_handler(exit_handler_t handler)
-{
- if (rhash_exit_handlers.handlers_count >= (sizeof(rhash_exit_handlers.handlers) / sizeof(rhash_exit_handlers.handlers[0])))
- {
- assert(!"to many handlers");
- rsh_exit(2);
- }
- rhash_exit_handlers.handlers[rhash_exit_handlers.handlers_count] = handler;
- rhash_exit_handlers.handlers_count++;
-}
-
-/**
-* Remove the last installed exit handler.
-*/
-void rsh_remove_exit_handler(void)
-{
- if (rhash_exit_handlers.handlers_count == 0)
- {
- assert(rhash_exit_handlers.handlers_count > 0 && "no handlers installed");
- rsh_exit(2);
- }
- rhash_exit_handlers.handlers_count--;
-}
-
-/**
-* Call all installed exit handlers, starting from the latest one, and exit the program.
-*
-* @param code the program exit code
-*/
-void rsh_exit(int code)
-{
- while (rhash_exit_handlers.handlers_count > 0)
- rhash_exit_handlers.handlers[--rhash_exit_handlers.handlers_count]();
- exit(code);
-}
-
-/*=========================================================================
- * Error reporting functions
- *=========================================================================*/
-
-static void report_error_default(const char* srcfile, int srcline,
- const char* format, ...);
-
-void (*rsh_report_error)(const char* srcfile, int srcline,
- const char* format, ...) = report_error_default;
-
-/**
- * Print given library failure to stderr.
- *
- * @param srcfile source file to report error on fail
- * @param srcline source code line to be reported on fail
- * @param format printf-formatted error message
- */
-static void report_error_default(const char* srcfile, int srcline, const char* format, ...)
-{
- va_list ap;
- rsh_fprintf(stderr, "RHash: error at %s:%u: ", srcfile, srcline);
- va_start(ap, format);
- rsh_vfprintf(stderr, format, ap); /* report the error to stderr */
- va_end(ap);
-}
-
-/*=========================================================================
- * Memory functions
- *=========================================================================*/
-
-/**
- * Allocates a buffer via malloc with reporting memory error to stderr.
- *
- * @param size size of the block to allocate
- * @param srcfile source file to report error on fail
- * @param srcline source code line to be reported on fail
- * @return allocated block
- */
-void* rhash_malloc(size_t size, const char* srcfile, int srcline)
-{
- void* res = malloc(size);
- if (!res) {
- rsh_report_error(srcfile, srcline, "%s(%u) failed\n", "malloc", (unsigned)size);
- rsh_exit(2);
- }
- return res;
-}
-
-/**
- * Allocates a buffer via calloc with reporting memory error to stderr.
- *
- * @param num number of elements to be allocated
- * @param size size of elements
- * @param srcfile source file to report error on fail
- * @param srcline source code line to be reported on fail
- * @return allocated block
- */
-void* rhash_calloc(size_t num, size_t size, const char* srcfile, int srcline)
-{
- void* res = calloc(num, size);
- if (!res) {
- rsh_report_error(srcfile, srcline, "calloc(%u, %u) failed\n", (unsigned)num, (unsigned)size);
- rsh_exit(2);
- }
- return res;
-}
-
-
-/**
- * Duplicate c-string with reporting memory error to stderr.
- *
- * @param str the zero-terminated string to duplicate
- * @param srcfile source file to report error on fail
- * @param srcline source code line to be reported on fail
- * @return allocated memory buffer with copied string
- */
-char* rhash_strdup(const char* str, const char* srcfile, int srcline)
-{
-#ifndef __STRICT_ANSI__
- char* res = strdup(str);
-#else
- char* res = (char*)malloc(strlen(str)+1);
- if (res) strcpy(res, str);
-#endif
-
- if (!res) {
- rsh_report_error(srcfile, srcline, "strdup(\"%s\") failed\n", str);
- rsh_exit(2);
- }
- return res;
-}
-
-#ifdef _WIN32
-/**
- * Duplicate wide string with reporting memory error to stderr.
- *
- * @param str the zero-terminated string to duplicate
- * @param srcfile source file to report error on fail
- * @param srcline source code line to be reported on fail
- * @return allocated memory buffer with copied string
- */
-wchar_t* rhash_wcsdup(const wchar_t* str, const char* srcfile, int srcline)
-{
-#ifndef __STRICT_ANSI__
- wchar_t* res = wcsdup(str);
-#else
- wchar_t* res = (wchar_t*)malloc((wcslen(str) + 1) * sizeof(wchar_t));
- if (res) wcscpy(res, str);
-#endif
-
- if (!res) {
- rsh_report_error(srcfile, srcline, "wcsdup(\"%u\") failed\n", (wcslen(str) + 1));
- rsh_exit(2);
- }
- return res;
-}
-#endif
-
-/**
- * Reallocates a buffer via realloc with reporting memory error to stderr.
- *
- * @param mem a memory block to re-allocate
- * @param size the new size of the block
- * @param srcfile source file to report error on fail
- * @param srcline source code line to be reported on fail
- * @return re-allocated memory buffer
- */
-void* rhash_realloc(void* mem, size_t size, const char* srcfile, int srcline)
-{
- void* res = realloc(mem, size);
- if (!res) {
- rsh_report_error(srcfile, srcline, "realloc(%p, %u) failed\n", mem, (unsigned)size);
- rsh_exit(2);
- }
- return res;
-}
-
-/*=========================================================================
- * Containers
- *=========================================================================*/
-
-/**
- * Allocate an empty vector.
- *
- * @param destructor pointer to the cleanup/deallocate function called
- * on each element when the vector is destructed,
- * NULL if items doesn't need to be freed
- * @return allocated vector
- */
-vector_t* rsh_vector_new(void (*destructor)(void*))
-{
- vector_t* ptr = (vector_t*)rsh_malloc(sizeof(vector_t));
- memset(ptr, 0, sizeof(vector_t));
- ptr->destructor = destructor;
- return ptr;
-}
-
-/**
- * Allocate an empty vector of pointers to memory blocks,
- * which will be deallocated at destruction time by calling free().
- *
- * @return allocated vector
- */
-struct vector_t* rsh_vector_new_simple(void)
-{
- return rsh_vector_new(free);
-}
-
-/**
- * Release memory allocated by vector, but the vector structure itself.
- *
- * @param vect the vector to free
- */
-void rsh_vector_destroy(vector_t* vect)
-{
- if (!vect) return;
- if (vect->destructor) {
- unsigned i;
- for (i=0; isize; i++) vect->destructor(vect->array[i]);
- }
- free(vect->array);
- vect->size = vect->allocated = 0;
- vect->array = 0;
-}
-
-/**
- * Release all memory allocated by vector.
- *
- * @param vect the vector to free
- */
-void rsh_vector_free(vector_t* vect)
-{
- rsh_vector_destroy(vect);
- free(vect);
-}
-
-/**
- * Add an item to vector.
- *
- * @param vect vector to add item to
- * @param item the item to add
- */
-void rsh_vector_add_ptr(vector_t* vect, void* item)
-{
- /* check if vect contains enough space for the next item */
- if (vect->size >= vect->allocated) {
- size_t size = (vect->allocated==0 ? 128 : vect->allocated * 2);
- vect->array = (void**)rsh_realloc(vect->array, size * sizeof(void*));
- vect->allocated = size;
- }
- /* add new item to the vector */
- vect->array[vect->size] = item;
- vect->size++;
-}
-
-/**
- * Add a sized item to vector.
- *
- * @param vect pointer to the vector to add item to
- * @param item_size the size of a vector item
- */
-void rsh_vector_add_empty(struct vector_t* vect, size_t item_size)
-{
- /* check if vect contains enough space for next item */
- if (vect->size >= vect->allocated) {
- size_t size = (vect->allocated==0 ? 128 : vect->allocated * 2);
- vect->array = (void**)rsh_realloc(vect->array, size * item_size);
- vect->allocated = size;
- }
- vect->size++;
-}
-
-/**
- * Initialize empty blocks vector.
- *
- * @param bvector pointer to the blocks vector
- */
-void rsh_blocks_vector_init(blocks_vector_t* bvector)
-{
- memset(bvector, 0, sizeof(*bvector));
- bvector->blocks.destructor = free;
-}
-
-/**
- * Free memory allocated by blocks vector, the function
- * doesn't deallocate memory additionally allocated for each element.
- *
- * @param bvector pointer to the blocks vector
- */
-void rsh_blocks_vector_destroy(blocks_vector_t* bvector)
-{
- rsh_vector_destroy(&bvector->blocks);
-}
-
-/*=========================================================================
- * String buffer functions
- *=========================================================================*/
-
-/**
- * Allocate an empty string buffer.
- *
- * @return allocated string buffer
- */
-strbuf_t* rsh_str_new(void)
-{
- strbuf_t *res = (strbuf_t*)malloc(sizeof(strbuf_t));
- memset(res, 0, sizeof(strbuf_t));
- return res;
-}
-
-/**
- * Free memory allocated by string buffer object
- *
- * @param ptr pointer to the string buffer to destroy
- */
-void rsh_str_free(strbuf_t* ptr)
-{
- if (ptr) {
- free(ptr->str);
- free(ptr);
- }
-}
-
-/**
- * Grow, if needed, internal buffer of the given string to ensure it contains
- * at least new_size number bytes.
- *
- * @param str pointer to the string-buffer object
- * @param new_size number of bytes buffer must contain
- */
-void rsh_str_ensure_size(strbuf_t *str, size_t new_size)
-{
- if (new_size >= (size_t)str->allocated) {
- if (new_size < 64) new_size = 64;
- str->str = (char*)rsh_realloc(str->str, new_size);
- str->allocated = new_size;
- }
-}
-
-/**
- * Append a sequence of single-byte characters of the specified length to
- * string buffer. The array is fully copied even if it contains the '\\0'
- * character. The function ensures the string buffer still contains
- * null-terminated string.
- *
- * @param str pointer to the string buffer
- * @param text the text to append
- * @param length number of character to append.
- */
-void rsh_str_append_n(strbuf_t *str, const char* text, size_t length)
-{
- rsh_str_ensure_length(str, str->len + length + 1);
- memcpy(str->str + str->len, text, length);
- str->len += length;
- str->str[str->len] = '\0';
-}
-
-/**
- * Append a null-terminated string to the string string buffer.
- *
- * @param str pointer to the string buffer
- * @param text the null-terminated string to append
- */
-void rsh_str_append(strbuf_t *str, const char* text)
-{
- rsh_str_append_n(str, text, strlen(text));
-}
+/* common_func.c - functions used almost everywhere */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if defined( _WIN32) || defined(__CYGWIN__)
+# include
+#endif
+
+#include "common_func.h"
+#include "parse_cmdline.h"
+#include "version.h"
+#include "win_utils.h"
+
+/*=========================================================================
+ * String functions
+ *=========================================================================*/
+
+/**
+ * Print a 0-terminated string representation of a 64-bit number to
+ * a string buffer.
+ *
+ * @param dst the string buffer to write the number to
+ * @param number the 64-bit number to output
+ * @param min_width the minimum width, the number must take
+ */
+void sprintI64(char *dst, uint64_t number, int min_width)
+{
+ char buf[24]; /* internal buffer to output the number to */
+ size_t len;
+ char *p = buf + 23; /* start filling from the buffer end */
+ *(p--) = 0; /* last symbol should be '\0' */
+ if (number == 0) {
+ *(p--) = '0';
+ } else {
+ for (; p >= buf && number != 0; p--, number /= 10) {
+ *p = '0' + (char)(number % 10);
+ }
+ }
+ len = buf + 22 - p;
+ if ((size_t)min_width > len) {
+ memset(dst, 0x20, min_width - len); /* fill by spaces */
+ dst += min_width - len;
+ }
+ memcpy(dst, p+1, len+1); /* copy the number to the output buffer */
+}
+
+/**
+ * Calculate length of decimal representation of given 64-bit integer.
+ *
+ * @param num integer to calculate the length for
+ * @return length of decimal representation
+ */
+int int_len(uint64_t num)
+{
+ int len;
+ for (len = 0; num; len++, num /= 10);
+ return (len == 0 ? 1 : len); /* note: int_len(0) == 1 */
+}
+
+/**
+ * Convert a byte to a hexadecimal string. The result, consisting of two
+ * hexadecimal digits is stored into a buffer.
+ *
+ * @param dst the buffer to receive two symbols of hex representation
+ * @param byte the byte to decode
+ * @param upper_case flag to print string in uppercase
+ * @return pointer to the next char in buffer (dst+2)
+ */
+static char* print_hex_byte(char *dst, const unsigned char byte, int upper_case)
+{
+ const char add = (upper_case ? 'A' - 10 : 'a' - 10);
+ unsigned char c = (byte >> 4) & 15;
+ *dst++ = (c > 9 ? c + add : c + '0');
+ c = byte & 15;
+ *dst++ = (c > 9 ? c + add : c + '0');
+ return dst;
+}
+
+/* unsafe characters are "<>{}[]%#/|\^~`@:;?=&+ */
+#define IS_GOOD_URL_CHAR(c) (isalnum((unsigned char)c) || strchr("$-_.!'(),", c))
+
+/**
+ * URL-encode a string.
+ *
+ * @param dst buffer to receive result or NULL to calculate
+ * the lengths of encoded string
+ * @param filename the file name
+ * @return the length of the result string
+ */
+int urlencode(char *dst, const char *name)
+{
+ const char *start;
+ if (!dst) {
+ int len;
+ for (len = 0; *name; name++) len += (IS_GOOD_URL_CHAR(*name) ? 1 : 3);
+ return len;
+ }
+ /* encode URL as specified by RFC 1738 */
+ for (start = dst; *name; name++) {
+ if ( IS_GOOD_URL_CHAR(*name) ) {
+ *dst++ = *name;
+ } else {
+ *dst++ = '%';
+ dst = print_hex_byte(dst, *name, 'A');
+ }
+ }
+ *dst = 0;
+ return (int)(dst - start);
+}
+
+/**
+ * Convert given string to lower case.
+ * The result string will be allocated by malloc.
+ * The allocated memory should be freed by calling free().
+ *
+ * @param str a string to convert
+ * @return converted string allocated by malloc
+ */
+char* str_tolower(const char* str)
+{
+ char* buf = rsh_strdup(str);
+ char* p;
+ if (buf) {
+ for (p = buf; *p; p++) *p = tolower(*p);
+ }
+ return buf;
+}
+
+/**
+ * Remove spaces from the begin and the end of the string.
+ *
+ * @param str the modifiable buffer with the string
+ * @return trimmed string
+ */
+char* str_trim(char* str)
+{
+ char* last = str + strlen(str) - 1;
+ while (isspace((unsigned char)*str)) str++;
+ while (isspace((unsigned char)*last) && last > str) *(last--) = 0;
+ return str;
+}
+
+/**
+ * Fill a buffer with NULL-terminated string consisting
+ * solely of a given repeated character.
+ *
+ * @param buf the modifiable buffer to fill
+ * @param ch the character to fill string with
+ * @param length the length of the string to construct
+ * @return the buffer
+ */
+char* str_set(char* buf, int ch, int length)
+{
+ memset(buf, ch, length);
+ buf[length] = '\0';
+ return buf;
+}
+
+/**
+ * Concatenates two strings and returns allocated buffer with result.
+ *
+ * @param orig original string
+ * @param append the string to append
+ * @return the buffer
+ */
+char* str_append(const char* orig, const char* append)
+{
+ size_t len1 = strlen(orig);
+ size_t len2 = strlen(append);
+ char* res = (char*)rsh_malloc(len1 + len2 + 1);
+
+ /* concatenate two strings */
+ memcpy(res, orig, len1);
+ memcpy(res + len1, append, len2 + 1);
+ return res;
+}
+
+/**
+ * Check if a string is a binary string, which means the string contain
+ * a character with ACII code below 0x20 other than '\r', '\n', '\t'.
+ *
+ * @param str a string to check
+ * @return non zero if string is binary
+ */
+int is_binary_string(const char* str)
+{
+ for (; *str; str++) {
+ if (((unsigned char)*str) < 32 && ((1 << (unsigned char)*str) & ~0x2600)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Count number of utf8 characters in a 0-terminated string
+ *
+ * @param str the string to measure
+ * @return number of utf8 characters in the string
+ */
+size_t strlen_utf8_c(const char *str)
+{
+ size_t length = 0;
+ for (; *str; str++) {
+ if ((*str & 0xc0) != 0x80) length++;
+ }
+ return length;
+}
+
+/*=========================================================================
+* Program version information
+*=========================================================================*/
+
+const char* get_version_string(void)
+{
+ static const char* version_string = VERSION;
+ return version_string;
+}
+
+const char* get_bt_program_name(void)
+{
+ static const char* bt_program_name = PROGRAM_NAME "/" VERSION;
+ return bt_program_name;
+}
+
+/*=========================================================================
+ * Timer functions
+ *=========================================================================*/
+
+/**
+ * Return real-value representing number of seconds
+ * stored in the given timeval structure.
+ * The function is used with timers, when printing time statistics.
+ *
+ * @param delta time delta to be converted
+ * @return number of seconds
+ */
+static double rsh_fsec(timedelta_t* timer)
+{
+#if defined( _WIN32) || defined(__CYGWIN__)
+ LARGE_INTEGER freq;
+ QueryPerformanceFrequency(&freq);
+ return (double)*timer / freq.QuadPart;
+#else
+ return ((double)timer->tv_usec / 1000000.0) + timer->tv_sec;
+#endif
+}
+
+#if defined( _WIN32) || defined(__CYGWIN__)
+#define get_timedelta(delta) QueryPerformanceCounter((LARGE_INTEGER*)delta)
+#else
+#define get_timedelta(delta) gettimeofday(delta, NULL)
+#endif
+
+void rsh_timer_start(timedelta_t* timer)
+{
+ get_timedelta(timer);
+}
+
+double rsh_timer_stop(timedelta_t* timer)
+{
+ timedelta_t end;
+ get_timedelta(&end);
+#if defined( _WIN32) || defined(__CYGWIN__)
+ *timer = end - *timer;
+#else
+ timer->tv_sec = end.tv_sec - timer->tv_sec - (end.tv_usec >= timer->tv_usec ? 0 : 1);
+ timer->tv_usec = end.tv_usec + (end.tv_usec >= timer->tv_usec ? 0 : 1000000 ) - timer->tv_usec;
+#endif
+ return rsh_fsec(timer);
+}
+
+unsigned rhash_get_ticks(void)
+{
+#if defined( _WIN32) || defined(__CYGWIN__)
+ return GetTickCount();
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
+#endif
+}
+
+/*=========================================================================
+ * Custom program exit function
+ *=========================================================================*/
+
+struct rhash_exit_handlers_t
+{
+ unsigned handlers_count;
+ exit_handler_t handlers[4];
+} rhash_exit_handlers = { 0, { 0 } };
+
+/**
+* Install a handler to be called on program exit.
+*
+* @param handler the hadler to add
+*/
+void rsh_install_exit_handler(exit_handler_t handler)
+{
+ if (rhash_exit_handlers.handlers_count >= (sizeof(rhash_exit_handlers.handlers) / sizeof(rhash_exit_handlers.handlers[0])))
+ {
+ assert(!"to many handlers");
+ rsh_exit(2);
+ }
+ rhash_exit_handlers.handlers[rhash_exit_handlers.handlers_count] = handler;
+ rhash_exit_handlers.handlers_count++;
+}
+
+/**
+* Remove the last installed exit handler.
+*/
+void rsh_remove_exit_handler(void)
+{
+ if (rhash_exit_handlers.handlers_count == 0)
+ {
+ assert(rhash_exit_handlers.handlers_count > 0 && "no handlers installed");
+ rsh_exit(2);
+ }
+ rhash_exit_handlers.handlers_count--;
+}
+
+/**
+* Call all installed exit handlers, starting from the latest one, and exit the program.
+*
+* @param code the program exit code
+*/
+void rsh_exit(int code)
+{
+ while (rhash_exit_handlers.handlers_count > 0)
+ rhash_exit_handlers.handlers[--rhash_exit_handlers.handlers_count]();
+ exit(code);
+}
+
+/*=========================================================================
+ * Error reporting functions
+ *=========================================================================*/
+
+static void report_error_default(const char* srcfile, int srcline,
+ const char* format, ...);
+
+void (*rsh_report_error)(const char* srcfile, int srcline,
+ const char* format, ...) = report_error_default;
+
+/**
+ * Print given library failure to stderr.
+ *
+ * @param srcfile source file to report error on fail
+ * @param srcline source code line to be reported on fail
+ * @param format printf-formatted error message
+ */
+static void report_error_default(const char* srcfile, int srcline, const char* format, ...)
+{
+ va_list ap;
+ rsh_fprintf(stderr, "RHash: error at %s:%u: ", srcfile, srcline);
+ va_start(ap, format);
+ rsh_vfprintf(stderr, format, ap); /* report the error to stderr */
+ va_end(ap);
+}
+
+/*=========================================================================
+ * Memory functions
+ *=========================================================================*/
+
+/**
+ * Allocates a buffer via malloc with reporting memory error to stderr.
+ *
+ * @param size size of the block to allocate
+ * @param srcfile source file to report error on fail
+ * @param srcline source code line to be reported on fail
+ * @return allocated block
+ */
+void* rhash_malloc(size_t size, const char* srcfile, int srcline)
+{
+ void* res = malloc(size);
+ if (!res) {
+ rsh_report_error(srcfile, srcline, "%s(%u) failed\n", "malloc", (unsigned)size);
+ rsh_exit(2);
+ }
+ return res;
+}
+
+/**
+ * Allocates a buffer via calloc with reporting memory error to stderr.
+ *
+ * @param num number of elements to be allocated
+ * @param size size of elements
+ * @param srcfile source file to report error on fail
+ * @param srcline source code line to be reported on fail
+ * @return allocated block
+ */
+void* rhash_calloc(size_t num, size_t size, const char* srcfile, int srcline)
+{
+ void* res = calloc(num, size);
+ if (!res) {
+ rsh_report_error(srcfile, srcline, "calloc(%u, %u) failed\n", (unsigned)num, (unsigned)size);
+ rsh_exit(2);
+ }
+ return res;
+}
+
+
+/**
+ * Duplicate c-string with reporting memory error to stderr.
+ *
+ * @param str the zero-terminated string to duplicate
+ * @param srcfile source file to report error on fail
+ * @param srcline source code line to be reported on fail
+ * @return allocated memory buffer with copied string
+ */
+char* rhash_strdup(const char* str, const char* srcfile, int srcline)
+{
+#ifndef __STRICT_ANSI__
+ char* res = strdup(str);
+#else
+ char* res = (char*)malloc(strlen(str)+1);
+ if (res) strcpy(res, str);
+#endif
+
+ if (!res) {
+ rsh_report_error(srcfile, srcline, "strdup(\"%s\") failed\n", str);
+ rsh_exit(2);
+ }
+ return res;
+}
+
+#ifdef _WIN32
+/**
+ * Duplicate wide string with reporting memory error to stderr.
+ *
+ * @param str the zero-terminated string to duplicate
+ * @param srcfile source file to report error on fail
+ * @param srcline source code line to be reported on fail
+ * @return allocated memory buffer with copied string
+ */
+wchar_t* rhash_wcsdup(const wchar_t* str, const char* srcfile, int srcline)
+{
+#ifndef __STRICT_ANSI__
+ wchar_t* res = wcsdup(str);
+#else
+ wchar_t* res = (wchar_t*)malloc((wcslen(str) + 1) * sizeof(wchar_t));
+ if (res) wcscpy(res, str);
+#endif
+
+ if (!res) {
+ rsh_report_error(srcfile, srcline, "wcsdup(\"%u\") failed\n", (wcslen(str) + 1));
+ rsh_exit(2);
+ }
+ return res;
+}
+#endif
+
+/**
+ * Reallocates a buffer via realloc with reporting memory error to stderr.
+ *
+ * @param mem a memory block to re-allocate
+ * @param size the new size of the block
+ * @param srcfile source file to report error on fail
+ * @param srcline source code line to be reported on fail
+ * @return re-allocated memory buffer
+ */
+void* rhash_realloc(void* mem, size_t size, const char* srcfile, int srcline)
+{
+ void* res = realloc(mem, size);
+ if (!res) {
+ rsh_report_error(srcfile, srcline, "realloc(%p, %u) failed\n", mem, (unsigned)size);
+ rsh_exit(2);
+ }
+ return res;
+}
+
+/*=========================================================================
+ * Containers
+ *=========================================================================*/
+
+/**
+ * Allocate an empty vector.
+ *
+ * @param destructor pointer to the cleanup/deallocate function called
+ * on each element when the vector is destructed,
+ * NULL if items doesn't need to be freed
+ * @return allocated vector
+ */
+vector_t* rsh_vector_new(void (*destructor)(void*))
+{
+ vector_t* ptr = (vector_t*)rsh_malloc(sizeof(vector_t));
+ memset(ptr, 0, sizeof(vector_t));
+ ptr->destructor = destructor;
+ return ptr;
+}
+
+/**
+ * Allocate an empty vector of pointers to memory blocks,
+ * which will be deallocated at destruction time by calling free().
+ *
+ * @return allocated vector
+ */
+struct vector_t* rsh_vector_new_simple(void)
+{
+ return rsh_vector_new(free);
+}
+
+/**
+ * Release memory allocated by vector, but the vector structure itself.
+ *
+ * @param vect the vector to free
+ */
+void rsh_vector_destroy(vector_t* vect)
+{
+ if (!vect) return;
+ if (vect->destructor) {
+ unsigned i;
+ for (i=0; isize; i++) vect->destructor(vect->array[i]);
+ }
+ free(vect->array);
+ vect->size = vect->allocated = 0;
+ vect->array = 0;
+}
+
+/**
+ * Release all memory allocated by vector.
+ *
+ * @param vect the vector to free
+ */
+void rsh_vector_free(vector_t* vect)
+{
+ rsh_vector_destroy(vect);
+ free(vect);
+}
+
+/**
+ * Add an item to vector.
+ *
+ * @param vect vector to add item to
+ * @param item the item to add
+ */
+void rsh_vector_add_ptr(vector_t* vect, void* item)
+{
+ /* check if vect contains enough space for the next item */
+ if (vect->size >= vect->allocated) {
+ size_t size = (vect->allocated==0 ? 128 : vect->allocated * 2);
+ vect->array = (void**)rsh_realloc(vect->array, size * sizeof(void*));
+ vect->allocated = size;
+ }
+ /* add new item to the vector */
+ vect->array[vect->size] = item;
+ vect->size++;
+}
+
+/**
+ * Add a sized item to vector.
+ *
+ * @param vect pointer to the vector to add item to
+ * @param item_size the size of a vector item
+ */
+void rsh_vector_add_empty(struct vector_t* vect, size_t item_size)
+{
+ /* check if vect contains enough space for next item */
+ if (vect->size >= vect->allocated) {
+ size_t size = (vect->allocated==0 ? 128 : vect->allocated * 2);
+ vect->array = (void**)rsh_realloc(vect->array, size * item_size);
+ vect->allocated = size;
+ }
+ vect->size++;
+}
+
+/**
+ * Initialize empty blocks vector.
+ *
+ * @param bvector pointer to the blocks vector
+ */
+void rsh_blocks_vector_init(blocks_vector_t* bvector)
+{
+ memset(bvector, 0, sizeof(*bvector));
+ bvector->blocks.destructor = free;
+}
+
+/**
+ * Free memory allocated by blocks vector, the function
+ * doesn't deallocate memory additionally allocated for each element.
+ *
+ * @param bvector pointer to the blocks vector
+ */
+void rsh_blocks_vector_destroy(blocks_vector_t* bvector)
+{
+ rsh_vector_destroy(&bvector->blocks);
+}
+
+/*=========================================================================
+ * String buffer functions
+ *=========================================================================*/
+
+/**
+ * Allocate an empty string buffer.
+ *
+ * @return allocated string buffer
+ */
+strbuf_t* rsh_str_new(void)
+{
+ strbuf_t *res = (strbuf_t*)malloc(sizeof(strbuf_t));
+ memset(res, 0, sizeof(strbuf_t));
+ return res;
+}
+
+/**
+ * Free memory allocated by string buffer object
+ *
+ * @param ptr pointer to the string buffer to destroy
+ */
+void rsh_str_free(strbuf_t* ptr)
+{
+ if (ptr) {
+ free(ptr->str);
+ free(ptr);
+ }
+}
+
+/**
+ * Grow, if needed, internal buffer of the given string to ensure it contains
+ * at least new_size number bytes.
+ *
+ * @param str pointer to the string-buffer object
+ * @param new_size number of bytes buffer must contain
+ */
+void rsh_str_ensure_size(strbuf_t *str, size_t new_size)
+{
+ if (new_size >= (size_t)str->allocated) {
+ if (new_size < 64) new_size = 64;
+ str->str = (char*)rsh_realloc(str->str, new_size);
+ str->allocated = new_size;
+ }
+}
+
+/**
+ * Append a sequence of single-byte characters of the specified length to
+ * string buffer. The array is fully copied even if it contains the '\\0'
+ * character. The function ensures the string buffer still contains
+ * null-terminated string.
+ *
+ * @param str pointer to the string buffer
+ * @param text the text to append
+ * @param length number of character to append.
+ */
+void rsh_str_append_n(strbuf_t *str, const char* text, size_t length)
+{
+ rsh_str_ensure_length(str, str->len + length + 1);
+ memcpy(str->str + str->len, text, length);
+ str->len += length;
+ str->str[str->len] = '\0';
+}
+
+/**
+ * Append a null-terminated string to the string string buffer.
+ *
+ * @param str pointer to the string buffer
+ * @param text the null-terminated string to append
+ */
+void rsh_str_append(strbuf_t *str, const char* text)
+{
+ rsh_str_append_n(str, text, strlen(text));
+}
diff --git a/common_func.h b/common_func.h
index 494ce2b8..ed867498 100644
--- a/common_func.h
+++ b/common_func.h
@@ -1,220 +1,220 @@
-/* common_func.h - commonly used functions */
-#ifndef COMMON_FUNC_H
-#define COMMON_FUNC_H
-
-/* internationalization support via gettext/libintl */
-#ifdef USE_GETTEXT
-# include
-# define _(str) gettext(str)
-# define TEXT_DOMAIN "rhash"
-# ifndef LOCALEDIR
-# define LOCALEDIR "/usr/share/locale"
-# endif /* LOCALEDIR */
-#else
-# define _(str) (str)
-#endif /* USE_GETTEXT */
-
-#include
-#include
-#include /* for time_t */
-#include /* for wchar_t */
-
-#if !defined( _WIN32) && !defined(__CYGWIN__)
-# include /* for timeval */
-#elif _MSC_VER > 1300
-# include "platform.h"
-#endif
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* string function */
-void sprintI64(char *dst, uint64_t number, int max_width);
-int int_len(uint64_t num);
-
-int urlencode(char *dst, const char *name);
-int is_binary_string(const char* str);
-char* str_tolower(const char* str);
-char* str_trim(char* str);
-char* str_set(char* buf, int ch, int size);
-char* str_append(const char* orig, const char* append);
-size_t strlen_utf8_c(const char *str);
-
-#define IS_COMMENT(c) ((c) == ';' || (c) == '#')
-
-#ifdef _WIN32
-typedef wchar_t rsh_tchar;
-# define RSH_T(str) L##str
-# define t2c(tstr) (w2c(tstr))
-#else
-typedef char rsh_tchar;
-# define RSH_T(str) str
-# define t2c(tstr) (tstr)
-#endif /* _WIN32 */
-typedef rsh_tchar* tstr_t;
-typedef const rsh_tchar* ctstr_t;
-
-#ifdef _WIN32
-# define IF_WINDOWS(code) code
-# define is_utf8() win_is_utf8()
-# define to_utf8(str) str_to_utf8(str)
-#else /* non _WIN32 part */
-# define IF_WINDOWS(code)
-/* stub for utf8 */
-# define is_utf8() 1
-# define to_utf8(str) NULL
-#endif /* _WIN32 */
-
-/* version information */
-const char* get_version_string(void);
-const char* get_bt_program_name(void);
-
-
-#ifdef _WIN32
-# define rsh_fprintf win_fprintf
-# define rsh_vfprintf win_vfprintf
-# define rsh_fwrite win_fwrite
-#else
-# define rsh_fprintf fprintf
-# define rsh_vfprintf vfprintf
-# define rsh_fwrite fwrite
-#endif
-
-
-/* time data and functions */
-
-/* portable timer definition */
-#if defined( _WIN32) || defined(__CYGWIN__)
-typedef unsigned long long timedelta_t;
-#else
-#include /* for timeval */
-typedef struct timeval timedelta_t;
-#endif
-
-/**
- * Start a timer.
- *
- * @param timer timer to start
- */
-void rsh_timer_start(timedelta_t* timer);
-
-/**
- * Stop given timer.
- *
- * @param timer the timer to stop
- * @return number of seconds timed
- */
-double rsh_timer_stop(timedelta_t* timer);
-
-/**
- * Return ticks in milliseconds for time intervals measurement.
- * This function should be optimized for speed and retrieve
- * internal clock value, if possible.
- *
- * @return ticks count in milliseconds
- */
-unsigned rhash_get_ticks(void);
-
-/* program exit handlers */
-typedef void (*exit_handler_t)(void);
-void rsh_install_exit_handler(exit_handler_t handler);
-void rsh_remove_exit_handler(void);
-void rsh_exit(int code);
-
-/* clever malloc with error detection */
-#define rsh_malloc(size) rhash_malloc(size, __FILE__, __LINE__)
-#define rsh_calloc(num, size) rhash_calloc(num, size, __FILE__, __LINE__)
-#define rsh_strdup(str) rhash_strdup(str, __FILE__, __LINE__)
-#define rsh_realloc(mem, size) rhash_realloc(mem, size, __FILE__, __LINE__)
-void* rhash_malloc(size_t size, const char* srcfile, int srcline);
-void* rhash_calloc(size_t num, size_t size, const char* srcfile, int srcline);
-char* rhash_strdup(const char* str, const char* srcfile, int srcline);
-void* rhash_realloc(void* mem, size_t size, const char* srcfile, int srcline);
-
-#ifdef _WIN32
-#define rsh_wcsdup(str) rhash_wcsdup(str, __FILE__, __LINE__)
-wchar_t* rhash_wcsdup(const wchar_t* str, const char* srcfile, int srcline);
-#endif
-
-extern void (*rsh_report_error)(const char* srcfile, int srcline, const char* format, ...);
-
-/* vector functions */
-typedef struct vector_t
-{
- void **array;
- size_t size;
- size_t allocated;
- void (*destructor)(void*);
-} vector_t;
-
-vector_t* rsh_vector_new(void (*destructor)(void*));
-vector_t* rsh_vector_new_simple(void);
-void rsh_vector_free(vector_t* vect);
-void rsh_vector_destroy(vector_t* vect);
-void rsh_vector_add_ptr(vector_t* vect, void *item);
-void rsh_vector_add_empty(vector_t* vect, size_t item_size);
-#define rsh_vector_add_uint32(vect, item) { \
- rsh_vector_add_empty(vect, item_size); \
- ((unsigned*)(vect)->array)[(vect)->size - 1] = item; \
-}
-#define rsh_vector_add_item(vect, item, item_size) { \
- rsh_vector_add_empty(vect, item_size); \
- memcpy(((char*)(vect)->array) + item_size * ((vect)->size - 1), item, item_size); \
-}
-
-/* a vector pattern implementation, allocating elements by blocks */
-typedef struct blocks_vector_t
-{
- size_t size;
- vector_t blocks;
-} blocks_vector_t;
-
-void rsh_blocks_vector_init(blocks_vector_t*);
-void rsh_blocks_vector_destroy(blocks_vector_t* vect);
-#define rsh_blocks_vector_get_item(bvector, index, blocksize, item_type) \
- (&((item_type*)((bvector)->blocks.array[(index) / (blocksize)]))[(index) % (blocksize)])
-#define rsh_blocks_vector_get_ptr(bvector, index, blocksize, item_size) \
- (&((unsigned char*)((bvector)->blocks.array[(index) / (blocksize)]))[(item_size) * ((index) % (blocksize))])
-#define rsh_blocks_vector_add(bvector, item, blocksize, item_size) { \
- if (((bvector)->size % (blocksize)) == 0) \
- rsh_vector_add_ptr(&((bvector)->blocks), rsh_malloc((item_size) * (blocksize))); \
- memcpy(rsh_blocks_vector_get_ptr((bvector), (bvector)->size, (blocksize), (item_size)), (item), (item_size)); \
- (bvector)->size++; \
-}
-#define rsh_blocks_vector_add_ptr(bvector, ptr, blocksize) { \
- if (((bvector)->size % (blocksize)) == 0) \
- rsh_vector_add_ptr(&((bvector)->blocks), rsh_malloc(sizeof(void*) * (blocksize))); \
- ((void***)(bvector)->blocks.array)[(bvector)->size / (blocksize)][(bvector)->size % (blocksize)] = (void*)ptr; \
- (bvector)->size++; \
-}
-#define rsh_blocks_vector_add_empty(bvector, blocksize, item_size) { \
- if ( (((bvector)->size++) % (blocksize)) == 0) \
- rsh_vector_add_ptr(&((bvector)->blocks), rsh_malloc((item_size) * (blocksize))); \
-}
-
-/* string buffer functions */
-typedef struct strbuf_t
-{
- char* str;
- size_t allocated;
- size_t len;
-} strbuf_t;
-
-strbuf_t* rsh_str_new(void);
-void rsh_str_free(strbuf_t* buf);
-void rsh_str_ensure_size(strbuf_t *str, size_t new_size);
-void rsh_str_append_n(strbuf_t *str, const char* text, size_t len);
-void rsh_str_append(strbuf_t *str, const char* text);
-
-#define rsh_str_ensure_length(str, len) \
- if ((size_t)(len) >= (size_t)(str)->allocated) rsh_str_ensure_size((str), (len) + 1);
-#define rsh_wstr_ensure_length(str, len) \
- if ((size_t)((len) + sizeof(wchar_t)) > (size_t)(str)->allocated) rsh_str_ensure_size((str), (len) + sizeof(wchar_t));
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif /* __cplusplus */
-
-#endif /* COMMON_FUNC_H */
+/* common_func.h - commonly used functions */
+#ifndef COMMON_FUNC_H
+#define COMMON_FUNC_H
+
+/* internationalization support via gettext/libintl */
+#ifdef USE_GETTEXT
+# include
+# define _(str) gettext(str)
+# define TEXT_DOMAIN "rhash"
+# ifndef LOCALEDIR
+# define LOCALEDIR "/usr/share/locale"
+# endif /* LOCALEDIR */
+#else
+# define _(str) (str)
+#endif /* USE_GETTEXT */
+
+#include
+#include
+#include /* for time_t */
+#include /* for wchar_t */
+
+#if !defined( _WIN32) && !defined(__CYGWIN__)
+# include /* for timeval */
+#elif _MSC_VER > 1300
+# include "platform.h"
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* string function */
+void sprintI64(char *dst, uint64_t number, int max_width);
+int int_len(uint64_t num);
+
+int urlencode(char *dst, const char *name);
+int is_binary_string(const char* str);
+char* str_tolower(const char* str);
+char* str_trim(char* str);
+char* str_set(char* buf, int ch, int size);
+char* str_append(const char* orig, const char* append);
+size_t strlen_utf8_c(const char *str);
+
+#define IS_COMMENT(c) ((c) == ';' || (c) == '#')
+
+#ifdef _WIN32
+typedef wchar_t rsh_tchar;
+# define RSH_T(str) L##str
+# define t2c(tstr) (w2c(tstr))
+#else
+typedef char rsh_tchar;
+# define RSH_T(str) str
+# define t2c(tstr) (tstr)
+#endif /* _WIN32 */
+typedef rsh_tchar* tstr_t;
+typedef const rsh_tchar* ctstr_t;
+
+#ifdef _WIN32
+# define IF_WINDOWS(code) code
+# define is_utf8() win_is_utf8()
+# define to_utf8(str) str_to_utf8(str)
+#else /* non _WIN32 part */
+# define IF_WINDOWS(code)
+/* stub for utf8 */
+# define is_utf8() 1
+# define to_utf8(str) NULL
+#endif /* _WIN32 */
+
+/* version information */
+const char* get_version_string(void);
+const char* get_bt_program_name(void);
+
+
+#ifdef _WIN32
+# define rsh_fprintf win_fprintf
+# define rsh_vfprintf win_vfprintf
+# define rsh_fwrite win_fwrite
+#else
+# define rsh_fprintf fprintf
+# define rsh_vfprintf vfprintf
+# define rsh_fwrite fwrite
+#endif
+
+
+/* time data and functions */
+
+/* portable timer definition */
+#if defined( _WIN32) || defined(__CYGWIN__)
+typedef unsigned long long timedelta_t;
+#else
+#include /* for timeval */
+typedef struct timeval timedelta_t;
+#endif
+
+/**
+ * Start a timer.
+ *
+ * @param timer timer to start
+ */
+void rsh_timer_start(timedelta_t* timer);
+
+/**
+ * Stop given timer.
+ *
+ * @param timer the timer to stop
+ * @return number of seconds timed
+ */
+double rsh_timer_stop(timedelta_t* timer);
+
+/**
+ * Return ticks in milliseconds for time intervals measurement.
+ * This function should be optimized for speed and retrieve
+ * internal clock value, if possible.
+ *
+ * @return ticks count in milliseconds
+ */
+unsigned rhash_get_ticks(void);
+
+/* program exit handlers */
+typedef void (*exit_handler_t)(void);
+void rsh_install_exit_handler(exit_handler_t handler);
+void rsh_remove_exit_handler(void);
+void rsh_exit(int code);
+
+/* clever malloc with error detection */
+#define rsh_malloc(size) rhash_malloc(size, __FILE__, __LINE__)
+#define rsh_calloc(num, size) rhash_calloc(num, size, __FILE__, __LINE__)
+#define rsh_strdup(str) rhash_strdup(str, __FILE__, __LINE__)
+#define rsh_realloc(mem, size) rhash_realloc(mem, size, __FILE__, __LINE__)
+void* rhash_malloc(size_t size, const char* srcfile, int srcline);
+void* rhash_calloc(size_t num, size_t size, const char* srcfile, int srcline);
+char* rhash_strdup(const char* str, const char* srcfile, int srcline);
+void* rhash_realloc(void* mem, size_t size, const char* srcfile, int srcline);
+
+#ifdef _WIN32
+#define rsh_wcsdup(str) rhash_wcsdup(str, __FILE__, __LINE__)
+wchar_t* rhash_wcsdup(const wchar_t* str, const char* srcfile, int srcline);
+#endif
+
+extern void (*rsh_report_error)(const char* srcfile, int srcline, const char* format, ...);
+
+/* vector functions */
+typedef struct vector_t
+{
+ void **array;
+ size_t size;
+ size_t allocated;
+ void (*destructor)(void*);
+} vector_t;
+
+vector_t* rsh_vector_new(void (*destructor)(void*));
+vector_t* rsh_vector_new_simple(void);
+void rsh_vector_free(vector_t* vect);
+void rsh_vector_destroy(vector_t* vect);
+void rsh_vector_add_ptr(vector_t* vect, void *item);
+void rsh_vector_add_empty(vector_t* vect, size_t item_size);
+#define rsh_vector_add_uint32(vect, item) { \
+ rsh_vector_add_empty(vect, item_size); \
+ ((unsigned*)(vect)->array)[(vect)->size - 1] = item; \
+}
+#define rsh_vector_add_item(vect, item, item_size) { \
+ rsh_vector_add_empty(vect, item_size); \
+ memcpy(((char*)(vect)->array) + item_size * ((vect)->size - 1), item, item_size); \
+}
+
+/* a vector pattern implementation, allocating elements by blocks */
+typedef struct blocks_vector_t
+{
+ size_t size;
+ vector_t blocks;
+} blocks_vector_t;
+
+void rsh_blocks_vector_init(blocks_vector_t*);
+void rsh_blocks_vector_destroy(blocks_vector_t* vect);
+#define rsh_blocks_vector_get_item(bvector, index, blocksize, item_type) \
+ (&((item_type*)((bvector)->blocks.array[(index) / (blocksize)]))[(index) % (blocksize)])
+#define rsh_blocks_vector_get_ptr(bvector, index, blocksize, item_size) \
+ (&((unsigned char*)((bvector)->blocks.array[(index) / (blocksize)]))[(item_size) * ((index) % (blocksize))])
+#define rsh_blocks_vector_add(bvector, item, blocksize, item_size) { \
+ if (((bvector)->size % (blocksize)) == 0) \
+ rsh_vector_add_ptr(&((bvector)->blocks), rsh_malloc((item_size) * (blocksize))); \
+ memcpy(rsh_blocks_vector_get_ptr((bvector), (bvector)->size, (blocksize), (item_size)), (item), (item_size)); \
+ (bvector)->size++; \
+}
+#define rsh_blocks_vector_add_ptr(bvector, ptr, blocksize) { \
+ if (((bvector)->size % (blocksize)) == 0) \
+ rsh_vector_add_ptr(&((bvector)->blocks), rsh_malloc(sizeof(void*) * (blocksize))); \
+ ((void***)(bvector)->blocks.array)[(bvector)->size / (blocksize)][(bvector)->size % (blocksize)] = (void*)ptr; \
+ (bvector)->size++; \
+}
+#define rsh_blocks_vector_add_empty(bvector, blocksize, item_size) { \
+ if ( (((bvector)->size++) % (blocksize)) == 0) \
+ rsh_vector_add_ptr(&((bvector)->blocks), rsh_malloc((item_size) * (blocksize))); \
+}
+
+/* string buffer functions */
+typedef struct strbuf_t
+{
+ char* str;
+ size_t allocated;
+ size_t len;
+} strbuf_t;
+
+strbuf_t* rsh_str_new(void);
+void rsh_str_free(strbuf_t* buf);
+void rsh_str_ensure_size(strbuf_t *str, size_t new_size);
+void rsh_str_append_n(strbuf_t *str, const char* text, size_t len);
+void rsh_str_append(strbuf_t *str, const char* text);
+
+#define rsh_str_ensure_length(str, len) \
+ if ((size_t)(len) >= (size_t)(str)->allocated) rsh_str_ensure_size((str), (len) + 1);
+#define rsh_wstr_ensure_length(str, len) \
+ if ((size_t)((len) + sizeof(wchar_t)) > (size_t)(str)->allocated) rsh_str_ensure_size((str), (len) + sizeof(wchar_t));
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* COMMON_FUNC_H */
diff --git a/configure b/configure
index ee827a84..e0560c5e 100755
--- a/configure
+++ b/configure
@@ -1,903 +1,903 @@
-#!/bin/sh
-
-# set default values
-OPT_OPENSSL=auto
-OPT_OPENSSL_RUNTIME=auto
-OPT_GETTEXT=auto
-
-export LC_ALL=C
-CFG_LINE="$*"
-INSTALL_PREFIX="/usr/local"
-test -z "$CC" && CC=cc
-CMD_AR=ar
-CMD_INSTALL=install
-BUILD_DEBUG=
-BUILD_STATIC=auto
-BUILD_EXTRA_CFLAGS=
-BUILD_EXTRA_LDFLAGS=
-CHECK_LDFLAGS=
-WARN_CFLAGS="-Wall -W -Wstrict-prototypes -Wnested-externs -Winline -Wpointer-arith -Wbad-function-cast -Wmissing-prototypes -Wmissing-declarations"
-INSTALL_SYMLINKS="sfv-hash tiger-hash tth-hash whirlpool-hash has160-hash gost-hash edonr256-hash edonr512-hash ed2k-link magnet-link"
-INSTALL_LIB_STATIC=auto
-INSTALL_LIB_SHARED=auto
-INSTALL_PKGCONFIGDIR="$PKG_INSTALLDIR"
-
-# display error message and exit
-die () {
- echo
- echo "Error: $@" >&2
- echo >&2
- test -f "$TMPLOG" && echo "Error: $@" >> "$TMPLOG"
- rm -f "$TMPBIN" "$TMPC" "$TMPT"
- echo "Check \"$TMPLOG\" if you do not understand why it failed."
- exit 1
-}
-
-print_help()
-{
- cat << EOF
-Usage: configure [OPTIONS]...
-
-Generic Options:
- -h, --help display this help and exit
- --cc=COMPILER C compiler to build RHash [gcc]
- --ar=AR librarian to build RHash [ar]
- --target=PLATFORM target platform (i386-linux, arm-linux, etc)
- --with-install=PATH path to a custom install program
-
-Directory Options:
- --prefix=DIR prefix directory for installation [/usr/local]
- --exec-prefix=DIR prefix directory for binaries [PREFIX]
- --bindir=DIR directory for installing binaries [EXEC_PREFIX/bin]
- --sysconfdir=DIR directory to look for configuration file
- [PREFIX/etc]
- --mandir=DIR directory for installing man pages [PREFIX/share/man]
- --libdir=DIR directory for the rhash library [EXEC_PREFIX/lib]
- --pkgconfigdir=DIR directory for pkg-config files [LIBDIR/pkgconfig]
- --localedir=DIR directory for locale files [PREFIX/share/locale]
-
-Features options:
- --disable-FEATURE do not include FEATURE
- --enable-gettext enable gettext (localization) support [autodetect]
- --enable-openssl enable OpenSSL (optimized hash functions) support
- [autodetect]
- --enable-openssl-runtime load OpenSSL at runtime if present [autodetect]
- --enable-static statically link RHash binary
- --enable-lib-static build and install LibRHash static library [auto]
- --enable-lib-shared build and install LibRHash shared library [auto]
- --enable-symlinks[=LIST] install symlinks to the binary [enable]
-
-Use these options if autodetection fails:
- --extra-cflags=FLAGS extra CFLAGS
- --extra-ldflags=FLAGS extra LDFLAGS
-EOF
-exit 0
-}
-
-get_opt_value()
-{
- echo $(echo $* | cut -d '=' -f 2-)
-}
-
-for OPT do
- case "$OPT" in
- --help|-help|-h)
- print_help
- ;;
- --prefix=*)
- INSTALL_PREFIX=$(get_opt_value $OPT)
- ;;
- --exec-prefix=*)
- INSTALL_EXEC_PREFIX=$(get_opt_value $OPT)
- INSTALL_EXEC_PREFIX_SET=yes
- ;;
- --bindir=*)
- INSTALL_BINDIR=$(get_opt_value $OPT)
- ;;
- --mandir=*)
- INSTALL_MANDIR=$(get_opt_value $OPT)
- ;;
- --sysconfdir=*)
- INSTALL_SYSCONFDIR=$(get_opt_value $OPT)
- ;;
- --libdir=*)
- INSTALL_LIBDIR=$(get_opt_value $OPT)
- ;;
- --pkgconfigdir=*)
- INSTALL_PKGCONFIGDIR=$(get_opt_value $OPT)
- ;;
- --localedir=*)
- INSTALL_LOCALEDIR=$(get_opt_value $OPT)
- ;;
- --enable-gettext)
- OPT_GETTEXT=yes
- ;;
- --disable-gettext)
- OPT_GETTEXT=no
- ;;
- --enable-openssl)
- OPT_OPENSSL=yes
- ;;
- --disable-openssl)
- OPT_OPENSSL=no
- ;;
- --enable-openssl-runtime)
- OPT_OPENSSL_RUNTIME=yes
- ;;
- --disable-openssl-runtime)
- OPT_OPENSSL_RUNTIME=no
- ;;
- --target=*)
- BUILD_TARGET=$(get_opt_value $OPT)
- ;;
- --cc=*)
- CC=$(get_opt_value $OPT)
- ;;
- --ar=*)
- CMD_AR=$(get_opt_value $OPT)
- ;;
- --enable-static)
- BUILD_STATIC=yes
- ;;
- --disable-static)
- BUILD_STATIC=no
- ;;
- --enable-lib-static)
- INSTALL_LIB_STATIC=yes
- ;;
- --disable-lib-static)
- INSTALL_LIB_STATIC=no
- ;;
- --enable-lib-shared)
- INSTALL_LIB_SHARED=yes
- ;;
- --disable-lib-shared)
- INSTALL_LIB_SHARED=no
- ;;
- --enable-symlinks)
- # use default INSTALL_SYMLINKS list
- ;;
- --enable-symlinks=*)
- INSTALL_SYMLINKS=$(get_opt_value $OPT)
- ;;
- --disable-symlinks)
- INSTALL_SYMLINKS=
- ;;
- --enable-debug)
- BUILD_DEBUG='-g'
- ;;
- --enable-debug=*)
- BUILD_DEBUG='-g'$(get_opt_value $OPT)
- ;;
- --disable-debug)
- BUILD_DEBUG=
- ;;
- --with-install=*)
- CMD_INSTALL=$(get_opt_value $OPT)
- ;;
- --extra-cflags=*)
- BUILD_EXTRA_CFLAGS=$(get_opt_value $OPT)
- ;;
- --extra-ldflags=*)
- BUILD_EXTRA_LDFLAGS=$(get_opt_value $OPT)
- ;;
- *)
- echo "unknown option $OPT"
- exit 1
- ;;
- esac
- shift
-done
-
-# set variables which use INSTALL_PREFIX
-test -z "$INSTALL_EXEC_PREFIX_SET" && INSTALL_EXEC_PREFIX="$INSTALL_PREFIX"
-test -z "$INSTALL_BINDIR" && INSTALL_BINDIR="$INSTALL_EXEC_PREFIX/bin"
-test -z "$INSTALL_MANDIR" && INSTALL_MANDIR="$INSTALL_PREFIX/share/man"
-test -z "$INSTALL_SYSCONFDIR" && INSTALL_SYSCONFDIR="$INSTALL_PREFIX/etc"
-test -z "$INSTALL_INCDIR" && INSTALL_INCDIR="$INSTALL_PREFIX/include"
-test -z "$INSTALL_LIBDIR" && INSTALL_LIBDIR="$INSTALL_EXEC_PREFIX/lib"
-test -z "$INSTALL_PKGCONFIGDIR" && INSTALL_PKGCONFIGDIR="$INSTALL_LIBDIR/pkgconfig"
-test -z "$INSTALL_LOCALEDIR" && INSTALL_LOCALEDIR="$INSTALL_PREFIX/share/locale"
-
-# detect and prepare tmp directory
-for DETECT_TMP in "$TMPDIR" "$TEMPDIR" "/tmp" ; do
- test -d "$DETECT_TMP" && break
-done
-RANDNUM=$RANDOM
-test -z $RANDNUM && which jot >/dev/null && RANDNUM=$(jot -r 1 1 32767)
-BUILD_TMPDIR="$DETECT_TMP/rhash-configure-$RANDNUM-$$"
-mkdir $BUILD_TMPDIR || die "Unable to create tmp dir."
-TMPC="$BUILD_TMPDIR/tmp.c"
-TMPT="$BUILD_TMPDIR/tmp.txt"
-TMPBIN="$BUILD_TMPDIR/tmp"
-TMPLOG="config.log"
-rm -f "$TMPLOG"
-echo "Configuration parameters: \"$CFG_LINE\"" > "$TMPLOG"
-echo "Symlinks to install: $INSTALL_SYMLINKS" >> "$TMPLOG"
-echo >> "$TMPLOG"
-
-remove_tmpdir()
-{
- rm -rf "$BUILD_TMPDIR"
-}
-trap remove_tmpdir EXIT
-
-join_params()
-{
- printf '%s ' $@ | sed -e 's/ $//'
-}
-
-yn_nonempty()
-{
- test -n "$1" && echo yes || echo no;
-}
-
-# Use this before starting a check
-start_check() {
- echo "============ Checking for $1 ============" >> "$TMPLOG"
- printf '%s' "Checking for $1 ... "
- res_comment=""
-}
-
-# Use this to echo the results of a check
-finish_check() {
- if test "$res_comment" ; then
- res_comment="($res_comment)"
- fi
- echo "Result is: $1 $res_comment" >> "$TMPLOG"
- echo "=============================================" >> "$TMPLOG"
- echo "" >> "$TMPLOG"
- echo "$1 $res_comment"
- res_comment=""
-}
-
-# check source file compilation and return exit code
-compile_check() {
- source="$1"
- shift
- echo >> "$TMPLOG"
- echo "----- source file: $source -----" >> "$TMPLOG"
- cat "$source" >> "$TMPLOG"
- echo "----- end of file: $source -----" >> "$TMPLOG"
- echo "$CC $OPTFLAGS $WARN_CFLAGS $CFLAGS $source $BUILD_EXTRA_CFLAGS $BUILD_EXTRA_LDFLAGS $CHECK_LDFLAGS -o $TMPBIN $@" >> "$TMPLOG"
- rm -f "$TMPBIN"
- $CC $OPTFLAGS $WARN_CFLAGS $CFLAGS "$source" $BUILD_EXTRA_CFLAGS $BUILD_EXTRA_LDFLAGS $CHECK_LDFLAGS -o "$TMPBIN" "$@" >> "$TMPLOG" 2>&1
- TMPRES="$?"
- echo "Compilation result: $TMPRES" >> "$TMPLOG"
- echo >> "$TMPLOG"
- return "$TMPRES"
-}
-
-cc_check() {
- compile_check $TMPC $@
-}
-
-create_c_file() {
- rm -f "$TMPC"
- if test -n "$1"; then
- echo "#include <$1>" > $TMPC || die "Can't write to the $TMPC file"
- fi
-}
-
-cc_check_macro() {
- create_c_file "$1"
- cat >> $TMPC << EOF
-#ifndef $2
-#error condition not true: $2
-#endif
-int main(void) { return 0; }
-EOF
- shift 2
- cc_check $@
-}
-
-cc_check_cflag() {
- echo "int main(void) { return 0; }" > $TMPC
- cc_check $@
-}
-
-cc_check_headers() {
- rm -f "$TMPC"
- while test -n "$1"; do
- echo "#include <$1>" >> $TMPC
- shift
- done
- echo "int main(void) { return 0; }" >> $TMPC
- cc_check "-c"
-}
-
-cc_check_statement() {
- create_c_file "$1"
- cat >> $TMPC << EOF
-int main(void) {
- $2
- return 0;
-}
-EOF
- shift 2
- cc_check $@
-}
-
-# detect host and target OS
-start_check "target OS"
-HOST_OS=$(uname -s 2>&1)
-case "$HOST_OS" in
- Linux|FreeBSD|NetBSD|OpenBSD|DragonFly|BSD/OS|Darwin|SunOS|QNX|GNU|MorphOS|AIX|AmigaOS|Haiku)
- ;;
- IRIX*)
- HOST_OS=IRIX
- ;;
- GNU/kFreeBSD)
- HOST_OS=FreeBSD
- ;;
- HP-UX*)
- HOST_OS=HP-UX
- ;;
- MINGW32*)
- HOST_OS=MINGW32
- ;;
- MINGW64*)
- HOST_OS=MINGW64
- ;;
- MSYS*)
- HOST_OS=MSYS
- ;;
- [cC][yY][gG][wW][iI][nN]*)
- HOST_OS=CYGWIN
- ;;
- OS/2*)
- HOST_OS=OS/2
- ;;
- *)
- HOST_OS="$HOST_OS-UNKNOWN"
- ;;
-esac
-
-if test -z "$BUILD_TARGET" ; then
- # host's CPU/instruction set
- set_host_arch() {
- case "$1" in
- x86_64|amd64|i[3-9]86*|i86pc|x86|x86pc|k5|k6|k6_2|k6_3|k6-2|k6-3|pentium*|athlon*|i586_i686|i586-i686) HOST_ARCH=i386 ;;
- ia64) HOST_ARCH=ia64 ;;
- macppc|ppc*|Power*) HOST_ARCH=ppc ;;
- alpha) HOST_ARCH=alpha ;;
- sun4*|sparc*) HOST_ARCH=sparc ;;
- parisc*|hppa*|9000*) HOST_ARCH=hppa ;;
- aarch64*) HOST_ARCH=aarch64 ;;
- arm*|zaurus|cats) HOST_ARCH=arm ;;
- sh3|sh4|sh4a) HOST_ARCH=sh ;;
- s390) HOST_ARCH=s390 ;;
- s390x) HOST_ARCH=s390x ;;
- *mips*) HOST_ARCH=mips ;;
- nios2) HOST_ARCH=nios2 ;;
- vax) HOST_ARCH=vax ;;
- xtensa*) HOST_ARCH=xtensa ;;
- *) HOST_ARCH=UNKNOWN ;;
- esac
- }
- set_host_arch "$(uname -m 2>&1)"
- if test "$HOST_ARCH" = UNKNOWN ; then
- set_host_arch "$(uname -p 2>&1)"
- fi
- TARGET_OS="$HOST_OS"
- TARGET_ARCH="$HOST_ARCH"
-else
- set_target_os() {
- component=$1
- part=$(echo $BUILD_TARGET | cut -d '-' -f $component)
- case "$(echo $part | tr '[A-Z]' '[a-z]')" in
- linux) TARGET_OS=Linux ;;
- freebsd*) TARGET_OS=FreeBSD ;;
- gnu/kfreebsd) TARGET_OS=FreeBSD ;;
- netbsd) TARGET_OS=NetBSD ;;
- bsd/os) TARGET_OS=BSD/OS ;;
- openbsd) TARGET_OS=OpenBSD ;;
- dragonfly) TARGET_OS=DragonFly ;;
- sunos|solaris2.*) TARGET_OS=SunOS ;;
- qnx) TARGET_OS=QNX ;;
- morphos) TARGET_OS=MorphOS ;;
- amigaos) TARGET_OS=AmigaOS ;;
- mingw32*) TARGET_OS=MINGW32 ;;
- wine) TARGET_OS=Wine ;;
- darwin*) TARGET_OS=Darwin ;;
- esac
- }
- TARGET_OS="UNKNOWN"
- set_target_os 3
- if test "$TARGET_OS" = UNKNOWN ; then
- set_target_os 2
- fi
- TARGET_ARCH=$(echo $BUILD_TARGET | cut -d '-' -f 1)
- if test "$(echo $TARGET_ARCH)" != "x86_64" ; then
- TARGET_ARCH=$(echo $TARGET_ARCH | tr '_' '-')
- fi
-fi
-
-echo "Host OS : $HOST_OS" >> "$TMPLOG"
-echo "Target OS : $TARGET_OS" >> "$TMPLOG"
-echo "Target ARCH: $TARGET_ARCH" >> "$TMPLOG"
-finish_check "$TARGET_OS"
-test "$TARGET_OS" = UNKNOWN && die "Unknown target OS, please specify the --target option"
-
-OS_LC="$(echo $TARGET_OS | tr '[A-Z]' '[a-z]')"
-aix() { test "$OS_LC" = "aix"; }
-amigaos() { test "$OS_LC" = "amigaos"; }
-bsdos() { test "$OS_LC" = "bsd/os"; }
-darwin() { test "$OS_LC" = "darwin"; }
-dragonfly() { test "$OS_LC" = "dragonfly"; }
-freebsd() { test "$OS_LC" = "freebsd" || test "$OS_LC" = "gnu/kfreebsd"; }
-gnu() { test "$OS_LC" = "gnu"; }
-hpux() { test "$OS_LC" = "hp-ux"; }
-irix() { test "$OS_LC" = "irix"; }
-linux() { test "$OS_LC" = "linux"; }
-mingw32() { test "$OS_LC" = "mingw32"; }
-mingw64() { test "$OS_LC" = "mingw64"; }
-msys() { test "$OS_LC" = "msys"; }
-cygwin() { test "$OS_LC" = "cygwin"; }
-netbsd() { test "$OS_LC" = "netbsd"; }
-openbsd() { test "$OS_LC" = "openbsd"; }
-os2() { test "$OS_LC" = "os/2"; }
-qnx() { test "$OS_LC" = "qnx"; }
-sunos() { test "$OS_LC" = "sunos"; }
-wine() { test "$OS_LC" = "wine"; }
-win32() { cygwin || mingw32 || mingw64 || msys || wine; }
-posix_make() { aix || bsdos || hpux || irix || qnx || sunos; }
-
-# Checking CC version...
-# Intel C++ Compilers (no autoselect, use CC=/some/binary ./configure)
-cc_vendor=
-if test "$(basename $CC)" = "icc" || test "$(basename $CC)" = "ecc"; then
- start_check "$CC version"
- cc_vendor=intel
- cc_name=$($CC -V 2>&1 | head -n 1 | cut -d ',' -f 1)
- cc_version=$($CC -V 2>&1 | head -n 1 | cut -d ',' -f 2 | cut -d ' ' -f 3)
- _cc_major=$(echo $cc_version | cut -d '.' -f 1)
- _cc_minor=$(echo $cc_version | cut -d '.' -f 2)
- case $cc_version in
- '')
- cc_version="v. ?.??, bad"
- cc_fail=yes
- ;;
- 10.1|11.1|12.*|13.*)
- cc_version="$cc_version, ok"
- ;;
- *)
- cc_version="$cc_version, bad"
- cc_fail=yes
- ;;
- esac
- finish_check "$cc_version"
-else
- CC_TMP="$CC"
- for CC in "$CC_TMP" gcc cc ; do
- if $CC -v >/dev/null 2>&1; then
- cc_name_tmp=$($CC -v 2>&1 | tail -n 1 | cut -d ' ' -f 1)
- if test "$cc_name_tmp" = "gcc"; then
- cc_name=$cc_name_tmp
- start_check "$CC version"
- cc_vendor=gnu
- cc_version=$($CC -dumpversion 2>&1)
- if ! echo $cc_version | grep -q '^[0-9][0-9]*\.[0-9]'; then
- cc_v2=$($CC -dumpfullversion -dumpversion 2>/dev/null)
- if echo $cc_v2 | grep -q '^[0-9][0-9]*\.[0-9]'; then
- cc_version=$cc_v2
- fi
- fi
- case $cc_version in
- 2.96*)
- cc_fail=yes
- ;;
- *)
- _cc_major=$(echo $cc_version | cut -d '.' -f 1)
- _cc_minor=$(echo $cc_version | cut -d '.' -f 2)
- _cc_mini=$(echo $cc_version | cut -d '.' -f 3)
- ;;
- esac
- finish_check "$cc_name $cc_version"
- break
- fi
- if $CC -v 2>&1 | grep -q "clang"; then
- start_check "$CC version"
- cc_vendor=clang
- cc_version=$($CC -dumpversion 2>&1)
- finish_check "clang $cc_version"
- break
- fi
- cc_name_tmp=$($CC -V 2>&1 | head -n 1 | cut -d ' ' -f 2,3)
- if test "$cc_name_tmp" = "Sun C"; then
- start_check "$CC version"
- cc_vendor=sun
- cc_version=$($CC -V 2>&1 | head -n 1 | cut -d ' ' -f 4)
- res_comment="experimental support"
- finish_check "Sun C $cc_version"
- break
- fi
- fi
- done
-fi # icc
-test -z "$cc_vendor" && die "compiler not found"
-test "$cc_fail" = "yes" && die "unsupported compiler version"
-
-if test "$cc_name" = "gcc" && test "$_cc_major" -gt 3; then
- WARN_CFLAGS="$WARN_CFLAGS -Wdeclaration-after-statement"
-fi
-
-# select optimization flags
-has_optimization()
-{
- # posix-compatible way to find -O option
- for OPT in $BUILD_EXTRA_CFLAGS; do
- case "$OPT" in
- -O[0-3]|-O) return 0 ;;
- esac
- done
- return 1
-}
-has_optimization && OPTLEVEL= || OPTLEVEL="-O2"
-OPTFLAGS="-pipe -DNDEBUG -fomit-frame-pointer -ffunction-sections -fdata-sections"
-OPTFLAGS=$(join_params $BUILD_DEBUG $OPTLEVEL $OPTFLAGS)
-
-# detect proper shared library name
-SHARED_PREFIX="lib"
-STATIC_PREFIX="lib"
-SHARED_EXT=".so.0"
-STATIC_EXT=".a"
-SOLINK_EXT=".so"
-EXEC_EXT=
-NEED_IMPLIB=no
-NEED_SOLINK=yes
-INSTALL_SO_DIR=$INSTALL_LIBDIR
-LN_S="ln -sf"
-if win32; then
- LN_S="cp -pR"
- EXEC_EXT=".exe"
- SHARED_EXT=".dll"
- NEED_IMPLIB=yes
- NEED_SOLINK=no
- INSTALL_SO_DIR=$INSTALL_BINDIR
- if msys; then
- SHARED_PREFIX="msys-"
- elif cygwin; then
- SHARED_PREFIX="cyg"
- fi
-elif darwin; then
- SHARED_EXT=".0.dylib"
- SOLINK_EXT=".dylib"
-fi
-
-# check for linker flags
-LD_STATIC=-static
-test "$BUILD_STATIC" = "auto" && BUILD_STATIC=no
-test "$OPT_OPENSSL_RUNTIME" = "yes" && ! win32 && LD_STATIC=
-if test -n "$LD_STATIC"; then
- start_check "linker support for $LD_STATIC"
- if cc_check_cflag "$LD_STATIC"; then
- test "$BUILD_STATIC" = "yes" && CHECK_LDFLAGS=$LD_STATIC
- else
- LD_STATIC=
- fi
- finish_check $(yn_nonempty "$LD_STATIC")
-fi
-test "$OPT_OPENSSL_RUNTIME" = "auto" && test "$BUILD_STATIC" = "yes" && ! win32 && OPT_OPENSSL_RUNTIME=no
-
-ALLOW_RUNTIME_LINKING=yes
-LIBDL_LDFLAGS=
-if ! win32 && test "$OPT_OPENSSL_RUNTIME" != "no"; then
- start_check "linker support for dlopen"
- ALLOW_RUNTIME_LINKING=no
- if cc_check_statement "dlfcn.h" 'dlopen("", RTLD_NOW);'; then
- ALLOW_RUNTIME_LINKING=yes
- elif cc_check_statement "dlfcn.h" 'dlopen("", RTLD_NOW);' "-ldl"; then
- ALLOW_RUNTIME_LINKING=yes
- LIBDL_LDFLAGS="-ldl"
- fi
- finish_check "$ALLOW_RUNTIME_LINKING"
-fi
-
-SHARED_VSCRIPT=
-if ! darwin; then
- start_check "linker support for --version-script"
- echo "{ local: *; };" > $TMPT
- cc_check_cflag "-Wl,--version-script,$TMPT -shared" &&
- SHARED_VSCRIPT=",--version-script,exports.sym"
- finish_check $(yn_nonempty "$SHARED_VSCRIPT")
-fi
-
-WIN_LDFLAGS=
-if win32; then
- start_check "linker support for --nxcompat --no-seh --dynamicbase"
- cc_check_cflag "-Wl,--nxcompat,--no-seh,--dynamicbase" &&
- WIN_LDFLAGS="-Wl,--nxcompat,--no-seh,--dynamicbase"
- finish_check $(yn_nonempty "$WIN_LDFLAGS")
-fi
-
-# detect library names and build flags
-LIBRHASH_SHARED="${SHARED_PREFIX}rhash${SHARED_EXT}"
-LIBRHASH_STATIC="${STATIC_PREFIX}rhash${STATIC_EXT}"
-LIBRHASH_SOLINK="${SHARED_PREFIX}rhash${SOLINK_EXT}"
-LIBRHASH_SOLINK_TARGET=
-test "$NEED_SOLINK" = "yes" && LIBRHASH_SOLINK_TARGET=$LIBRHASH_SOLINK
-LIBRHASH_DEF="${SHARED_PREFIX}rhash.def"
-LIBRHASH_IMPLIB="${STATIC_PREFIX}rhash${SHARED_EXT}${STATIC_EXT}"
-LIBRHASH_EXPORTS_FILE="exports.sym"
-LIBRHASH_EXPORTS_TARGET=
-LIBRHASH_SH_CFLAGS=""
-LIBRHASH_SH_LDFLAGS=""
-LIBRHASH_RM_FILES=
-LIBRHASH_LEGACY_HEADERS=
-if win32; then
- LIBRHASH_SH_CFLAGS="-DRHASH_EXPORTS"
- LIBRHASH_SH_LDFLAGS="-shared -Wl,--out-implib=${LIBRHASH_IMPLIB}${SHARED_VSCRIPT},--output-def,${LIBRHASH_DEF}"
- test -n "$SHARED_VSCRIPT" && LIBRHASH_EXPORTS_TARGET=$LIBRHASH_EXPORTS_FILE
- LIBRHASH_RM_FILES="${LIBRHASH_IMPLIB} ${LIBRHASH_DEF}"
-elif darwin; then
- LIBRHASH_SH_CFLAGS="-fpic"
- LIBRHASH_SH_LDFLAGS='-dynamiclib -Wl,-install_name,$(LIBDIR)/$@'
-else
- LIBRHASH_LEGACY_HEADERS="rhash_timing.h"
- LIBRHASH_SH_CFLAGS="-fpic"
- LIBRHASH_SH_LDFLAGS="-shared -Wl${SHARED_VSCRIPT},-soname,\$(LIBRHASH_SHARED)"
- test -n "$SHARED_VSCRIPT" && LIBRHASH_EXPORTS_TARGET=$LIBRHASH_EXPORTS_FILE
-fi
-LIBRHASH_RM_FILES=$(join_params $LIBRHASH_RM_FILES $LIBRHASH_EXPORTS_TARGET $LIBRHASH_SOLINK_TARGET)
-
-RHASH_DEFINES=
-LIBRHASH_DEFINES=
-GETTEXT_LDFLAGS=
-OPENSSL_LDFLAGS=
-if test "$OPT_GETTEXT" != "no"; then
- start_check "gettext"
- GETTEXT_FOUND=no
- if cc_check_headers "libintl.h"; then
- if cc_check_statement "libintl.h" "gettext(\"\");"; then
- GETTEXT_FOUND=found
- elif cc_check_statement "libintl.h" "gettext(\"\");" "-lintl"; then
- GETTEXT_LDFLAGS="-lintl"
- GETTEXT_FOUND=found
- elif cc_check_statement "libintl.h" "gettext(\"\");" "-lintl -liconv"; then
- GETTEXT_LDFLAGS="-lintl -liconv"
- GETTEXT_FOUND=found
- fi
- fi
- test "$GETTEXT_FOUND" = "found" && RHASH_DEFINES=$(join_params $RHASH_DEFINES -DUSE_GETTEXT)
- finish_check $GETTEXT_FOUND
- test "$OPT_GETTEXT" = "yes" && test "$GETTEXT_FOUND" = "no" && die "gettext library not found"
-fi
-
-if test "$OPT_OPENSSL" != "no"; then
- start_check "OpenSSL"
- test "$OPT_OPENSSL" = "auto" && test "$OPT_OPENSSL_RUNTIME" = "yes" && OPT_OPENSSL=yes
- OPENSSL_FOUND=no
- if test "$ALLOW_RUNTIME_LINKING" = "no"; then
- echo "No runtime library loading, because dlopen() is not found!" >> "$TMPLOG"
- test "$OPT_OPENSSL_RUNTIME" = "yes" && die "dlopen() is required for OpenSSL runtime loading"
- OPT_OPENSSL_RUNTIME=no
- fi
- OPENSSL_HEADERS="openssl/opensslconf.h openssl/md4.h openssl/md5.h openssl/sha.h"
- if cc_check_headers $OPENSSL_HEADERS; then
- if test "$OPT_OPENSSL_RUNTIME" != "no"; then
- OPENSSL_FOUND=runtime
- LIBRHASH_DEFINES=$(join_params $LIBRHASH_DEFINES -DOPENSSL_RUNTIME)
- OPENSSL_LDFLAGS="$LIBDL_LDFLAGS"
- # note: libdl should disable -static
- test -n "$LIBDL_LDFLAGS" && LD_STATIC=
- elif win32 && cc_check_statement "openssl/md5.h" "MD5_Init(NULL);" "-leay32"; then
- OPENSSL_FOUND=found
- LIBRHASH_DEFINES=$(join_params $LIBRHASH_DEFINES -DUSE_OPENSSL)
- OPENSSL_LDFLAGS="-leay32"
- elif cc_check_statement "openssl/md5.h" "MD5_Init(NULL);" "-lcrypto"; then
- OPENSSL_FOUND=found
- LIBRHASH_DEFINES=$(join_params $LIBRHASH_DEFINES -DUSE_OPENSSL)
- OPENSSL_LDFLAGS="-lcrypto"
- fi
- fi
- finish_check $OPENSSL_FOUND
- test "$OPT_OPENSSL" = "yes" && test "$OPENSSL_FOUND" = "no" && die "OpenSSL library not found"
-fi
-
-# building of static/shared binary an library
-RHASH_STATIC=rhash_static
-RHASH_SHARED=rhash_shared
-RHASH_BUILD_TARGETS=
-RHASH_EXTRA_INSTALL=
-LIBRHASH_BUILD_TARGETS=
-LIBRHASH_TEST_TARGETS=
-EXTRA_INSTALL_LIBSHARED=
-EXTRA_UNINSTALL_LIBSHARED=
-if test "$BUILD_STATIC" = "yes"; then
- RHASH_STATIC=rhash
- RHASH_BUILD_TYPE=static
- RHASH_BUILD_TARGETS="\$(RHASH_STATIC)"
- test "$INSTALL_LIB_SHARED" = "yes" && RHASH_BUILD_TARGETS="$RHASH_BUILD_TARGETS \$(LIBRHASH_SHARED)"
-else
- RHASH_SHARED=rhash
- RHASH_BUILD_TYPE=shared
- RHASH_BUILD_TARGETS="\$(RHASH_SHARED)"
- test "$INSTALL_LIB_SHARED" = "auto" && INSTALL_LIB_SHARED=yes
- test "$INSTALL_LIB_STATIC" = "yes" && RHASH_BUILD_TARGETS="$RHASH_BUILD_TARGETS \$(LIBRHASH_STATIC)"
-fi
-if test "$INSTALL_LIB_STATIC" = "yes"; then
- RHASH_EXTRA_INSTALL=$(join_params $RHASH_EXTRA_INSTALL install-lib-static)
- LIBRHASH_BUILD_TARGETS=$LIBRHASH_STATIC
- LIBRHASH_TEST_TARGETS=test-static
-fi
-if test "$NEED_IMPLIB" = "yes"; then
- EXTRA_INSTALL_LIBSHARED="install-implib"
- EXTRA_UNINSTALL_LIBSHARED="uninstall-implib"
-fi
-if test "$INSTALL_LIB_SHARED" = "yes"; then
- RHASH_EXTRA_INSTALL=$(join_params $RHASH_EXTRA_INSTALL install-lib-shared)
- LIBRHASH_BUILD_TARGETS=$(join_params $LIBRHASH_BUILD_TARGETS $LIBRHASH_SHARED)
- LIBRHASH_TEST_TARGETS=$(join_params $LIBRHASH_TEST_TARGETS test-shared)
-fi
-
-# check for old POSIX make
-posix_make && Q_ASSIGN="=" || Q_ASSIGN="?="
-
-# detect source directories
-start_check "sources"
-HAS_RHASH=no
-HAS_LIBRHASH=no
-HAS_BINDINGS=no
-RHASH_VERSION=
-BINDINGS_VERSION=
-RHASH_SRC=
-LIBRHASH_SRC=
-LIBRHASH_PC=
-BINDINGS_SRC=
-SRC_FOUND=no
-test -f Makefile || die "Makefile not found"
-if test -f rhash_main.c; then
- HAS_RHASH=yes
- SRC_FOUND=RHash
- if test -d librhash; then
- HAS_LIBRHASH=yes
- LIBRHASH_SRC=librhash/
- fi
- if test -f bindings/version.properties; then
- HAS_BINDINGS=yes
- BINDINGS_SRC=bindings/
- fi
-elif test -f rhash.c; then
- HAS_LIBRHASH=yes
- SRC_FOUND=LibRHash
-elif test -f version.properties; then
- HAS_BINDINGS=yes
- SRC_FOUND="RHash bindings"
-fi
-echo "RHASH_SRC=$RHASH_SRC, LIBRHASH_SRC=$LIBRHASH_SRC, BINDINGS_SRC=$BINDINGS_SRC" >> "$TMPLOG"
-
-# check version
-good_version() { echo "$1" | grep -q '^[1-9]\.[1-9][0-9]*\.[1-9]' ; }
-if test "$HAS_RHASH" = "yes"; then
- test -f "${RHASH_SRC}version.h" || die "${RHASH_SRC}version.h not found"
- RHASH_VERSION=$(cut -d'"' -f2 "${RHASH_SRC}version.h")
- echo "RHASH_VERSION=$RHASH_VERSION" >> "$TMPLOG"
- good_version "$RHASH_VERSION" || die "wrong version: $RHASH_VERSION"
- test "$HAS_LIBRHASH" = "yes" && LIBRHASH_PC=dist/librhash.pc
-fi
-if test "$HAS_BINDINGS" = "yes"; then
- BINDINGS_VERSION=$(cut -d = -f 2 "${BINDINGS_SRC}version.properties")
- echo "BINDINGS_VERSION=$BINDINGS_VERSION" >> "$TMPLOG"
- good_version "$BINDINGS_VERSION" || die "wrong bindings version: $BINDINGS_VERSION"
- test -z "$RHASH_VERSION" && RHASH_VERSION="$BINDINGS_VERSION"
-fi
-test -n "$RHASH_VERSION" && SRC_FOUND="$SRC_FOUND $RHASH_VERSION"
-finish_check "$SRC_FOUND"
-test "$SRC_FOUND" = "no" && die "sources not found"
-
-if test "$HAS_BINDINGS" = "yes" && test "$BINDINGS_VERSION" != "$RHASH_VERSION"; then
- echo "Updating ${BINDINGS_SRC}version.properties"
- echo "version=$RHASH_VERSION" > ${BINDINGS_SRC}version.properties
-fi
-
-if test "$HAS_RHASH" = "yes"; then
- echo "Writing ${RHASH_SRC}config.mak"
- cat > ${RHASH_SRC}config.mak << EOF
-# -------- Generated by configure -----------
-
-DESTDIR $Q_ASSIGN
-BINDIR = \$(DESTDIR)$INSTALL_BINDIR
-SYSCONFDIR = \$(DESTDIR)$INSTALL_SYSCONFDIR
-MANDIR = \$(DESTDIR)$INSTALL_MANDIR
-PKGCONFIGDIR = \$(DESTDIR)$INSTALL_PKGCONFIGDIR
-LOCALEDIR = \$(DESTDIR)$INSTALL_LOCALEDIR
-
-AR = $CMD_AR
-CC = $CC
-INSTALL = $CMD_INSTALL
-
-LIBRHASH_STATIC = librhash/$LIBRHASH_STATIC
-LIBRHASH_SHARED = librhash/$LIBRHASH_SHARED
-BUILD_TYPE = $RHASH_BUILD_TYPE
-VERSION = $RHASH_VERSION
-EXEC_EXT = $EXEC_EXT
-RHASH_STATIC = $RHASH_STATIC\$(EXEC_EXT)
-RHASH_SHARED = $RHASH_SHARED\$(EXEC_EXT)
-BUILD_TARGETS = $RHASH_BUILD_TARGETS
-EXTRA_INSTALL = $RHASH_EXTRA_INSTALL
-SYMLINKS = $INSTALL_SYMLINKS
-LN_S = $LN_S
-
-OPTFLAGS = $OPTFLAGS
-OPTLDFLAGS = $WIN_LDFLAGS
-WARN_CFLAGS = $WARN_CFLAGS
-ADDCFLAGS = $BUILD_EXTRA_CFLAGS
-ADDLDFLAGS = $BUILD_EXTRA_LDFLAGS
-CFLAGS = $RHASH_DEFINES \$(OPTFLAGS) \$(WARN_CFLAGS) \$(ADDCFLAGS)
-LDFLAGS = \$(OPTLDFLAGS) \$(ADDLDFLAGS) $GETTEXT_LDFLAGS
-BIN_STATIC_LDFLAGS = \$(LDFLAGS) $(join_params $LD_STATIC $OPENSSL_LDFLAGS)
-
-EOF
-fi
-
-
-if test "$HAS_LIBRHASH" = "yes"; then
- echo "Writing ${LIBRHASH_SRC}config.mak"
- cat > ${LIBRHASH_SRC}config.mak << EOF
-# -------- Generated by configure -----------
-
-DESTDIR $Q_ASSIGN
-INCDIR = \$(DESTDIR)$INSTALL_INCDIR
-LIBDIR = \$(DESTDIR)$INSTALL_LIBDIR
-SO_DIR = \$(DESTDIR)$INSTALL_SO_DIR
-
-AR = $CMD_AR
-CC = $CC
-INSTALL = $CMD_INSTALL
-
-LIBRHASH_STATIC = $LIBRHASH_STATIC
-LIBRHASH_SHARED = $LIBRHASH_SHARED
-LIBRHASH_SOLINK = $LIBRHASH_SOLINK
-LIBRHASH_DEF = $LIBRHASH_DEF
-LIBRHASH_IMPLIB = $LIBRHASH_IMPLIB
-EXPORTS_FILE = $LIBRHASH_EXPORTS_FILE
-RM_FILES = $LIBRHASH_RM_FILES
-BUILD_TYPE = $RHASH_BUILD_TYPE
-EXEC_EXT = $EXEC_EXT
-LEGACY_HEADERS = $LIBRHASH_LEGACY_HEADERS
-
-EXPORTS_TARGET = $LIBRHASH_EXPORTS_TARGET
-BUILD_TARGETS = $LIBRHASH_BUILD_TARGETS
-TEST_TARGETS = $LIBRHASH_TEST_TARGETS
-SOLINK_TARGET = $LIBRHASH_SOLINK_TARGET
-EXTRA_INSTALL_LIBSHARED = $EXTRA_INSTALL_LIBSHARED
-EXTRA_UNINSTALL_LIBSHARED = $EXTRA_UNINSTALL_LIBSHARED
-
-OPTFLAGS = $OPTFLAGS
-OPTLDFLAGS = $WIN_LDFLAGS
-WARN_CFLAGS = $WARN_CFLAGS
-ADDCFLAGS = $BUILD_EXTRA_CFLAGS
-ADDLDFLAGS = $BUILD_EXTRA_LDFLAGS
-CFLAGS = $LIBRHASH_DEFINES \$(OPTFLAGS) \$(WARN_CFLAGS) \$(ADDCFLAGS)
-LDFLAGS = \$(OPTLDFLAGS) \$(ADDLDFLAGS)
-SHARED_CFLAGS = \$(CFLAGS) $LIBRHASH_SH_CFLAGS
-SHARED_LDFLAGS = \$(LDFLAGS) $(join_params $OPENSSL_LDFLAGS $LIBRHASH_SH_LDFLAGS)
-BIN_STATIC_LDFLAGS = \$(LDFLAGS) $(join_params $LD_STATIC $OPENSSL_LDFLAGS)
-
-EOF
-fi
-
-if test -n "$LIBRHASH_PC"; then
- PC_EXC="$INSTALL_EXEC_PREFIX"
- PC_INC="$INSTALL_INCDIR"
- PC_LIB="$INSTALL_LIBDIR"
- test "$PC_EXC" = "${INSTALL_PREFIX}" && PC_EXC='${prefix}'
- test "$PC_INC" = "${INSTALL_PREFIX}/include" && PC_INC='${prefix}/include'
- test "$PC_LIB" = "${INSTALL_EXEC_PREFIX}/lib" && PC_LIB='${exec_prefix}/lib'
- echo "Writing ${LIBRHASH_PC}"
- cat > $LIBRHASH_PC << EOF
-prefix=${INSTALL_PREFIX}
-exec_prefix=${PC_EXC}
-libdir=${PC_LIB}
-includedir=${PC_INC}
-
-Name: librash
-Description: LibRHash shared library
-Version: ${RHASH_VERSION}
-Cflags: -I\${includedir}
-Libs: -L\${libdir} -lrhash
-Libs.private: ${OPENSSL_LDFLAGS}
-
-EOF
-fi
+#!/bin/sh
+
+# set default values
+OPT_OPENSSL=auto
+OPT_OPENSSL_RUNTIME=auto
+OPT_GETTEXT=auto
+
+export LC_ALL=C
+CFG_LINE="$*"
+INSTALL_PREFIX="/usr/local"
+test -z "$CC" && CC=cc
+CMD_AR=ar
+CMD_INSTALL=install
+BUILD_DEBUG=
+BUILD_STATIC=auto
+BUILD_EXTRA_CFLAGS=
+BUILD_EXTRA_LDFLAGS=
+CHECK_LDFLAGS=
+WARN_CFLAGS="-Wall -W -Wstrict-prototypes -Wnested-externs -Winline -Wpointer-arith -Wbad-function-cast -Wmissing-prototypes -Wmissing-declarations"
+INSTALL_SYMLINKS="sfv-hash tiger-hash tth-hash whirlpool-hash has160-hash gost-hash edonr256-hash edonr512-hash ed2k-link magnet-link"
+INSTALL_LIB_STATIC=auto
+INSTALL_LIB_SHARED=auto
+INSTALL_PKGCONFIGDIR="$PKG_INSTALLDIR"
+
+# display error message and exit
+die () {
+ echo
+ echo "Error: $@" >&2
+ echo >&2
+ test -f "$TMPLOG" && echo "Error: $@" >> "$TMPLOG"
+ rm -f "$TMPBIN" "$TMPC" "$TMPT"
+ echo "Check \"$TMPLOG\" if you do not understand why it failed."
+ exit 1
+}
+
+print_help()
+{
+ cat << EOF
+Usage: configure [OPTIONS]...
+
+Generic Options:
+ -h, --help display this help and exit
+ --cc=COMPILER C compiler to build RHash [gcc]
+ --ar=AR librarian to build RHash [ar]
+ --target=PLATFORM target platform (i386-linux, arm-linux, etc)
+ --with-install=PATH path to a custom install program
+
+Directory Options:
+ --prefix=DIR prefix directory for installation [/usr/local]
+ --exec-prefix=DIR prefix directory for binaries [PREFIX]
+ --bindir=DIR directory for installing binaries [EXEC_PREFIX/bin]
+ --sysconfdir=DIR directory to look for configuration file
+ [PREFIX/etc]
+ --mandir=DIR directory for installing man pages [PREFIX/share/man]
+ --libdir=DIR directory for the rhash library [EXEC_PREFIX/lib]
+ --pkgconfigdir=DIR directory for pkg-config files [LIBDIR/pkgconfig]
+ --localedir=DIR directory for locale files [PREFIX/share/locale]
+
+Features options:
+ --disable-FEATURE do not include FEATURE
+ --enable-gettext enable gettext (localization) support [autodetect]
+ --enable-openssl enable OpenSSL (optimized hash functions) support
+ [autodetect]
+ --enable-openssl-runtime load OpenSSL at runtime if present [autodetect]
+ --enable-static statically link RHash binary
+ --enable-lib-static build and install LibRHash static library [auto]
+ --enable-lib-shared build and install LibRHash shared library [auto]
+ --enable-symlinks[=LIST] install symlinks to the binary [enable]
+
+Use these options if autodetection fails:
+ --extra-cflags=FLAGS extra CFLAGS
+ --extra-ldflags=FLAGS extra LDFLAGS
+EOF
+exit 0
+}
+
+get_opt_value()
+{
+ echo $(echo $* | cut -d '=' -f 2-)
+}
+
+for OPT do
+ case "$OPT" in
+ --help|-help|-h)
+ print_help
+ ;;
+ --prefix=*)
+ INSTALL_PREFIX=$(get_opt_value $OPT)
+ ;;
+ --exec-prefix=*)
+ INSTALL_EXEC_PREFIX=$(get_opt_value $OPT)
+ INSTALL_EXEC_PREFIX_SET=yes
+ ;;
+ --bindir=*)
+ INSTALL_BINDIR=$(get_opt_value $OPT)
+ ;;
+ --mandir=*)
+ INSTALL_MANDIR=$(get_opt_value $OPT)
+ ;;
+ --sysconfdir=*)
+ INSTALL_SYSCONFDIR=$(get_opt_value $OPT)
+ ;;
+ --libdir=*)
+ INSTALL_LIBDIR=$(get_opt_value $OPT)
+ ;;
+ --pkgconfigdir=*)
+ INSTALL_PKGCONFIGDIR=$(get_opt_value $OPT)
+ ;;
+ --localedir=*)
+ INSTALL_LOCALEDIR=$(get_opt_value $OPT)
+ ;;
+ --enable-gettext)
+ OPT_GETTEXT=yes
+ ;;
+ --disable-gettext)
+ OPT_GETTEXT=no
+ ;;
+ --enable-openssl)
+ OPT_OPENSSL=yes
+ ;;
+ --disable-openssl)
+ OPT_OPENSSL=no
+ ;;
+ --enable-openssl-runtime)
+ OPT_OPENSSL_RUNTIME=yes
+ ;;
+ --disable-openssl-runtime)
+ OPT_OPENSSL_RUNTIME=no
+ ;;
+ --target=*)
+ BUILD_TARGET=$(get_opt_value $OPT)
+ ;;
+ --cc=*)
+ CC=$(get_opt_value $OPT)
+ ;;
+ --ar=*)
+ CMD_AR=$(get_opt_value $OPT)
+ ;;
+ --enable-static)
+ BUILD_STATIC=yes
+ ;;
+ --disable-static)
+ BUILD_STATIC=no
+ ;;
+ --enable-lib-static)
+ INSTALL_LIB_STATIC=yes
+ ;;
+ --disable-lib-static)
+ INSTALL_LIB_STATIC=no
+ ;;
+ --enable-lib-shared)
+ INSTALL_LIB_SHARED=yes
+ ;;
+ --disable-lib-shared)
+ INSTALL_LIB_SHARED=no
+ ;;
+ --enable-symlinks)
+ # use default INSTALL_SYMLINKS list
+ ;;
+ --enable-symlinks=*)
+ INSTALL_SYMLINKS=$(get_opt_value $OPT)
+ ;;
+ --disable-symlinks)
+ INSTALL_SYMLINKS=
+ ;;
+ --enable-debug)
+ BUILD_DEBUG='-g'
+ ;;
+ --enable-debug=*)
+ BUILD_DEBUG='-g'$(get_opt_value $OPT)
+ ;;
+ --disable-debug)
+ BUILD_DEBUG=
+ ;;
+ --with-install=*)
+ CMD_INSTALL=$(get_opt_value $OPT)
+ ;;
+ --extra-cflags=*)
+ BUILD_EXTRA_CFLAGS=$(get_opt_value $OPT)
+ ;;
+ --extra-ldflags=*)
+ BUILD_EXTRA_LDFLAGS=$(get_opt_value $OPT)
+ ;;
+ *)
+ echo "unknown option $OPT"
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+# set variables which use INSTALL_PREFIX
+test -z "$INSTALL_EXEC_PREFIX_SET" && INSTALL_EXEC_PREFIX="$INSTALL_PREFIX"
+test -z "$INSTALL_BINDIR" && INSTALL_BINDIR="$INSTALL_EXEC_PREFIX/bin"
+test -z "$INSTALL_MANDIR" && INSTALL_MANDIR="$INSTALL_PREFIX/share/man"
+test -z "$INSTALL_SYSCONFDIR" && INSTALL_SYSCONFDIR="$INSTALL_PREFIX/etc"
+test -z "$INSTALL_INCDIR" && INSTALL_INCDIR="$INSTALL_PREFIX/include"
+test -z "$INSTALL_LIBDIR" && INSTALL_LIBDIR="$INSTALL_EXEC_PREFIX/lib"
+test -z "$INSTALL_PKGCONFIGDIR" && INSTALL_PKGCONFIGDIR="$INSTALL_LIBDIR/pkgconfig"
+test -z "$INSTALL_LOCALEDIR" && INSTALL_LOCALEDIR="$INSTALL_PREFIX/share/locale"
+
+# detect and prepare tmp directory
+for DETECT_TMP in "$TMPDIR" "$TEMPDIR" "/tmp" ; do
+ test -d "$DETECT_TMP" && break
+done
+RANDNUM=$RANDOM
+test -z $RANDNUM && which jot >/dev/null && RANDNUM=$(jot -r 1 1 32767)
+BUILD_TMPDIR="$DETECT_TMP/rhash-configure-$RANDNUM-$$"
+mkdir $BUILD_TMPDIR || die "Unable to create tmp dir."
+TMPC="$BUILD_TMPDIR/tmp.c"
+TMPT="$BUILD_TMPDIR/tmp.txt"
+TMPBIN="$BUILD_TMPDIR/tmp"
+TMPLOG="config.log"
+rm -f "$TMPLOG"
+echo "Configuration parameters: \"$CFG_LINE\"" > "$TMPLOG"
+echo "Symlinks to install: $INSTALL_SYMLINKS" >> "$TMPLOG"
+echo >> "$TMPLOG"
+
+remove_tmpdir()
+{
+ rm -rf "$BUILD_TMPDIR"
+}
+trap remove_tmpdir EXIT
+
+join_params()
+{
+ printf '%s ' $@ | sed -e 's/ $//'
+}
+
+yn_nonempty()
+{
+ test -n "$1" && echo yes || echo no;
+}
+
+# Use this before starting a check
+start_check() {
+ echo "============ Checking for $1 ============" >> "$TMPLOG"
+ printf '%s' "Checking for $1 ... "
+ res_comment=""
+}
+
+# Use this to echo the results of a check
+finish_check() {
+ if test "$res_comment" ; then
+ res_comment="($res_comment)"
+ fi
+ echo "Result is: $1 $res_comment" >> "$TMPLOG"
+ echo "=============================================" >> "$TMPLOG"
+ echo "" >> "$TMPLOG"
+ echo "$1 $res_comment"
+ res_comment=""
+}
+
+# check source file compilation and return exit code
+compile_check() {
+ source="$1"
+ shift
+ echo >> "$TMPLOG"
+ echo "----- source file: $source -----" >> "$TMPLOG"
+ cat "$source" >> "$TMPLOG"
+ echo "----- end of file: $source -----" >> "$TMPLOG"
+ echo "$CC $OPTFLAGS $WARN_CFLAGS $CFLAGS $source $BUILD_EXTRA_CFLAGS $BUILD_EXTRA_LDFLAGS $CHECK_LDFLAGS -o $TMPBIN $@" >> "$TMPLOG"
+ rm -f "$TMPBIN"
+ $CC $OPTFLAGS $WARN_CFLAGS $CFLAGS "$source" $BUILD_EXTRA_CFLAGS $BUILD_EXTRA_LDFLAGS $CHECK_LDFLAGS -o "$TMPBIN" "$@" >> "$TMPLOG" 2>&1
+ TMPRES="$?"
+ echo "Compilation result: $TMPRES" >> "$TMPLOG"
+ echo >> "$TMPLOG"
+ return "$TMPRES"
+}
+
+cc_check() {
+ compile_check $TMPC $@
+}
+
+create_c_file() {
+ rm -f "$TMPC"
+ if test -n "$1"; then
+ echo "#include <$1>" > $TMPC || die "Can't write to the $TMPC file"
+ fi
+}
+
+cc_check_macro() {
+ create_c_file "$1"
+ cat >> $TMPC << EOF
+#ifndef $2
+#error condition not true: $2
+#endif
+int main(void) { return 0; }
+EOF
+ shift 2
+ cc_check $@
+}
+
+cc_check_cflag() {
+ echo "int main(void) { return 0; }" > $TMPC
+ cc_check $@
+}
+
+cc_check_headers() {
+ rm -f "$TMPC"
+ while test -n "$1"; do
+ echo "#include <$1>" >> $TMPC
+ shift
+ done
+ echo "int main(void) { return 0; }" >> $TMPC
+ cc_check "-c"
+}
+
+cc_check_statement() {
+ create_c_file "$1"
+ cat >> $TMPC << EOF
+int main(void) {
+ $2
+ return 0;
+}
+EOF
+ shift 2
+ cc_check $@
+}
+
+# detect host and target OS
+start_check "target OS"
+HOST_OS=$(uname -s 2>&1)
+case "$HOST_OS" in
+ Linux|FreeBSD|NetBSD|OpenBSD|DragonFly|BSD/OS|Darwin|SunOS|QNX|GNU|MorphOS|AIX|AmigaOS|Haiku)
+ ;;
+ IRIX*)
+ HOST_OS=IRIX
+ ;;
+ GNU/kFreeBSD)
+ HOST_OS=FreeBSD
+ ;;
+ HP-UX*)
+ HOST_OS=HP-UX
+ ;;
+ MINGW32*)
+ HOST_OS=MINGW32
+ ;;
+ MINGW64*)
+ HOST_OS=MINGW64
+ ;;
+ MSYS*)
+ HOST_OS=MSYS
+ ;;
+ [cC][yY][gG][wW][iI][nN]*)
+ HOST_OS=CYGWIN
+ ;;
+ OS/2*)
+ HOST_OS=OS/2
+ ;;
+ *)
+ HOST_OS="$HOST_OS-UNKNOWN"
+ ;;
+esac
+
+if test -z "$BUILD_TARGET" ; then
+ # host's CPU/instruction set
+ set_host_arch() {
+ case "$1" in
+ x86_64|amd64|i[3-9]86*|i86pc|x86|x86pc|k5|k6|k6_2|k6_3|k6-2|k6-3|pentium*|athlon*|i586_i686|i586-i686) HOST_ARCH=i386 ;;
+ ia64) HOST_ARCH=ia64 ;;
+ macppc|ppc*|Power*) HOST_ARCH=ppc ;;
+ alpha) HOST_ARCH=alpha ;;
+ sun4*|sparc*) HOST_ARCH=sparc ;;
+ parisc*|hppa*|9000*) HOST_ARCH=hppa ;;
+ aarch64*) HOST_ARCH=aarch64 ;;
+ arm*|zaurus|cats) HOST_ARCH=arm ;;
+ sh3|sh4|sh4a) HOST_ARCH=sh ;;
+ s390) HOST_ARCH=s390 ;;
+ s390x) HOST_ARCH=s390x ;;
+ *mips*) HOST_ARCH=mips ;;
+ nios2) HOST_ARCH=nios2 ;;
+ vax) HOST_ARCH=vax ;;
+ xtensa*) HOST_ARCH=xtensa ;;
+ *) HOST_ARCH=UNKNOWN ;;
+ esac
+ }
+ set_host_arch "$(uname -m 2>&1)"
+ if test "$HOST_ARCH" = UNKNOWN ; then
+ set_host_arch "$(uname -p 2>&1)"
+ fi
+ TARGET_OS="$HOST_OS"
+ TARGET_ARCH="$HOST_ARCH"
+else
+ set_target_os() {
+ component=$1
+ part=$(echo $BUILD_TARGET | cut -d '-' -f $component)
+ case "$(echo $part | tr '[A-Z]' '[a-z]')" in
+ linux) TARGET_OS=Linux ;;
+ freebsd*) TARGET_OS=FreeBSD ;;
+ gnu/kfreebsd) TARGET_OS=FreeBSD ;;
+ netbsd) TARGET_OS=NetBSD ;;
+ bsd/os) TARGET_OS=BSD/OS ;;
+ openbsd) TARGET_OS=OpenBSD ;;
+ dragonfly) TARGET_OS=DragonFly ;;
+ sunos|solaris2.*) TARGET_OS=SunOS ;;
+ qnx) TARGET_OS=QNX ;;
+ morphos) TARGET_OS=MorphOS ;;
+ amigaos) TARGET_OS=AmigaOS ;;
+ mingw32*) TARGET_OS=MINGW32 ;;
+ wine) TARGET_OS=Wine ;;
+ darwin*) TARGET_OS=Darwin ;;
+ esac
+ }
+ TARGET_OS="UNKNOWN"
+ set_target_os 3
+ if test "$TARGET_OS" = UNKNOWN ; then
+ set_target_os 2
+ fi
+ TARGET_ARCH=$(echo $BUILD_TARGET | cut -d '-' -f 1)
+ if test "$(echo $TARGET_ARCH)" != "x86_64" ; then
+ TARGET_ARCH=$(echo $TARGET_ARCH | tr '_' '-')
+ fi
+fi
+
+echo "Host OS : $HOST_OS" >> "$TMPLOG"
+echo "Target OS : $TARGET_OS" >> "$TMPLOG"
+echo "Target ARCH: $TARGET_ARCH" >> "$TMPLOG"
+finish_check "$TARGET_OS"
+test "$TARGET_OS" = UNKNOWN && die "Unknown target OS, please specify the --target option"
+
+OS_LC="$(echo $TARGET_OS | tr '[A-Z]' '[a-z]')"
+aix() { test "$OS_LC" = "aix"; }
+amigaos() { test "$OS_LC" = "amigaos"; }
+bsdos() { test "$OS_LC" = "bsd/os"; }
+darwin() { test "$OS_LC" = "darwin"; }
+dragonfly() { test "$OS_LC" = "dragonfly"; }
+freebsd() { test "$OS_LC" = "freebsd" || test "$OS_LC" = "gnu/kfreebsd"; }
+gnu() { test "$OS_LC" = "gnu"; }
+hpux() { test "$OS_LC" = "hp-ux"; }
+irix() { test "$OS_LC" = "irix"; }
+linux() { test "$OS_LC" = "linux"; }
+mingw32() { test "$OS_LC" = "mingw32"; }
+mingw64() { test "$OS_LC" = "mingw64"; }
+msys() { test "$OS_LC" = "msys"; }
+cygwin() { test "$OS_LC" = "cygwin"; }
+netbsd() { test "$OS_LC" = "netbsd"; }
+openbsd() { test "$OS_LC" = "openbsd"; }
+os2() { test "$OS_LC" = "os/2"; }
+qnx() { test "$OS_LC" = "qnx"; }
+sunos() { test "$OS_LC" = "sunos"; }
+wine() { test "$OS_LC" = "wine"; }
+win32() { cygwin || mingw32 || mingw64 || msys || wine; }
+posix_make() { aix || bsdos || hpux || irix || qnx || sunos; }
+
+# Checking CC version...
+# Intel C++ Compilers (no autoselect, use CC=/some/binary ./configure)
+cc_vendor=
+if test "$(basename $CC)" = "icc" || test "$(basename $CC)" = "ecc"; then
+ start_check "$CC version"
+ cc_vendor=intel
+ cc_name=$($CC -V 2>&1 | head -n 1 | cut -d ',' -f 1)
+ cc_version=$($CC -V 2>&1 | head -n 1 | cut -d ',' -f 2 | cut -d ' ' -f 3)
+ _cc_major=$(echo $cc_version | cut -d '.' -f 1)
+ _cc_minor=$(echo $cc_version | cut -d '.' -f 2)
+ case $cc_version in
+ '')
+ cc_version="v. ?.??, bad"
+ cc_fail=yes
+ ;;
+ 10.1|11.1|12.*|13.*)
+ cc_version="$cc_version, ok"
+ ;;
+ *)
+ cc_version="$cc_version, bad"
+ cc_fail=yes
+ ;;
+ esac
+ finish_check "$cc_version"
+else
+ CC_TMP="$CC"
+ for CC in "$CC_TMP" gcc cc ; do
+ if $CC -v >/dev/null 2>&1; then
+ cc_name_tmp=$($CC -v 2>&1 | tail -n 1 | cut -d ' ' -f 1)
+ if test "$cc_name_tmp" = "gcc"; then
+ cc_name=$cc_name_tmp
+ start_check "$CC version"
+ cc_vendor=gnu
+ cc_version=$($CC -dumpversion 2>&1)
+ if ! echo $cc_version | grep -q '^[0-9][0-9]*\.[0-9]'; then
+ cc_v2=$($CC -dumpfullversion -dumpversion 2>/dev/null)
+ if echo $cc_v2 | grep -q '^[0-9][0-9]*\.[0-9]'; then
+ cc_version=$cc_v2
+ fi
+ fi
+ case $cc_version in
+ 2.96*)
+ cc_fail=yes
+ ;;
+ *)
+ _cc_major=$(echo $cc_version | cut -d '.' -f 1)
+ _cc_minor=$(echo $cc_version | cut -d '.' -f 2)
+ _cc_mini=$(echo $cc_version | cut -d '.' -f 3)
+ ;;
+ esac
+ finish_check "$cc_name $cc_version"
+ break
+ fi
+ if $CC -v 2>&1 | grep -q "clang"; then
+ start_check "$CC version"
+ cc_vendor=clang
+ cc_version=$($CC -dumpversion 2>&1)
+ finish_check "clang $cc_version"
+ break
+ fi
+ cc_name_tmp=$($CC -V 2>&1 | head -n 1 | cut -d ' ' -f 2,3)
+ if test "$cc_name_tmp" = "Sun C"; then
+ start_check "$CC version"
+ cc_vendor=sun
+ cc_version=$($CC -V 2>&1 | head -n 1 | cut -d ' ' -f 4)
+ res_comment="experimental support"
+ finish_check "Sun C $cc_version"
+ break
+ fi
+ fi
+ done
+fi # icc
+test -z "$cc_vendor" && die "compiler not found"
+test "$cc_fail" = "yes" && die "unsupported compiler version"
+
+if test "$cc_name" = "gcc" && test "$_cc_major" -gt 3; then
+ WARN_CFLAGS="$WARN_CFLAGS -Wdeclaration-after-statement"
+fi
+
+# select optimization flags
+has_optimization()
+{
+ # posix-compatible way to find -O option
+ for OPT in $BUILD_EXTRA_CFLAGS; do
+ case "$OPT" in
+ -O[0-3]|-O) return 0 ;;
+ esac
+ done
+ return 1
+}
+has_optimization && OPTLEVEL= || OPTLEVEL="-O2"
+OPTFLAGS="-pipe -DNDEBUG -fomit-frame-pointer -ffunction-sections -fdata-sections"
+OPTFLAGS=$(join_params $BUILD_DEBUG $OPTLEVEL $OPTFLAGS)
+
+# detect proper shared library name
+SHARED_PREFIX="lib"
+STATIC_PREFIX="lib"
+SHARED_EXT=".so.0"
+STATIC_EXT=".a"
+SOLINK_EXT=".so"
+EXEC_EXT=
+NEED_IMPLIB=no
+NEED_SOLINK=yes
+INSTALL_SO_DIR=$INSTALL_LIBDIR
+LN_S="ln -sf"
+if win32; then
+ LN_S="cp -pR"
+ EXEC_EXT=".exe"
+ SHARED_EXT=".dll"
+ NEED_IMPLIB=yes
+ NEED_SOLINK=no
+ INSTALL_SO_DIR=$INSTALL_BINDIR
+ if msys; then
+ SHARED_PREFIX="msys-"
+ elif cygwin; then
+ SHARED_PREFIX="cyg"
+ fi
+elif darwin; then
+ SHARED_EXT=".0.dylib"
+ SOLINK_EXT=".dylib"
+fi
+
+# check for linker flags
+LD_STATIC=-static
+test "$BUILD_STATIC" = "auto" && BUILD_STATIC=no
+test "$OPT_OPENSSL_RUNTIME" = "yes" && ! win32 && LD_STATIC=
+if test -n "$LD_STATIC"; then
+ start_check "linker support for $LD_STATIC"
+ if cc_check_cflag "$LD_STATIC"; then
+ test "$BUILD_STATIC" = "yes" && CHECK_LDFLAGS=$LD_STATIC
+ else
+ LD_STATIC=
+ fi
+ finish_check $(yn_nonempty "$LD_STATIC")
+fi
+test "$OPT_OPENSSL_RUNTIME" = "auto" && test "$BUILD_STATIC" = "yes" && ! win32 && OPT_OPENSSL_RUNTIME=no
+
+ALLOW_RUNTIME_LINKING=yes
+LIBDL_LDFLAGS=
+if ! win32 && test "$OPT_OPENSSL_RUNTIME" != "no"; then
+ start_check "linker support for dlopen"
+ ALLOW_RUNTIME_LINKING=no
+ if cc_check_statement "dlfcn.h" 'dlopen("", RTLD_NOW);'; then
+ ALLOW_RUNTIME_LINKING=yes
+ elif cc_check_statement "dlfcn.h" 'dlopen("", RTLD_NOW);' "-ldl"; then
+ ALLOW_RUNTIME_LINKING=yes
+ LIBDL_LDFLAGS="-ldl"
+ fi
+ finish_check "$ALLOW_RUNTIME_LINKING"
+fi
+
+SHARED_VSCRIPT=
+if ! darwin; then
+ start_check "linker support for --version-script"
+ echo "{ local: *; };" > $TMPT
+ cc_check_cflag "-Wl,--version-script,$TMPT -shared" &&
+ SHARED_VSCRIPT=",--version-script,exports.sym"
+ finish_check $(yn_nonempty "$SHARED_VSCRIPT")
+fi
+
+WIN_LDFLAGS=
+if win32; then
+ start_check "linker support for --nxcompat --no-seh --dynamicbase"
+ cc_check_cflag "-Wl,--nxcompat,--no-seh,--dynamicbase" &&
+ WIN_LDFLAGS="-Wl,--nxcompat,--no-seh,--dynamicbase"
+ finish_check $(yn_nonempty "$WIN_LDFLAGS")
+fi
+
+# detect library names and build flags
+LIBRHASH_SHARED="${SHARED_PREFIX}rhash${SHARED_EXT}"
+LIBRHASH_STATIC="${STATIC_PREFIX}rhash${STATIC_EXT}"
+LIBRHASH_SOLINK="${SHARED_PREFIX}rhash${SOLINK_EXT}"
+LIBRHASH_SOLINK_TARGET=
+test "$NEED_SOLINK" = "yes" && LIBRHASH_SOLINK_TARGET=$LIBRHASH_SOLINK
+LIBRHASH_DEF="${SHARED_PREFIX}rhash.def"
+LIBRHASH_IMPLIB="${STATIC_PREFIX}rhash${SHARED_EXT}${STATIC_EXT}"
+LIBRHASH_EXPORTS_FILE="exports.sym"
+LIBRHASH_EXPORTS_TARGET=
+LIBRHASH_SH_CFLAGS=""
+LIBRHASH_SH_LDFLAGS=""
+LIBRHASH_RM_FILES=
+LIBRHASH_LEGACY_HEADERS=
+if win32; then
+ LIBRHASH_SH_CFLAGS="-DRHASH_EXPORTS"
+ LIBRHASH_SH_LDFLAGS="-shared -Wl,--out-implib=${LIBRHASH_IMPLIB}${SHARED_VSCRIPT},--output-def,${LIBRHASH_DEF}"
+ test -n "$SHARED_VSCRIPT" && LIBRHASH_EXPORTS_TARGET=$LIBRHASH_EXPORTS_FILE
+ LIBRHASH_RM_FILES="${LIBRHASH_IMPLIB} ${LIBRHASH_DEF}"
+elif darwin; then
+ LIBRHASH_SH_CFLAGS="-fpic"
+ LIBRHASH_SH_LDFLAGS='-dynamiclib -Wl,-install_name,$(LIBDIR)/$@'
+else
+ LIBRHASH_LEGACY_HEADERS="rhash_timing.h"
+ LIBRHASH_SH_CFLAGS="-fpic"
+ LIBRHASH_SH_LDFLAGS="-shared -Wl${SHARED_VSCRIPT},-soname,\$(LIBRHASH_SHARED)"
+ test -n "$SHARED_VSCRIPT" && LIBRHASH_EXPORTS_TARGET=$LIBRHASH_EXPORTS_FILE
+fi
+LIBRHASH_RM_FILES=$(join_params $LIBRHASH_RM_FILES $LIBRHASH_EXPORTS_TARGET $LIBRHASH_SOLINK_TARGET)
+
+RHASH_DEFINES=
+LIBRHASH_DEFINES=
+GETTEXT_LDFLAGS=
+OPENSSL_LDFLAGS=
+if test "$OPT_GETTEXT" != "no"; then
+ start_check "gettext"
+ GETTEXT_FOUND=no
+ if cc_check_headers "libintl.h"; then
+ if cc_check_statement "libintl.h" "gettext(\"\");"; then
+ GETTEXT_FOUND=found
+ elif cc_check_statement "libintl.h" "gettext(\"\");" "-lintl"; then
+ GETTEXT_LDFLAGS="-lintl"
+ GETTEXT_FOUND=found
+ elif cc_check_statement "libintl.h" "gettext(\"\");" "-lintl -liconv"; then
+ GETTEXT_LDFLAGS="-lintl -liconv"
+ GETTEXT_FOUND=found
+ fi
+ fi
+ test "$GETTEXT_FOUND" = "found" && RHASH_DEFINES=$(join_params $RHASH_DEFINES -DUSE_GETTEXT)
+ finish_check $GETTEXT_FOUND
+ test "$OPT_GETTEXT" = "yes" && test "$GETTEXT_FOUND" = "no" && die "gettext library not found"
+fi
+
+if test "$OPT_OPENSSL" != "no"; then
+ start_check "OpenSSL"
+ test "$OPT_OPENSSL" = "auto" && test "$OPT_OPENSSL_RUNTIME" = "yes" && OPT_OPENSSL=yes
+ OPENSSL_FOUND=no
+ if test "$ALLOW_RUNTIME_LINKING" = "no"; then
+ echo "No runtime library loading, because dlopen() is not found!" >> "$TMPLOG"
+ test "$OPT_OPENSSL_RUNTIME" = "yes" && die "dlopen() is required for OpenSSL runtime loading"
+ OPT_OPENSSL_RUNTIME=no
+ fi
+ OPENSSL_HEADERS="openssl/opensslconf.h openssl/md4.h openssl/md5.h openssl/sha.h"
+ if cc_check_headers $OPENSSL_HEADERS; then
+ if test "$OPT_OPENSSL_RUNTIME" != "no"; then
+ OPENSSL_FOUND=runtime
+ LIBRHASH_DEFINES=$(join_params $LIBRHASH_DEFINES -DOPENSSL_RUNTIME)
+ OPENSSL_LDFLAGS="$LIBDL_LDFLAGS"
+ # note: libdl should disable -static
+ test -n "$LIBDL_LDFLAGS" && LD_STATIC=
+ elif win32 && cc_check_statement "openssl/md5.h" "MD5_Init(NULL);" "-leay32"; then
+ OPENSSL_FOUND=found
+ LIBRHASH_DEFINES=$(join_params $LIBRHASH_DEFINES -DUSE_OPENSSL)
+ OPENSSL_LDFLAGS="-leay32"
+ elif cc_check_statement "openssl/md5.h" "MD5_Init(NULL);" "-lcrypto"; then
+ OPENSSL_FOUND=found
+ LIBRHASH_DEFINES=$(join_params $LIBRHASH_DEFINES -DUSE_OPENSSL)
+ OPENSSL_LDFLAGS="-lcrypto"
+ fi
+ fi
+ finish_check $OPENSSL_FOUND
+ test "$OPT_OPENSSL" = "yes" && test "$OPENSSL_FOUND" = "no" && die "OpenSSL library not found"
+fi
+
+# building of static/shared binary an library
+RHASH_STATIC=rhash_static
+RHASH_SHARED=rhash_shared
+RHASH_BUILD_TARGETS=
+RHASH_EXTRA_INSTALL=
+LIBRHASH_BUILD_TARGETS=
+LIBRHASH_TEST_TARGETS=
+EXTRA_INSTALL_LIBSHARED=
+EXTRA_UNINSTALL_LIBSHARED=
+if test "$BUILD_STATIC" = "yes"; then
+ RHASH_STATIC=rhash
+ RHASH_BUILD_TYPE=static
+ RHASH_BUILD_TARGETS="\$(RHASH_STATIC)"
+ test "$INSTALL_LIB_SHARED" = "yes" && RHASH_BUILD_TARGETS="$RHASH_BUILD_TARGETS \$(LIBRHASH_SHARED)"
+else
+ RHASH_SHARED=rhash
+ RHASH_BUILD_TYPE=shared
+ RHASH_BUILD_TARGETS="\$(RHASH_SHARED)"
+ test "$INSTALL_LIB_SHARED" = "auto" && INSTALL_LIB_SHARED=yes
+ test "$INSTALL_LIB_STATIC" = "yes" && RHASH_BUILD_TARGETS="$RHASH_BUILD_TARGETS \$(LIBRHASH_STATIC)"
+fi
+if test "$INSTALL_LIB_STATIC" = "yes"; then
+ RHASH_EXTRA_INSTALL=$(join_params $RHASH_EXTRA_INSTALL install-lib-static)
+ LIBRHASH_BUILD_TARGETS=$LIBRHASH_STATIC
+ LIBRHASH_TEST_TARGETS=test-static
+fi
+if test "$NEED_IMPLIB" = "yes"; then
+ EXTRA_INSTALL_LIBSHARED="install-implib"
+ EXTRA_UNINSTALL_LIBSHARED="uninstall-implib"
+fi
+if test "$INSTALL_LIB_SHARED" = "yes"; then
+ RHASH_EXTRA_INSTALL=$(join_params $RHASH_EXTRA_INSTALL install-lib-shared)
+ LIBRHASH_BUILD_TARGETS=$(join_params $LIBRHASH_BUILD_TARGETS $LIBRHASH_SHARED)
+ LIBRHASH_TEST_TARGETS=$(join_params $LIBRHASH_TEST_TARGETS test-shared)
+fi
+
+# check for old POSIX make
+posix_make && Q_ASSIGN="=" || Q_ASSIGN="?="
+
+# detect source directories
+start_check "sources"
+HAS_RHASH=no
+HAS_LIBRHASH=no
+HAS_BINDINGS=no
+RHASH_VERSION=
+BINDINGS_VERSION=
+RHASH_SRC=
+LIBRHASH_SRC=
+LIBRHASH_PC=
+BINDINGS_SRC=
+SRC_FOUND=no
+test -f Makefile || die "Makefile not found"
+if test -f rhash_main.c; then
+ HAS_RHASH=yes
+ SRC_FOUND=RHash
+ if test -d librhash; then
+ HAS_LIBRHASH=yes
+ LIBRHASH_SRC=librhash/
+ fi
+ if test -f bindings/version.properties; then
+ HAS_BINDINGS=yes
+ BINDINGS_SRC=bindings/
+ fi
+elif test -f rhash.c; then
+ HAS_LIBRHASH=yes
+ SRC_FOUND=LibRHash
+elif test -f version.properties; then
+ HAS_BINDINGS=yes
+ SRC_FOUND="RHash bindings"
+fi
+echo "RHASH_SRC=$RHASH_SRC, LIBRHASH_SRC=$LIBRHASH_SRC, BINDINGS_SRC=$BINDINGS_SRC" >> "$TMPLOG"
+
+# check version
+good_version() { echo "$1" | grep -q '^[1-9]\.[1-9][0-9]*\.[1-9]' ; }
+if test "$HAS_RHASH" = "yes"; then
+ test -f "${RHASH_SRC}version.h" || die "${RHASH_SRC}version.h not found"
+ RHASH_VERSION=$(cut -d'"' -f2 "${RHASH_SRC}version.h")
+ echo "RHASH_VERSION=$RHASH_VERSION" >> "$TMPLOG"
+ good_version "$RHASH_VERSION" || die "wrong version: $RHASH_VERSION"
+ test "$HAS_LIBRHASH" = "yes" && LIBRHASH_PC=dist/librhash.pc
+fi
+if test "$HAS_BINDINGS" = "yes"; then
+ BINDINGS_VERSION=$(cut -d = -f 2 "${BINDINGS_SRC}version.properties")
+ echo "BINDINGS_VERSION=$BINDINGS_VERSION" >> "$TMPLOG"
+ good_version "$BINDINGS_VERSION" || die "wrong bindings version: $BINDINGS_VERSION"
+ test -z "$RHASH_VERSION" && RHASH_VERSION="$BINDINGS_VERSION"
+fi
+test -n "$RHASH_VERSION" && SRC_FOUND="$SRC_FOUND $RHASH_VERSION"
+finish_check "$SRC_FOUND"
+test "$SRC_FOUND" = "no" && die "sources not found"
+
+if test "$HAS_BINDINGS" = "yes" && test "$BINDINGS_VERSION" != "$RHASH_VERSION"; then
+ echo "Updating ${BINDINGS_SRC}version.properties"
+ echo "version=$RHASH_VERSION" > ${BINDINGS_SRC}version.properties
+fi
+
+if test "$HAS_RHASH" = "yes"; then
+ echo "Writing ${RHASH_SRC}config.mak"
+ cat > ${RHASH_SRC}config.mak << EOF
+# -------- Generated by configure -----------
+
+DESTDIR $Q_ASSIGN
+BINDIR = \$(DESTDIR)$INSTALL_BINDIR
+SYSCONFDIR = \$(DESTDIR)$INSTALL_SYSCONFDIR
+MANDIR = \$(DESTDIR)$INSTALL_MANDIR
+PKGCONFIGDIR = \$(DESTDIR)$INSTALL_PKGCONFIGDIR
+LOCALEDIR = \$(DESTDIR)$INSTALL_LOCALEDIR
+
+AR = $CMD_AR
+CC = $CC
+INSTALL = $CMD_INSTALL
+
+LIBRHASH_STATIC = librhash/$LIBRHASH_STATIC
+LIBRHASH_SHARED = librhash/$LIBRHASH_SHARED
+BUILD_TYPE = $RHASH_BUILD_TYPE
+VERSION = $RHASH_VERSION
+EXEC_EXT = $EXEC_EXT
+RHASH_STATIC = $RHASH_STATIC\$(EXEC_EXT)
+RHASH_SHARED = $RHASH_SHARED\$(EXEC_EXT)
+BUILD_TARGETS = $RHASH_BUILD_TARGETS
+EXTRA_INSTALL = $RHASH_EXTRA_INSTALL
+SYMLINKS = $INSTALL_SYMLINKS
+LN_S = $LN_S
+
+OPTFLAGS = $OPTFLAGS
+OPTLDFLAGS = $WIN_LDFLAGS
+WARN_CFLAGS = $WARN_CFLAGS
+ADDCFLAGS = $BUILD_EXTRA_CFLAGS
+ADDLDFLAGS = $BUILD_EXTRA_LDFLAGS
+CFLAGS = $RHASH_DEFINES \$(OPTFLAGS) \$(WARN_CFLAGS) \$(ADDCFLAGS)
+LDFLAGS = \$(OPTLDFLAGS) \$(ADDLDFLAGS) $GETTEXT_LDFLAGS
+BIN_STATIC_LDFLAGS = \$(LDFLAGS) $(join_params $LD_STATIC $OPENSSL_LDFLAGS)
+
+EOF
+fi
+
+
+if test "$HAS_LIBRHASH" = "yes"; then
+ echo "Writing ${LIBRHASH_SRC}config.mak"
+ cat > ${LIBRHASH_SRC}config.mak << EOF
+# -------- Generated by configure -----------
+
+DESTDIR $Q_ASSIGN
+INCDIR = \$(DESTDIR)$INSTALL_INCDIR
+LIBDIR = \$(DESTDIR)$INSTALL_LIBDIR
+SO_DIR = \$(DESTDIR)$INSTALL_SO_DIR
+
+AR = $CMD_AR
+CC = $CC
+INSTALL = $CMD_INSTALL
+
+LIBRHASH_STATIC = $LIBRHASH_STATIC
+LIBRHASH_SHARED = $LIBRHASH_SHARED
+LIBRHASH_SOLINK = $LIBRHASH_SOLINK
+LIBRHASH_DEF = $LIBRHASH_DEF
+LIBRHASH_IMPLIB = $LIBRHASH_IMPLIB
+EXPORTS_FILE = $LIBRHASH_EXPORTS_FILE
+RM_FILES = $LIBRHASH_RM_FILES
+BUILD_TYPE = $RHASH_BUILD_TYPE
+EXEC_EXT = $EXEC_EXT
+LEGACY_HEADERS = $LIBRHASH_LEGACY_HEADERS
+
+EXPORTS_TARGET = $LIBRHASH_EXPORTS_TARGET
+BUILD_TARGETS = $LIBRHASH_BUILD_TARGETS
+TEST_TARGETS = $LIBRHASH_TEST_TARGETS
+SOLINK_TARGET = $LIBRHASH_SOLINK_TARGET
+EXTRA_INSTALL_LIBSHARED = $EXTRA_INSTALL_LIBSHARED
+EXTRA_UNINSTALL_LIBSHARED = $EXTRA_UNINSTALL_LIBSHARED
+
+OPTFLAGS = $OPTFLAGS
+OPTLDFLAGS = $WIN_LDFLAGS
+WARN_CFLAGS = $WARN_CFLAGS
+ADDCFLAGS = $BUILD_EXTRA_CFLAGS
+ADDLDFLAGS = $BUILD_EXTRA_LDFLAGS
+CFLAGS = $LIBRHASH_DEFINES \$(OPTFLAGS) \$(WARN_CFLAGS) \$(ADDCFLAGS)
+LDFLAGS = \$(OPTLDFLAGS) \$(ADDLDFLAGS)
+SHARED_CFLAGS = \$(CFLAGS) $LIBRHASH_SH_CFLAGS
+SHARED_LDFLAGS = \$(LDFLAGS) $(join_params $OPENSSL_LDFLAGS $LIBRHASH_SH_LDFLAGS)
+BIN_STATIC_LDFLAGS = \$(LDFLAGS) $(join_params $LD_STATIC $OPENSSL_LDFLAGS)
+
+EOF
+fi
+
+if test -n "$LIBRHASH_PC"; then
+ PC_EXC="$INSTALL_EXEC_PREFIX"
+ PC_INC="$INSTALL_INCDIR"
+ PC_LIB="$INSTALL_LIBDIR"
+ test "$PC_EXC" = "${INSTALL_PREFIX}" && PC_EXC='${prefix}'
+ test "$PC_INC" = "${INSTALL_PREFIX}/include" && PC_INC='${prefix}/include'
+ test "$PC_LIB" = "${INSTALL_EXEC_PREFIX}/lib" && PC_LIB='${exec_prefix}/lib'
+ echo "Writing ${LIBRHASH_PC}"
+ cat > $LIBRHASH_PC << EOF
+prefix=${INSTALL_PREFIX}
+exec_prefix=${PC_EXC}
+libdir=${PC_LIB}
+includedir=${PC_INC}
+
+Name: librash
+Description: LibRHash shared library
+Version: ${RHASH_VERSION}
+Cflags: -I\${includedir}
+Libs: -L\${libdir} -lrhash
+Libs.private: ${OPENSSL_LDFLAGS}
+
+EOF
+fi
diff --git a/dist/rhash.1 b/dist/rhash.1
index 9b5bfa69..65ed0b71 100644
--- a/dist/rhash.1
+++ b/dist/rhash.1
@@ -1,320 +1,320 @@
-.TH RHASH 1 "APR 2010" Linux "User Manuals"
-.SH NAME
-rhash \- calculate/check CRC32, MD5, SHA1, GOST, TTH, BTIH or other hash sums.
-.SH SYNOPSIS
-.B rhash [
-.I option
-.B ]... [
-.I file
-.B ]...
-.SH DESCRIPTION
-.B RHash
-(Recursive Hasher)
-computes and verifies various message digests (hash sums) of files or
-strings. Supported message digests include CRC32, CRC32C, MD4, MD5, SHA1,
-SHA256, SHA512, SHA3, Tiger, DC++ TTH, BTIH, AICH, ED2K, GOST R 34.11\-*,
-RIPEMD\-160, HAS\-160, EDON\-R 256/512, Whirlpool, Snefru\-128/256.
-
-The program can create and verify Magnet links
-and eDonkey ed2k:// links, see \-\-magnet and \-\-ed2k\-link options.
-
-A dash string parameter `\-' is interpreted as stdin file.
-
-By default
-.B rhash
-prints sums in SFV format with CRC32 hash sum only.
-The format can be changed by options \-\-bsd, \-\-magnet, \-\-simple,
-\-\-printf, \-\-template.
-To output all sums use the `\-a' option.
-
-The default output format can be changed by renaming the program or placing
-a hardlink/symlink to it with a filename containing strings `crc32',
-`crc32c', `md4', `md5', `sha1', `sha256' `sha512', `tiger', `tth',
-`btih', `aich', `ed2k', `ed2k\-link', `gost12\-256', `gost12\-512',
-`gost94', `gost94\-cryptopro', `ripemd160', `has160', `whirlpool',
-`edonr256', `edonr512', `snefru128', `snefru256', `sfv' or `magnet'.
-
-.SH PROGRAM MODE OPTIONS
-The default mode is to print hash sums for all files and directory trees
-specified by command line. The mode can be set by the following options.
-.IP "\-c, \-\-check"
-Check hash files specified by command line. RHash can verify hash files in
-SFV and BSD formats, standard MD5 and SHA1 files,
-and text files containing magnet or ed2k links (one link per line).
-Empty lines and lines starting with `;' or `#' are skipped.
-In fact RHash can verify most hash files generated by itself
-without formatting options \-\-printf and \-\-template.
-.IP "\-u, \-\-update"
-Update hash files specified by command line.
-The program calculates and appends hashes to the updated hash file
-in the format specified by formatting options.
-Hashes are calculated for those files from the same directory
-as the hash file, which are yet not present in it.
-.IP "\-k, \-\-check\-embedded"
-Verify files by crc32 sum embedded in their names.
-.IP "\-\-torrent"
-Create a torrent file for each processed file.
-.IP "\-h, \-\-help"
-Help: print help screen and exit.
-.IP "\-V, \-\-version"
-Version: print version and exit.
-.IP "\-B, \-\-benchmark"
-Run benchmark for selected algorithm(s).
-
-.SH HASH SUMS OPTIONS
-.IP "\-C, \-\-crc32"
-CRC32: calculate and print CRC32 hash sum.
-.IP "\-\-crc32c"
-CRC32C: calculate and print CRC32C hash sum.
-.IP "\-\-md4"
-MD4: calculate and print MD4 hash sum.
-.IP "\-M, \-\-md5"
-MD5: calculate and print MD5 hash sum.
-.IP "\-H, \-\-sha1"
-SHA1: calculate and print SHA1 hash sum.
-.IP "\-\-sha224, \-\-sha256, \-\-sha384, \-\-sha512"
-Calculate specified SHA2 hash sum.
-.IP "\-\-sha3-224, \-\-sha3-256, \-\-sha3-384, \-\-sha3-512"
-Calculate specified SHA3 hash sum.
-.IP "\-\-tiger"
-Tiger: calculate and print Tiger hash sum.
-.IP "\-T, \-\-tth"
-TTH: calculate and print DC++ TTH sum.
-.IP "\-\-btih"
-BTIH: calculate and print BitTorrent Info Hash.
-.IP "\-A, \-\-aich"
-AICH: calculate and print AICH hash.
-.IP "\-E, \-\-ed2k"
-ED2K: calculate and print eDonkey 2000 hash sum.
-.IP "\-L, \-\-ed2k\-link"
-eDonkey link: calculate and print eDonkey link.
-.IP "\-W, \-\-whirlpool"
-Whirlpool: calculate and print Whirlpool hash sum.
-.IP "\-G, \-\-gost12-256"
-GOST\-2012: calculate and print 256-bit GOST R 34.11\-2012 hash,
-the Russian GOST standard hash function.
-.IP "\-\-gost12-512"
-GOST\-2012: calculate and print 512-bit GOST R 34.11\-2012 hash,
-the Russian GOST standard hash function.
-.IP "\-\-gost94"
-GOST\-94: calculate and print GOST R 34.11\-94 hash,
-the deprecated Russian standard hash function.
-.IP "\-\-gost94\-cryptopro"
-GOST\-94\-CRYPTOPRO: calculate and print CryptoPro version of
-the deprecated Russian GOST R 34.11\-94 hash function.
-.IP "\-\-ripemd160"
-RIPEMD\-160: calculate and print RIPEMD\-160 hash sum.
-.IP "\-\-has160"
-HAS\-160: calculate and print HAS\-160 hash sum.
-.IP "\-\-snefru128, \-\-snefru256"
-SNEFRU: calculate and print SNEFRU\-128/256 hash sums.
-.IP "\-\-edonr256, \-\-edonr512"
-EDON\-R: calculate and print EDON\-R 256/512 hash sums.
-
-.IP "\-a, \-\-all"
-Calculate all supported hash sums.
-.IP "\-\-list\-hashes"
-List names of all supported hashes, one per line.
-
-.SH MISCELLANEOUS OPTIONS
-.IP "\-r, \-\-recursive"
-Recursively process directories, specified by command line.
-.IP "\-\-file\-list="
-Process given file as a file-list. Lines of this file are
-interpreted as paths to files to be processed. Multiple
-file lists can be specified at command line.
-.IP "\-m, \-\-message="
-Calculate hash sums of the text message.
-.IP "\-\-follow"
-Follow symbolic links when processing directories recursively.
-.IP "\-v, \-\-verbose"
-Be verbose.
-.IP "\-\-percents"
-Show percents, while calculating or checking sums
-.IP "\-\-skip\-ok"
-Don't print OK messages for successfully verified files.
-.IP "\-i, \-\-ignore\-case"
-Ignore case of filenames when updating crc files.
-.IP "\-\-speed"
-Print per\-file and the total processing speed.
-.IP "\-e, \-\-embed\-crc"
-Rename files by inserting crc32 sum into name.
-.IP "\-\-embed\-crc\-delimiter="
-Insert specified before a crc sum in the \-\-embed\-crc mode,
-default is white space. The can be a character or empty string.
-.IP "\-\-path\-separator="
-Use specified path separator to display paths.
-.IP "\-q, \-\-accept="
-Set a comma\(hydelimited list of extensions of the files to process.
-.IP "\-\-exclude="
-Set a comma\(hydelimited list of extensions of the files to exclude from processing.
-.IP "\-t, \-\-crc\-accept="
-Set a comma\(hydelimited list of extensions of the hash files to verify.
-.IP "\-\-maxdepth="
-Descend at most (a non\(hynegative integer) levels of directories below
-the command line arguments. `\-\-maxdepth 0' means only apply the tests and
-actions to the command line arguments.
-.IP "\-o, \-\-output="
-Set the file to output calculated hashes and verification results to.
-.IP "\-l, \-\-log="
-Set the file to log errors and verbose information to.
-.IP "\-\-openssl="
-Specify which hash functions should be calculated using the OpenSSL library.
-The is a comma delimited list of hash names, but only those
-supported by openssl are allowed, e.g. md4, md5, sha1, sha256, ripemd160.
-See openssl documentation for the full list.
-.IP "\-\-gost\-reverse"
-Reverse bytes in hexadecimal output of the GOST hash sum.
-The most significant bytes of the hash will be printed first.
-Default order is the least significant bytes first.
-.IP "\-\-bt\-batch="
-Turn on torrent batch mode (implies torrent mode). Calculates batch-torrent
-for the files specified at command line and saves the torrent file to
-the file\-path. The option \-r can be useful in this mode.
-.IP "\-\-bt\-private"
-Generate BTIH for a private BitTorrent tracker.
-.IP "\-\-bt\-piece\-length"
-Set the
-.I "piece length"
-value for torrent file.
-.IP "\-\-bt\-announce="
-Add a tracker announce URL to the created torrent file(s).
-Several URLs can be passed by specifying the option mutltiple times.
-This option doesn't change the BTIH hash.
-.IP "\-\-benchmark\-raw"
-Switch benchmark output format to be a machine\(hyreadable tab\(hydelimited text
-with hash function name, speed, cpu clocks per byte.
-This option works only if the \-\-benchmark option was specified.
-.IP "\-\- (double dash)"
-Mark the end of command line options. All parameters following the
-double dash are interpreted as files or directories. It is typically used
-to process filenames starting with a dash `\-'.
-Alternatively you can specify './' or full path before such files,
-so they will not look like options anymore.
-
-.SH OUTPUT FORMAT OPTIONS
-.IP "\-\-sfv"
-Print hash sums in the SFV (Simple File Verification) output format (default).
-But unlike common SFV file, not only CRC32, but any hash sums specified
-by options can be printed.
-.IP "\-g, \-\-magnet"
-Print hash sums formatted as magnet links.
-.IP "\-\-bsd"
-Use BSD output format. Each hash sum is printed on separate line
-after hash name and file's path, enclosed in parentheses.
-.IP "\-\-simple"
-Use simple output format. Each line will consist of
-filename and hash sums specified by options.
-.IP "\-\-uppercase"
-Print hash sums in upper case.
-.IP "\-\-lowercase"
-Print hash sums in lower case.
-.IP "\-\-template="
-Read printf\(hylike template from given . See the \-\-printf option.
-.IP "\-p, \-\-printf="
-Format: print
-.I format
-string the standard output, interpreting `\e'
-escapes and `%' directives. The escapes and directives are:
-.RS
-.IP \en
-Newline.
-.IP \er
-Carriage return.
-.IP \et
-Horizontal tab.
-.IP \e\e
-A literal backslash (`\e').
-.IP \e0
-ASCII NUL.
-.IP \eNNN
-The character which octal ASCII code is NNN.
-.IP \exNN
-The character which hexadecimal ASCII code is NN.
-.PP
-A `\e' character followed by any other character is treated as an
-ordinary character, so they both are printed.
-.IP %%
-A literal percent sign.
-.IP %p
-File's path.
-.IP %f
-File's name.
-.IP %u
-URL\(hyencoded filename.
-.IP %s
-File's size in bytes.
-.IP %{mtime}
-File's last modification time.
-.IP "%a or %A"
-AICH hash sum.
-.IP "%c or %C"
-CRC32 hash sum.
-Use %c for lowercase and %C for uppercase characters.
-.IP "%g or %G"
-GOST R 34.11\-94 hash.
-.IP "%h or %H"
-SHA1 hash.
-.IP "%e or %E"
-ED2K hash sum.
-.IP "%l or %L"
-EDonkey ed2k://... link.
-.IP "%m or %M"
-MD5 hash.
-.IP "%r or %R"
-RIPEMD-160 hash.
-.IP "%t or %T"
-TTH sum.
-.IP "%w or %W"
-Whirlpool hash.
-.IP "%{crc32}, %{crc32c}, %{md4}, %{md5}, %{sha1}, %{tiger}, %{tth}, %{btih},\
- %{ed2k}, %{aich}, %{whirlpool}, %{ripemd160}, %{has160},\
- %{gost94}, %{gost94\-cryptopro}, %{gost12\-256}, %{gost12\-512},\
- %{sha\-224}, %{sha\-256}, %{sha\-384}, %{sha\-512},\
- %{sha3\-224}, %{sha3\-256}, %{sha3\-384}, %{sha3\-512},\
- %{edon\-r256}, %{edon\-r512}, %{snefru128}, %{snefru256}"
-Print the specified hash sum. The hash is printed in uppercase, if the name
-of the hash sum starts with a capital letter, e.g. %{TTH}, %{Sha-512}.
-.IP "%x, %b, %B, %@"
-Use one of these prefixes to output a hash sum in hexadecimal, base32,
-base64 or raw (binary) format respectively, e.g. %b{md4}, %BH or %xT.
-.RE
-
-.SH CONFIG FILE
-RHash looks for a config file
-at $XDG_CONFIG_HOME/rhash/rhashrc, $HOME/.rhashrc and /etc/rhashrc.
-
-The config file consists of lines formatted as
-.RS
-variable = value
-.RE
-
-where the
-.I variable
-can be a name of any command line option, like
-.I magnet,
-.I printf,
-.I percents, etc.
-A boolean variable can be set to true by a value `on', `yes' or `true',
-any other value sets the variable to false.
-
-Empty lines and lines starting with `#' or `;' are ignored.
-
-Example config file:
-.nf
-# This is a comment line
-percents = on
-crc-accept = .sfv,.md5,.sha1,.sha256,.sha512,.tth,.magnet
-.fi
-
-.SH AUTHOR
-Aleksey Kravchenko
-.SH "SEE ALSO"
-.BR md5sum (1)
-.BR cksfv (1)
-.BR ed2k_hash (1)
-.SH BUGS
-Bug reports are welcome!
-Send them by email
-or post to the SourceForge Bug Tracking System
-.I http://sourceforge.net/projects/rhash/
+.TH RHASH 1 "APR 2010" Linux "User Manuals"
+.SH NAME
+rhash \- calculate/check CRC32, MD5, SHA1, GOST, TTH, BTIH or other hash sums.
+.SH SYNOPSIS
+.B rhash [
+.I option
+.B ]... [
+.I file
+.B ]...
+.SH DESCRIPTION
+.B RHash
+(Recursive Hasher)
+computes and verifies various message digests (hash sums) of files or
+strings. Supported message digests include CRC32, CRC32C, MD4, MD5, SHA1,
+SHA256, SHA512, SHA3, Tiger, DC++ TTH, BTIH, AICH, ED2K, GOST R 34.11\-*,
+RIPEMD\-160, HAS\-160, EDON\-R 256/512, Whirlpool, Snefru\-128/256.
+
+The program can create and verify Magnet links
+and eDonkey ed2k:// links, see \-\-magnet and \-\-ed2k\-link options.
+
+A dash string parameter `\-' is interpreted as stdin file.
+
+By default
+.B rhash
+prints sums in SFV format with CRC32 hash sum only.
+The format can be changed by options \-\-bsd, \-\-magnet, \-\-simple,
+\-\-printf, \-\-template.
+To output all sums use the `\-a' option.
+
+The default output format can be changed by renaming the program or placing
+a hardlink/symlink to it with a filename containing strings `crc32',
+`crc32c', `md4', `md5', `sha1', `sha256' `sha512', `tiger', `tth',
+`btih', `aich', `ed2k', `ed2k\-link', `gost12\-256', `gost12\-512',
+`gost94', `gost94\-cryptopro', `ripemd160', `has160', `whirlpool',
+`edonr256', `edonr512', `snefru128', `snefru256', `sfv' or `magnet'.
+
+.SH PROGRAM MODE OPTIONS
+The default mode is to print hash sums for all files and directory trees
+specified by command line. The mode can be set by the following options.
+.IP "\-c, \-\-check"
+Check hash files specified by command line. RHash can verify hash files in
+SFV and BSD formats, standard MD5 and SHA1 files,
+and text files containing magnet or ed2k links (one link per line).
+Empty lines and lines starting with `;' or `#' are skipped.
+In fact RHash can verify most hash files generated by itself
+without formatting options \-\-printf and \-\-template.
+.IP "\-u, \-\-update"
+Update hash files specified by command line.
+The program calculates and appends hashes to the updated hash file
+in the format specified by formatting options.
+Hashes are calculated for those files from the same directory
+as the hash file, which are yet not present in it.
+.IP "\-k, \-\-check\-embedded"
+Verify files by crc32 sum embedded in their names.
+.IP "\-\-torrent"
+Create a torrent file for each processed file.
+.IP "\-h, \-\-help"
+Help: print help screen and exit.
+.IP "\-V, \-\-version"
+Version: print version and exit.
+.IP "\-B, \-\-benchmark"
+Run benchmark for selected algorithm(s).
+
+.SH HASH SUMS OPTIONS
+.IP "\-C, \-\-crc32"
+CRC32: calculate and print CRC32 hash sum.
+.IP "\-\-crc32c"
+CRC32C: calculate and print CRC32C hash sum.
+.IP "\-\-md4"
+MD4: calculate and print MD4 hash sum.
+.IP "\-M, \-\-md5"
+MD5: calculate and print MD5 hash sum.
+.IP "\-H, \-\-sha1"
+SHA1: calculate and print SHA1 hash sum.
+.IP "\-\-sha224, \-\-sha256, \-\-sha384, \-\-sha512"
+Calculate specified SHA2 hash sum.
+.IP "\-\-sha3-224, \-\-sha3-256, \-\-sha3-384, \-\-sha3-512"
+Calculate specified SHA3 hash sum.
+.IP "\-\-tiger"
+Tiger: calculate and print Tiger hash sum.
+.IP "\-T, \-\-tth"
+TTH: calculate and print DC++ TTH sum.
+.IP "\-\-btih"
+BTIH: calculate and print BitTorrent Info Hash.
+.IP "\-A, \-\-aich"
+AICH: calculate and print AICH hash.
+.IP "\-E, \-\-ed2k"
+ED2K: calculate and print eDonkey 2000 hash sum.
+.IP "\-L, \-\-ed2k\-link"
+eDonkey link: calculate and print eDonkey link.
+.IP "\-W, \-\-whirlpool"
+Whirlpool: calculate and print Whirlpool hash sum.
+.IP "\-G, \-\-gost12-256"
+GOST\-2012: calculate and print 256-bit GOST R 34.11\-2012 hash,
+the Russian GOST standard hash function.
+.IP "\-\-gost12-512"
+GOST\-2012: calculate and print 512-bit GOST R 34.11\-2012 hash,
+the Russian GOST standard hash function.
+.IP "\-\-gost94"
+GOST\-94: calculate and print GOST R 34.11\-94 hash,
+the deprecated Russian standard hash function.
+.IP "\-\-gost94\-cryptopro"
+GOST\-94\-CRYPTOPRO: calculate and print CryptoPro version of
+the deprecated Russian GOST R 34.11\-94 hash function.
+.IP "\-\-ripemd160"
+RIPEMD\-160: calculate and print RIPEMD\-160 hash sum.
+.IP "\-\-has160"
+HAS\-160: calculate and print HAS\-160 hash sum.
+.IP "\-\-snefru128, \-\-snefru256"
+SNEFRU: calculate and print SNEFRU\-128/256 hash sums.
+.IP "\-\-edonr256, \-\-edonr512"
+EDON\-R: calculate and print EDON\-R 256/512 hash sums.
+
+.IP "\-a, \-\-all"
+Calculate all supported hash sums.
+.IP "\-\-list\-hashes"
+List names of all supported hashes, one per line.
+
+.SH MISCELLANEOUS OPTIONS
+.IP "\-r, \-\-recursive"
+Recursively process directories, specified by command line.
+.IP "\-\-file\-list="
+Process given file as a file-list. Lines of this file are
+interpreted as paths to files to be processed. Multiple
+file lists can be specified at command line.
+.IP "\-m, \-\-message="
+Calculate hash sums of the text message.
+.IP "\-\-follow"
+Follow symbolic links when processing directories recursively.
+.IP "\-v, \-\-verbose"
+Be verbose.
+.IP "\-\-percents"
+Show percents, while calculating or checking sums
+.IP "\-\-skip\-ok"
+Don't print OK messages for successfully verified files.
+.IP "\-i, \-\-ignore\-case"
+Ignore case of filenames when updating crc files.
+.IP "\-\-speed"
+Print per\-file and the total processing speed.
+.IP "\-e, \-\-embed\-crc"
+Rename files by inserting crc32 sum into name.
+.IP "\-\-embed\-crc\-delimiter="
+Insert specified before a crc sum in the \-\-embed\-crc mode,
+default is white space. The can be a character or empty string.
+.IP "\-\-path\-separator="
+Use specified path separator to display paths.
+.IP "\-q, \-\-accept="
+Set a comma\(hydelimited list of extensions of the files to process.
+.IP "\-\-exclude="
+Set a comma\(hydelimited list of extensions of the files to exclude from processing.
+.IP "\-t, \-\-crc\-accept="
+Set a comma\(hydelimited list of extensions of the hash files to verify.
+.IP "\-\-maxdepth="
+Descend at most (a non\(hynegative integer) levels of directories below
+the command line arguments. `\-\-maxdepth 0' means only apply the tests and
+actions to the command line arguments.
+.IP "\-o, \-\-output="
+Set the file to output calculated hashes and verification results to.
+.IP "\-l, \-\-log="
+Set the file to log errors and verbose information to.
+.IP "\-\-openssl="
+Specify which hash functions should be calculated using the OpenSSL library.
+The is a comma delimited list of hash names, but only those
+supported by openssl are allowed, e.g. md4, md5, sha1, sha256, ripemd160.
+See openssl documentation for the full list.
+.IP "\-\-gost\-reverse"
+Reverse bytes in hexadecimal output of the GOST hash sum.
+The most significant bytes of the hash will be printed first.
+Default order is the least significant bytes first.
+.IP "\-\-bt\-batch="
+Turn on torrent batch mode (implies torrent mode). Calculates batch-torrent
+for the files specified at command line and saves the torrent file to
+the file\-path. The option \-r can be useful in this mode.
+.IP "\-\-bt\-private"
+Generate BTIH for a private BitTorrent tracker.
+.IP "\-\-bt\-piece\-length"
+Set the
+.I "piece length"
+value for torrent file.
+.IP "\-\-bt\-announce="
+Add a tracker announce URL to the created torrent file(s).
+Several URLs can be passed by specifying the option mutltiple times.
+This option doesn't change the BTIH hash.
+.IP "\-\-benchmark\-raw"
+Switch benchmark output format to be a machine\(hyreadable tab\(hydelimited text
+with hash function name, speed, cpu clocks per byte.
+This option works only if the \-\-benchmark option was specified.
+.IP "\-\- (double dash)"
+Mark the end of command line options. All parameters following the
+double dash are interpreted as files or directories. It is typically used
+to process filenames starting with a dash `\-'.
+Alternatively you can specify './' or full path before such files,
+so they will not look like options anymore.
+
+.SH OUTPUT FORMAT OPTIONS
+.IP "\-\-sfv"
+Print hash sums in the SFV (Simple File Verification) output format (default).
+But unlike common SFV file, not only CRC32, but any hash sums specified
+by options can be printed.
+.IP "\-g, \-\-magnet"
+Print hash sums formatted as magnet links.
+.IP "\-\-bsd"
+Use BSD output format. Each hash sum is printed on separate line
+after hash name and file's path, enclosed in parentheses.
+.IP "\-\-simple"
+Use simple output format. Each line will consist of
+filename and hash sums specified by options.
+.IP "\-\-uppercase"
+Print hash sums in upper case.
+.IP "\-\-lowercase"
+Print hash sums in lower case.
+.IP "\-\-template="
+Read printf\(hylike template from given . See the \-\-printf option.
+.IP "\-p, \-\-printf="
+Format: print
+.I format
+string the standard output, interpreting `\e'
+escapes and `%' directives. The escapes and directives are:
+.RS
+.IP \en
+Newline.
+.IP \er
+Carriage return.
+.IP \et
+Horizontal tab.
+.IP \e\e
+A literal backslash (`\e').
+.IP \e0
+ASCII NUL.
+.IP \eNNN
+The character which octal ASCII code is NNN.
+.IP \exNN
+The character which hexadecimal ASCII code is NN.
+.PP
+A `\e' character followed by any other character is treated as an
+ordinary character, so they both are printed.
+.IP %%
+A literal percent sign.
+.IP %p
+File's path.
+.IP %f
+File's name.
+.IP %u
+URL\(hyencoded filename.
+.IP %s
+File's size in bytes.
+.IP %{mtime}
+File's last modification time.
+.IP "%a or %A"
+AICH hash sum.
+.IP "%c or %C"
+CRC32 hash sum.
+Use %c for lowercase and %C for uppercase characters.
+.IP "%g or %G"
+GOST R 34.11\-94 hash.
+.IP "%h or %H"
+SHA1 hash.
+.IP "%e or %E"
+ED2K hash sum.
+.IP "%l or %L"
+EDonkey ed2k://... link.
+.IP "%m or %M"
+MD5 hash.
+.IP "%r or %R"
+RIPEMD-160 hash.
+.IP "%t or %T"
+TTH sum.
+.IP "%w or %W"
+Whirlpool hash.
+.IP "%{crc32}, %{crc32c}, %{md4}, %{md5}, %{sha1}, %{tiger}, %{tth}, %{btih},\
+ %{ed2k}, %{aich}, %{whirlpool}, %{ripemd160}, %{has160},\
+ %{gost94}, %{gost94\-cryptopro}, %{gost12\-256}, %{gost12\-512},\
+ %{sha\-224}, %{sha\-256}, %{sha\-384}, %{sha\-512},\
+ %{sha3\-224}, %{sha3\-256}, %{sha3\-384}, %{sha3\-512},\
+ %{edon\-r256}, %{edon\-r512}, %{snefru128}, %{snefru256}"
+Print the specified hash sum. The hash is printed in uppercase, if the name
+of the hash sum starts with a capital letter, e.g. %{TTH}, %{Sha-512}.
+.IP "%x, %b, %B, %@"
+Use one of these prefixes to output a hash sum in hexadecimal, base32,
+base64 or raw (binary) format respectively, e.g. %b{md4}, %BH or %xT.
+.RE
+
+.SH CONFIG FILE
+RHash looks for a config file
+at $XDG_CONFIG_HOME/rhash/rhashrc, $HOME/.rhashrc and /etc/rhashrc.
+
+The config file consists of lines formatted as
+.RS
+variable = value
+.RE
+
+where the
+.I variable
+can be a name of any command line option, like
+.I magnet,
+.I printf,
+.I percents, etc.
+A boolean variable can be set to true by a value `on', `yes' or `true',
+any other value sets the variable to false.
+
+Empty lines and lines starting with `#' or `;' are ignored.
+
+Example config file:
+.nf
+# This is a comment line
+percents = on
+crc-accept = .sfv,.md5,.sha1,.sha256,.sha512,.tth,.magnet
+.fi
+
+.SH AUTHOR
+Aleksey Kravchenko
+.SH "SEE ALSO"
+.BR md5sum (1)
+.BR cksfv (1)
+.BR ed2k_hash (1)
+.SH BUGS
+Bug reports are welcome!
+Send them by email
+or post to the SourceForge Bug Tracking System
+.I http://sourceforge.net/projects/rhash/
diff --git a/dist/rhash.1.win.sed b/dist/rhash.1.win.sed
index e0a1f664..fa6eb761 100644
--- a/dist/rhash.1.win.sed
+++ b/dist/rhash.1.win.sed
@@ -1,19 +1,19 @@
-#!/bin/sed
-# insert encoding options before sfv
-/^\.IP "\\-\\-sfv"/ {
-i\
-.IP "\\-\\-utf8"\
-Use UTF\\-8 encoding for output.\
-.IP "\\-\\-win"\
-Use Windows codepage for output.\
-.IP "\\-\\-dos"\
-Use DOS (OEM) codepage for output.
-}
-
-/ looks for a config file/ {
-a\
-on Windows at\
-%APPDATA%\\\\RHash\\\\rhashrc, %HOMEDRIVE%%HOMEPATH%\\\\rhashrc, {PROGRAM_DIRECTORY}\\\\rhashrc\
-\
-and on Linux/Unix
-}
+#!/bin/sed
+# insert encoding options before sfv
+/^\.IP "\\-\\-sfv"/ {
+i\
+.IP "\\-\\-utf8"\
+Use UTF\\-8 encoding for output.\
+.IP "\\-\\-win"\
+Use Windows codepage for output.\
+.IP "\\-\\-dos"\
+Use DOS (OEM) codepage for output.
+}
+
+/ looks for a config file/ {
+a\
+on Windows at\
+%APPDATA%\\\\RHash\\\\rhashrc, %HOMEDRIVE%%HOMEPATH%\\\\rhashrc, {PROGRAM_DIRECTORY}\\\\rhashrc\
+\
+and on Linux/Unix
+}
diff --git a/dist/rhash.spec.in b/dist/rhash.spec.in
index 34895512..ca9e2b61 100644
--- a/dist/rhash.spec.in
+++ b/dist/rhash.spec.in
@@ -1,118 +1,118 @@
-# This file is automatically generated from rhash.spec.in
-%define version @VERSION@
-%define make %{?__make}%{!?__make:make}
-
-# major is the part of the shared library name after the .so
-%define major 0
-
-%if 0%{?mgaversion:1}
-%define libname %mklibname rhash %{major}
-%define devlibname %mklibname -d rhash
-%define opensll_dev libopenssl1.0.0-devel
-%else
-%define libname librhash%{major}
-%define devlibname rhash-devel
-%define opensll_dev openssl-devel
-%endif
-
-Summary: Utility for computing hash sums and creating magnet links.
-Name: rhash
-Version: %{version}
-Release: 1%{?dist}
-License: MIT
-%if 0%{?suse_version}
-Group: Productivity/File utilities
-%else
-Group: Applications/File
-%endif
-Vendor: Novosibirsk, Animegorodok
-Packager: Aleksey Kravchenko
-URL: http://rhash.sourceforge.net/
-Source: http://downloads.sourceforge.net/rhash/rhash-%{version}-src.tar.gz
-BuildRoot: %{_builddir}/%{name}-%{version}-root
-BuildRequires: gcc, %{opensll_dev}
-%description
-RHash is a console utility for calculation and verification of magnet links
-and a wide range of hash sums like CRC32, MD4, MD5, SHA1, SHA256, SHA512,
-AICH, ED2K, Tiger, DC++ TTH, BitTorrent BTIH, GOST R 34.11-94, RIPEMD-160,
-HAS-160, EDON-R, Whirlpool and Snefru.
-Hash sums are used to ensure and verify integrity of large volumes of data
-for a long-term storing or transferring.
-
-Features:
- * Output in a predefined (SFV, BSD-like) or a user-defined format.
- * Calculation of Magnet links.
- * Ability to process directories recursively.
- * Updating hash files (adding hash sums of files missing in the hash file).
- * Portability: the program works the same on Linux, *BSD or Windows.
-
-# LibRHash shared library, contains librhash.so.[major] only
-%package -n %{libname}
-Summary: LibRHash shared library
-Group: System/Libraries
-Provides: librhash = %{version}-%{release}
-%description -n %{libname}
-LibRHash is a professional, portable, thread-safe C library for computing
-a wide variety of hash sums, such as CRC32, MD4, MD5, SHA1, SHA256, SHA512,
-AICH, ED2K, Tiger, DC++ TTH, BitTorrent BTIH, GOST R 34.11-94, RIPEMD-160,
-HAS-160, EDON-R, Whirlpool and Snefru.
-Hash sums are used to ensure and verify integrity of large volumes of data
-for a long-term storing or transferring.
-
-%package -n %{devlibname}
-Summary: Headers and static library for LibRHash
-Group: Development/C
-Requires: %{libname} = %{version}
-#(!) MANDATORY
-Provides: librhash-devel = %{version}-%{release}
-%description -n %{devlibname}
-LibRHash is a professional, portable, thread-safe C library for computing
-a wide variety of hash sums, such as CRC32, MD4, MD5, SHA1, SHA256, SHA512,
-AICH, ED2K, Tiger, DC++ TTH, BitTorrent BTIH, GOST R 34.11-94, RIPEMD-160,
-HAS-160, EDON-R, Whirlpool and Snefru.
-Hash sums are used to ensure and verify integrity of large volumes of data
-for a long-term storing or transferring.
-
-%prep
-%setup
-
-%build
-./configure --enable-openssl-runtime --disable-gettext --enable-lib-static \
- --prefix=/usr --sysconfdir=/etc --mandir="%{_mandir}" --libdir="%{_libdir}" \
- --extra-cflags="$RPM_OPT_FLAGS"
-%{make}
-
-%check
-%{make} test
-
-%install
-%{make} install install-lib-so-link DESTDIR="$RPM_BUILD_ROOT"
-
-%clean
-rm -rf "$RPM_BUILD_ROOT"
-
-%files
-%defattr(-,root,root)
-%doc ChangeLog COPYING README
-/usr/bin/*
-/etc/rhashrc
-%{_mandir}/man1/
-
-%files -n %{devlibname}
-%defattr(-,root,root)
-%{_libdir}/librhash.a
-%{_libdir}/librhash.so
-%{_includedir}/*.h
-
-%files -n %{libname}
-%defattr(-,root,root)
-%doc COPYING README ChangeLog
-%{_libdir}/librhash.so.%{major}
-
-%post -n %{libname}
-ldconfig
-
-%postun -n %{libname}
-ldconfig
-
-%changelog
+# This file is automatically generated from rhash.spec.in
+%define version @VERSION@
+%define make %{?__make}%{!?__make:make}
+
+# major is the part of the shared library name after the .so
+%define major 0
+
+%if 0%{?mgaversion:1}
+%define libname %mklibname rhash %{major}
+%define devlibname %mklibname -d rhash
+%define opensll_dev libopenssl1.0.0-devel
+%else
+%define libname librhash%{major}
+%define devlibname rhash-devel
+%define opensll_dev openssl-devel
+%endif
+
+Summary: Utility for computing hash sums and creating magnet links.
+Name: rhash
+Version: %{version}
+Release: 1%{?dist}
+License: MIT
+%if 0%{?suse_version}
+Group: Productivity/File utilities
+%else
+Group: Applications/File
+%endif
+Vendor: Novosibirsk, Animegorodok
+Packager: Aleksey Kravchenko
+URL: http://rhash.sourceforge.net/
+Source: http://downloads.sourceforge.net/rhash/rhash-%{version}-src.tar.gz
+BuildRoot: %{_builddir}/%{name}-%{version}-root
+BuildRequires: gcc, %{opensll_dev}
+%description
+RHash is a console utility for calculation and verification of magnet links
+and a wide range of hash sums like CRC32, MD4, MD5, SHA1, SHA256, SHA512,
+AICH, ED2K, Tiger, DC++ TTH, BitTorrent BTIH, GOST R 34.11-94, RIPEMD-160,
+HAS-160, EDON-R, Whirlpool and Snefru.
+Hash sums are used to ensure and verify integrity of large volumes of data
+for a long-term storing or transferring.
+
+Features:
+ * Output in a predefined (SFV, BSD-like) or a user-defined format.
+ * Calculation of Magnet links.
+ * Ability to process directories recursively.
+ * Updating hash files (adding hash sums of files missing in the hash file).
+ * Portability: the program works the same on Linux, *BSD or Windows.
+
+# LibRHash shared library, contains librhash.so.[major] only
+%package -n %{libname}
+Summary: LibRHash shared library
+Group: System/Libraries
+Provides: librhash = %{version}-%{release}
+%description -n %{libname}
+LibRHash is a professional, portable, thread-safe C library for computing
+a wide variety of hash sums, such as CRC32, MD4, MD5, SHA1, SHA256, SHA512,
+AICH, ED2K, Tiger, DC++ TTH, BitTorrent BTIH, GOST R 34.11-94, RIPEMD-160,
+HAS-160, EDON-R, Whirlpool and Snefru.
+Hash sums are used to ensure and verify integrity of large volumes of data
+for a long-term storing or transferring.
+
+%package -n %{devlibname}
+Summary: Headers and static library for LibRHash
+Group: Development/C
+Requires: %{libname} = %{version}
+#(!) MANDATORY
+Provides: librhash-devel = %{version}-%{release}
+%description -n %{devlibname}
+LibRHash is a professional, portable, thread-safe C library for computing
+a wide variety of hash sums, such as CRC32, MD4, MD5, SHA1, SHA256, SHA512,
+AICH, ED2K, Tiger, DC++ TTH, BitTorrent BTIH, GOST R 34.11-94, RIPEMD-160,
+HAS-160, EDON-R, Whirlpool and Snefru.
+Hash sums are used to ensure and verify integrity of large volumes of data
+for a long-term storing or transferring.
+
+%prep
+%setup
+
+%build
+./configure --enable-openssl-runtime --disable-gettext --enable-lib-static \
+ --prefix=/usr --sysconfdir=/etc --mandir="%{_mandir}" --libdir="%{_libdir}" \
+ --extra-cflags="$RPM_OPT_FLAGS"
+%{make}
+
+%check
+%{make} test
+
+%install
+%{make} install install-lib-so-link DESTDIR="$RPM_BUILD_ROOT"
+
+%clean
+rm -rf "$RPM_BUILD_ROOT"
+
+%files
+%defattr(-,root,root)
+%doc ChangeLog COPYING README
+/usr/bin/*
+/etc/rhashrc
+%{_mandir}/man1/
+
+%files -n %{devlibname}
+%defattr(-,root,root)
+%{_libdir}/librhash.a
+%{_libdir}/librhash.so
+%{_includedir}/*.h
+
+%files -n %{libname}
+%defattr(-,root,root)
+%doc COPYING README ChangeLog
+%{_libdir}/librhash.so.%{major}
+
+%post -n %{libname}
+ldconfig
+
+%postun -n %{libname}
+ldconfig
+
+%changelog
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
index 82de373b..18cb353c 100644
--- a/docs/CONTRIBUTING.md
+++ b/docs/CONTRIBUTING.md
@@ -1,43 +1,43 @@
-# Contribution guidelines for the RHash project
-
-There are many ways of contributing to the project.
-* Contributing by writing code
-* Hunting bugs
-* Translating to other languages
-* Packaging RHash to a new distribution
-* Contributing money
-
-## Contributing by writing code
-* Fixing bugs and implementing features, check current [issues].
-* Updating documentation
-
-## Translating to other languages
-For online translation you need to register at the [Launchpad] platform.
-Then visit [RHash translations] and translate untranslated strings.
-
-Alternatively, you can translate one of [po files](../po/) and send a patch.
-
-## Hunting bugs
-* Test RHash with miscellaneous options. Try different OS and different environments.
-* Test compilation by different compilers.
-* Try static/dynamic analysis or phasing.
-
-If you have a found bug, try to reproduce it with the latest version, compiled from
-the [repository]. Collect information about you environment, particularly use command:
-```sh
-make -C librhash print-info
-```
-File new bugs at the [issues] page.
-
-## Packaging RHash to a new distribution
-Check if your OS distribution has the latest RHash. If not, then make a package and publish it into the OS repository.
-
-## Contributing money
-
-If you like the project, please consider [donating] a few dollars.
-
-[issues]: https://github.com/rhash/RHash/issues
-[Launchpad]: https://launchpad.net/
-[RHash translations]: https://translations.launchpad.net/rhash/
-[repository]: https://github.com/rhash/RHash/
-[donating]: http://sourceforge.net/donate/index.php?group_id=205103
+# Contribution guidelines for the RHash project
+
+There are many ways of contributing to the project.
+* Contributing by writing code
+* Hunting bugs
+* Translating to other languages
+* Packaging RHash to a new distribution
+* Contributing money
+
+## Contributing by writing code
+* Fixing bugs and implementing features, check current [issues].
+* Updating documentation
+
+## Translating to other languages
+For online translation you need to register at the [Launchpad] platform.
+Then visit [RHash translations] and translate untranslated strings.
+
+Alternatively, you can translate one of [po files](../po/) and send a patch.
+
+## Hunting bugs
+* Test RHash with miscellaneous options. Try different OS and different environments.
+* Test compilation by different compilers.
+* Try static/dynamic analysis or phasing.
+
+If you have a found bug, try to reproduce it with the latest version, compiled from
+the [repository]. Collect information about you environment, particularly use command:
+```sh
+make -C librhash print-info
+```
+File new bugs at the [issues] page.
+
+## Packaging RHash to a new distribution
+Check if your OS distribution has the latest RHash. If not, then make a package and publish it into the OS repository.
+
+## Contributing money
+
+If you like the project, please consider [donating] a few dollars.
+
+[issues]: https://github.com/rhash/RHash/issues
+[Launchpad]: https://launchpad.net/
+[RHash translations]: https://translations.launchpad.net/rhash/
+[repository]: https://github.com/rhash/RHash/
+[donating]: http://sourceforge.net/donate/index.php?group_id=205103
diff --git a/docs/LIBRHASH.md b/docs/LIBRHASH.md
index 84c78836..11e98901 100644
--- a/docs/LIBRHASH.md
+++ b/docs/LIBRHASH.md
@@ -1,127 +1,127 @@
-LibRHash Library
-================
-
-**LibRHash** is a professional, portable, thread-safe *C* library for computing a wide variety of hash sums.
-
-### Main features
-* Small and easy to learn interface.
-* Hi-level and Low-level API.
-* Calculates several hash functions simultaneously in one pass.
-* Extremely portable: works the same on Linux, Unix, macOS or Windows.
-* Written in pure C, small in size, open source.
-
-Scripting Languages Support
----------------------------
-
-LibRHash has [bindings] to several programming languages: *Java*, *C#*, *Perl*, *PHP*, *Python*, *Ruby*.
-
-License
--------
-
-The library is licensed under [RHash License].
-Basically the library and its source code can be used for free in Commercial, [Open Source] and other projects.
-
-Usage examples
---------------
-
-### Low-level interface
-
-* Calculating MD4 and MD5 digests simultaneously of a million characters of 'a'
-
-```c
- #include "rhash.h" /* LibRHash interface */
-
- int main(int argc, char *argv[]) {
- rhash context;
- char digest[64];
- char output[130];
- int i;
-
- rhash_library_init(); /* initialize static data */
-
- context = rhash_init(RHASH_MD4 | RHASH_MD5);
- if(!context) {
- fprintf(stderr, "error: couldn't initialize rhash context\n");
- return 1;
- }
-
- for(i = 0; i < 1000000; i++) {
- rhash_update(context, "a", 1);
- }
- rhash_final(context, NULL); /* finalize hash calculation */
-
- /* output digest as a hexadecimal hash string */
- rhash_print(output, context, RHASH_MD4, RHPR_UPPERCASE);
- printf("%s ('a'x1000000) = %s\n", rhash_get_name(RHASH_MD4), output);
-
- rhash_print(output, context, RHASH_MD5, RHPR_UPPERCASE);
- printf("%s ('a'x1000000) = %s\n", rhash_get_name(RHASH_MD5), output);
-
- rhash_free(context);
- return 0;
- }
-```
-
-### Hi-level interface
-
-* Calculating SHA1 hash of a string
-
-```c
- #include
- #include "rhash.h" /* LibRHash interface */
-
- int main(int argc, char *argv[])
- {
- const char* msg = "message digest";
- char digest[64];
- char output[130];
-
- rhash_library_init(); /* initialize static data */
-
- int res = rhash_msg(RHASH_SHA1, msg, strlen(msg), digest);
- if(res < 0) {
- fprintf(stderr, "hash calculation error\n");
- return 1;
- }
-
- /* convert binary digest to hexadecimal string */
- rhash_print_bytes(output, digest, rhash_get_digest_size(RHASH_SHA1),
- (RHPR_HEX | RHPR_UPPERCASE));
-
- printf("%s (\"%s\") = %s\n", rhash_get_name(RHASH_SHA1), msg, output);
- return 0;
- }
-```
-
-* Calculating TTH hash of a file
-
-```c
- #include
- #include "rhash.h" /* LibRHash interface */
-
- int main(int argc, char *argv[])
- {
- const char* filepath = "test_file.txt";
- char digest[64];
- char output[130];
-
- rhash_library_init(); /* initialize static data */
-
- int res = rhash_file(RHASH_TTH, filepath, digest);
- if(res < 0) {
- fprintf(stderr, "LibRHash error: %s: %s\n", filepath, strerror(errno));
- return 1;
- }
-
- /* convert binary digest to hexadecimal string */
- rhash_print_bytes(output, digest, rhash_get_digest_size(RHASH_TTH),
- (RHPR_BASE32 | RHPR_UPPERCASE));
-
- printf("%s (%s) = %s\n", rhash_get_name(RHASH_TTH), filepath, output);
- return 0;
- }
-```
-
-[bindings]: ../bindings/
-[RHash License]: ../COPYING
-[Open Source]: http://en.wikipedia.org/wiki/Open_Source
+LibRHash Library
+================
+
+**LibRHash** is a professional, portable, thread-safe *C* library for computing a wide variety of hash sums.
+
+### Main features
+* Small and easy to learn interface.
+* Hi-level and Low-level API.
+* Calculates several hash functions simultaneously in one pass.
+* Extremely portable: works the same on Linux, Unix, macOS or Windows.
+* Written in pure C, small in size, open source.
+
+Scripting Languages Support
+---------------------------
+
+LibRHash has [bindings] to several programming languages: *Java*, *C#*, *Perl*, *PHP*, *Python*, *Ruby*.
+
+License
+-------
+
+The library is licensed under [RHash License].
+Basically the library and its source code can be used for free in Commercial, [Open Source] and other projects.
+
+Usage examples
+--------------
+
+### Low-level interface
+
+* Calculating MD4 and MD5 digests simultaneously of a million characters of 'a'
+
+```c
+ #include "rhash.h" /* LibRHash interface */
+
+ int main(int argc, char *argv[]) {
+ rhash context;
+ char digest[64];
+ char output[130];
+ int i;
+
+ rhash_library_init(); /* initialize static data */
+
+ context = rhash_init(RHASH_MD4 | RHASH_MD5);
+ if(!context) {
+ fprintf(stderr, "error: couldn't initialize rhash context\n");
+ return 1;
+ }
+
+ for(i = 0; i < 1000000; i++) {
+ rhash_update(context, "a", 1);
+ }
+ rhash_final(context, NULL); /* finalize hash calculation */
+
+ /* output digest as a hexadecimal hash string */
+ rhash_print(output, context, RHASH_MD4, RHPR_UPPERCASE);
+ printf("%s ('a'x1000000) = %s\n", rhash_get_name(RHASH_MD4), output);
+
+ rhash_print(output, context, RHASH_MD5, RHPR_UPPERCASE);
+ printf("%s ('a'x1000000) = %s\n", rhash_get_name(RHASH_MD5), output);
+
+ rhash_free(context);
+ return 0;
+ }
+```
+
+### Hi-level interface
+
+* Calculating SHA1 hash of a string
+
+```c
+ #include
+ #include "rhash.h" /* LibRHash interface */
+
+ int main(int argc, char *argv[])
+ {
+ const char* msg = "message digest";
+ char digest[64];
+ char output[130];
+
+ rhash_library_init(); /* initialize static data */
+
+ int res = rhash_msg(RHASH_SHA1, msg, strlen(msg), digest);
+ if(res < 0) {
+ fprintf(stderr, "hash calculation error\n");
+ return 1;
+ }
+
+ /* convert binary digest to hexadecimal string */
+ rhash_print_bytes(output, digest, rhash_get_digest_size(RHASH_SHA1),
+ (RHPR_HEX | RHPR_UPPERCASE));
+
+ printf("%s (\"%s\") = %s\n", rhash_get_name(RHASH_SHA1), msg, output);
+ return 0;
+ }
+```
+
+* Calculating TTH hash of a file
+
+```c
+ #include
+ #include "rhash.h" /* LibRHash interface */
+
+ int main(int argc, char *argv[])
+ {
+ const char* filepath = "test_file.txt";
+ char digest[64];
+ char output[130];
+
+ rhash_library_init(); /* initialize static data */
+
+ int res = rhash_file(RHASH_TTH, filepath, digest);
+ if(res < 0) {
+ fprintf(stderr, "LibRHash error: %s: %s\n", filepath, strerror(errno));
+ return 1;
+ }
+
+ /* convert binary digest to hexadecimal string */
+ rhash_print_bytes(output, digest, rhash_get_digest_size(RHASH_TTH),
+ (RHPR_BASE32 | RHPR_UPPERCASE));
+
+ printf("%s (%s) = %s\n", rhash_get_name(RHASH_TTH), filepath, output);
+ return 0;
+ }
+```
+
+[bindings]: ../bindings/
+[RHash License]: ../COPYING
+[Open Source]: http://en.wikipedia.org/wiki/Open_Source
diff --git a/file.c b/file.c
index cc85f6bd..52ce1b4c 100644
--- a/file.c
+++ b/file.c
@@ -1,722 +1,722 @@
-/* file.c - file abstraction layer */
-
-/* use 64-bit off_t.
- * these macros must be defined before any included file */
-#undef _LARGEFILE64_SOURCE
-#undef _FILE_OFFSET_BITS
-#define _LARGEFILE64_SOURCE
-#define _FILE_OFFSET_BITS 64
-
-#include
-#include
-#include
-#include
-#include
-#include "file.h"
-#include "common_func.h"
-#include "win_utils.h"
-
-#if defined( _WIN32) || defined(__CYGWIN__)
-# include
-#if !defined(__CYGWIN__)
-# include /* for _SH_DENYWR */
-#endif
-# include /* _O_RDONLY, _O_BINARY */
-# include
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*=========================================================================
- * Path functions
- *=========================================================================*/
-
-/**
- * Return file name without path.
- *
- * @param path file path
- * @return file name
- */
-const char* get_basename(const char* path)
-{
- const char *p = path + strlen(path) - 1;
- for (; p >= path && !IS_PATH_SEPARATOR(*p); p--);
- return (p+1);
-}
-
-/**
- * Return allocated buffer with the directory part of the path.
- * The buffer must be freed by calling free().
- *
- * @param path file path
- * @return directory
- */
-char* get_dirname(const char* path)
-{
- const char *p = path + strlen(path) - 1;
- char *res;
- for (; p > path && !IS_PATH_SEPARATOR(*p); p--);
- if ((p - path) > 1) {
- res = (char*)rsh_malloc(p-path+1);
- memcpy(res, path, p-path);
- res[p-path] = 0;
- return res;
- } else {
- return rsh_strdup(".");
- }
-}
-
-/**
- * Assemble a filepath from its directory and filename.
- *
- * @param dir_path directory path
- * @param filename the file name
- * @return assembled file path
- */
-char* make_path(const char* dir_path, const char* filename)
-{
- char* buf;
- size_t len;
- assert(dir_path);
- assert(filename);
-
- /* remove leading path separators from filename */
- while (IS_PATH_SEPARATOR(*filename)) filename++;
-
- if (dir_path[0] == '.' && dir_path[1] == 0) {
- /* do not extend filename for dir_path="." */
- return rsh_strdup(filename);
- }
-
- /* copy directory path */
- len = strlen(dir_path);
- buf = (char*)rsh_malloc(len + strlen(filename) + 2);
- strcpy(buf, dir_path);
-
- /* separate directory from filename */
- if (len > 0 && !IS_PATH_SEPARATOR(buf[len-1])) {
- buf[len++] = SYS_PATH_SEPARATOR;
- }
-
- /* append filename */
- strcpy(buf+len, filename);
- return buf;
-}
-
-#define IS_ANY_SLASH(c) ((c) == RSH_T('/') || (c) == RSH_T('\\'))
-
-/**
- * Compare paths.
- *
- * @param a the first path
- * @param b the second path
- * @return 1 if paths a equal, 0 otherwise
- */
-int are_paths_equal(ctpath_t a, ctpath_t b)
-{
- if (!a || !b) return 0;
- if (a[0] == RSH_T('.') && IS_ANY_SLASH(a[1])) a += 2;
- if (b[0] == RSH_T('.') && IS_ANY_SLASH(b[1])) b += 2;
-
- for (; *a; ++a, ++b) {
- if (*a != *b && (!IS_ANY_SLASH(*b) || !IS_ANY_SLASH(*a))) {
- /* paths are different */
- return 0;
- }
- }
- /* check if both paths terminated */
- return (*a == *b);
-}
-
-/**
- * Check if a path points to a regular file.
- *
- * @param path the path to check
- * @return 1 if file exists an is a regular file, 0 otherwise
- */
-int is_regular_file(const char* path)
-{
- int is_regular = 0;
- file_t file;
- file_init(&file, path, FILE_OPT_DONT_FREE_PATH);
- if (file_stat(&file, 0) >= 0) {
- is_regular = FILE_ISREG(&file);
- }
- file_cleanup(&file);
- return is_regular;
-}
-
-/*=========================================================================
- * file_t functions
- *=========================================================================*/
-
-/**
- * Initialize file_t structure, associating it with the given file path.
- *
- * @param file the file_t structure to initialize
- * @param path the file path
- * @param init_flags initialization flags
- */
-void file_init(file_t* file, const char* path, int init_flags)
-{
- memset(file, 0, sizeof(*file));
- file->mode = (unsigned)init_flags;
- if ((init_flags & FILE_OPT_DONT_FREE_PATH) != 0) {
- file->path = (char*)path;
- } else {
- file->path = rsh_strdup(path);
- }
-}
-
-#ifdef _WIN32
-/**
- * Initialize file_t structure, associating it with the given file path.
- *
- * @param file the file_t structure to initialize
- * @param tpath the file path
- * @param init_flags initialization flags
- */
-void file_tinit(file_t* file, ctpath_t tpath, int init_flags)
-{
- memset(file, 0, sizeof(*file));
- file->mode = (unsigned)init_flags & ~FILE_OPT_DONT_FREE_PATH;
- if ((init_flags & FILE_OPT_DONT_FREE_PATH) != 0) {
- file->wpath = (wchar_t*)tpath;
- file->mode |= FILE_OPT_DONT_FREE_WPATH;
- } else {
- file->wpath = rsh_wcsdup(tpath);
- }
-}
-
-/**
- * Get the path of the file as a c-string.
- * On Windows lossy unicode conversion can be applied.
- *
- * @param file the file to get the path
- * @return the path of the file
- */
-const char* file_cpath(file_t* file)
-{
- if (!file->path && file->wpath) file->path = w2c(file->wpath);
- return file->path;
-}
-#endif
-
-/**
- * Free the memory allocated by the fields of the file_t structure.
- *
- * @param file the file_t structure to clean
- */
-void file_cleanup(file_t* file)
-{
- if ((file->mode & FILE_OPT_DONT_FREE_PATH) == 0)
- free(file->path);
- file->path = NULL;
-
-#ifdef _WIN32
- if ((file->mode & FILE_OPT_DONT_FREE_WPATH) == 0)
- free(file->wpath);
- file->wpath = NULL;
-#endif /* _WIN32 */
-
- free(file->data);
- file->data = NULL;
- file->mtime = 0;
- file->size = 0;
- file->mode = 0;
-}
-
-/**
- * Append the specified suffix to the src file path.
- *
- * @param dst result of appending
- * @param src the path to append the suffix to
- * @param suffix the suffix to append
- */
-void file_path_append(file_t* dst, const file_t* src, const char* suffix)
-{
- size_t src_len;
- size_t dst_len;
- memset(dst, 0, sizeof(*dst));
-#ifdef _WIN32
- if (src->wpath)
- {
- wchar_t* wsuffix = c2w(suffix, 0);
- assert(wsuffix != 0);
- src_len = wcslen(src->wpath);
- dst_len = src_len + wcslen(wsuffix) + 1;
- dst->wpath = (wchar_t*)rsh_malloc(dst_len * sizeof(wchar_t));
- wcscpy(dst->wpath, src->wpath);
- wcscpy(dst->wpath + src_len, wsuffix);
- dst->path = w2c(dst->wpath); /* for legacy file handling */
- return;
- }
-#endif
- assert(!!src->path);
- src_len = strlen(src->path);
- dst_len = src_len + strlen(suffix) + 1;
- dst->path = (char*)rsh_malloc(dst_len);
- strcpy(dst->path, src->path);
- strcpy(dst->path + src_len, suffix);
-}
-
-#ifdef _WIN32
-/**
- * Retrieve file information (type, size, mtime) into file_t fields.
- *
- * @param file the file information
- * @return 0 on success, -1 on error
- */
-static int file_statw(file_t* file)
-{
- WIN32_FILE_ATTRIBUTE_DATA data;
- wchar_t* long_path = get_long_path_if_needed(file->wpath);
-
- /* read file attributes */
- if (GetFileAttributesExW((long_path ? long_path : file->wpath), GetFileExInfoStandard, &data)) {
- uint64_t u;
- file->size = (((uint64_t)data.nFileSizeHigh) << 32) + data.nFileSizeLow;
- file->mode |= (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? FILE_IFDIR : FILE_IFREG);
- if ((data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0)
- file->mode |= FILE_IFLNK;
-
- /* the number of 100-nanosecond intervals since January 1, 1601 */
- u = (((uint64_t)data.ftLastWriteTime.dwHighDateTime) << 32) + data.ftLastWriteTime.dwLowDateTime;
- /* convert to second and subtract the epoch difference */
- file->mtime = u / 10000000 - 11644473600LL;
- free(long_path);
- return 0;
- }
- free(long_path);
- set_errno_from_last_file_error();
- return -1;
-}
-#endif
-
-/**
- * Retrieve file information (type, size, mtime) into file_t fields.
- *
- * @param file the file information
- * @param fstat_flags bitmask consisting of FileStatModes bits
- * @return 0 on success, -1 on error
- */
-int file_stat(file_t* file, int fstat_flags)
-{
-#ifdef _WIN32
- int i;
- (void)fstat_flags; /* ignore on windows */
-
- file->size = 0;
- file->mtime = 0;
- file->mode &= (FILE_OPT_DONT_FREE_PATH | FILE_OPT_DONT_FREE_WPATH | FILE_IFROOT | FILE_IFSTDIN);
- if (file->wpath)
- return file_statw(file);
-
- for (i = 0; i < 2; i++) {
- file->wpath = c2w_long_path(file->path, i);
- if (file->wpath == NULL) continue;
- if (file_statw(file) == 0) return 0; /* success */
- free(file->wpath);
- file->wpath = NULL;
- }
- assert(errno != 0);
- return -1;
-#else
- struct stat st;
- int res = 0;
- file->size = 0;
- file->mtime = 0;
- file->mode &= (FILE_OPT_DONT_FREE_PATH | FILE_IFROOT | FILE_IFSTDIN);
-
- if ((fstat_flags & FUseLstat) != 0) {
- if (lstat(file->path, &st) < 0) return -1;
- if (S_ISLNK(st.st_mode))
- file->mode |= FILE_IFLNK; /* it's a symlink */
- }
- else
- res = stat(file->path, &st);
-
- if (res == 0) {
- file->size = st.st_size;
- file->mtime = st.st_mtime;
-
- if (S_ISDIR(st.st_mode)) {
- file->mode |= FILE_IFDIR;
- } else if (S_ISREG(st.st_mode)) {
- /* it's a regular file or a symlink pointing to a regular file */
- file->mode |= FILE_IFREG;
- }
- }
- return res;
-#endif
-}
-
-
-/**
- * Open the file and return its decriptor.
- *
- * @param file the file information, including the path
- * @param fopen_flags bitmask consisting of FileFOpenModes bits
- * @return file descriptor on success, NULL on error
- */
-FILE* file_fopen(file_t* file, int fopen_flags)
-{
- const file_tchar* possible_modes[8] = { 0, RSH_T("r"), RSH_T("w"), RSH_T("r+"),
- 0, RSH_T("rb"), RSH_T("wb"), RSH_T("r+b") };
- const file_tchar* mode = possible_modes[fopen_flags & FOpenMask];
- assert((fopen_flags & FOpenRW) != 0);
- assert((fopen_flags & FOpenRW) != 0);
-#ifdef _WIN32
- if (!file->wpath)
- {
- int i;
- FILE* fd = 0;
- for (i = 0; i < 2; i++) {
- file->wpath = c2w_long_path(file->path, i);
- if (file->wpath == NULL) continue;
- fd = _wfsopen(file->wpath, mode, _SH_DENYNO);
- if (fd || errno != ENOENT) break;
- free(file->wpath);
- file->wpath = 0;
- }
- return fd;
- }
- return _wfsopen(file->wpath, mode, _SH_DENYNO);
-#else
- return fopen(file->path, mode);
-#endif
-}
-
-/**
- * Open file at the specified path and return its decriptor.
- *
- * @param tpath the file path
- * @param tmode the mode for file access
- * @return file descriptor on success, NULL on error
- */
-FILE* rsh_tfopen(ctpath_t tpath, file_tchar* tmode)
-{
-#ifdef _WIN32
- return _wfsopen(tpath, tmode, _SH_DENYNO);
-#else
- return fopen(tpath, tmode);
-#endif
-}
-
-/**
- * Rename or move the file. The source and destination paths should be on the same device.
- *
- * @param from the source file
- * @param to the destination path
- * @return 0 on success, -1 on error
- */
-int file_rename(file_t* from, file_t* to)
-{
-#ifdef _WIN32
- if (from->wpath && to->wpath)
- {
- /* Windows: file must be removed before overwriting it */
- _wunlink(to->wpath);
- return _wrename(from->wpath, to->wpath);
- }
- assert(from->path && to->path);
- unlink(to->path);
-#endif
- return rename(from->path, to->path);
-}
-
-/**
- * Rename a given file to *.bak, if it exists.
- *
- * @param file the file to move
- * @return 0 on success, -1 on error and errno is set
- */
-int file_move_to_bak(file_t* file)
-{
- if (file_stat(file, 0) >= 0) {
- int res;
- int save_errno;
- file_t bak_file;
- file_path_append(&bak_file, file, ".bak");
- res = file_rename(file, &bak_file);
- save_errno = errno;
- file_cleanup(&bak_file);
- if (res < 0)
- errno = save_errno;
- return res;
- }
- return -1;
-}
-
-#ifdef _WIN32
-/**
- * Check if the given file can't be opened with exclusive write access.
- *
- * @param file the file
- * @return 1 if the file is locked and can't be exclusively opened, 0 otherwise
- */
-static int can_not_open_exclusive(wchar_t* wpath)
-{
- int fd = _wsopen(wpath, _O_RDONLY | _O_BINARY, _SH_DENYWR, 0);
- if (fd < 0) return 1;
- _close(fd);
- return 0;
-}
-
-/**
- * Check if given file is write-locked, i.e. can not be opened
- * with exclusive write access.
- *
- * @param file the file
- * @return 1 if file can't be opened, 0 otherwise
- */
-int file_is_write_locked(file_t* file)
-{
- int i, res = 0;
- if (file->wpath)
- return can_not_open_exclusive(file->wpath);
- for (i = 0; i < 2 && !res; i++) {
- file->wpath = c2w_long_path(file->path, i);
- if(file->wpath && can_not_open_exclusive(file->wpath)) return 1;
- free(file->wpath);
- }
- file->wpath = NULL;
- return 0;
-}
-#endif
-
-
-/*=========================================================================
- * file-list functions
- *=========================================================================*/
-
-/**
- * Open a file, containing a list of file paths, to iterate over those paths
- * using the file_list_read() function.
- *
- * @param list the file_list_t structure to initialize
- * @param file_path the file to open
- * @return 0 on success, -1 on error and set errno
- */
-int file_list_open(file_list_t* list, file_t* file_path)
-{
- memset(list, 0, sizeof(file_list_t));
- if (!!(file_path->mode & FILE_IFSTDIN))
- {
- list->fd = stdin;
- return 0;
- }
- list->fd = file_fopen(file_path, FOpenRead | FOpenBin);
- return (list->fd ? 0 : -1);
-}
-
-/**
- * Close file_list_t and free allocated memory.
- */
-void file_list_close(file_list_t* list)
-{
- if (list->fd) {
- fclose(list->fd);
- list->fd = 0;
- }
- file_cleanup(&list->current_file);
-}
-
-enum FileListStateBits {
- NotFirstLine = 1
-};
-
-/**
- * Iterate over file list.
- *
- * @param list the file list to iterate over
- * @return 1 if the next file has been obtained, 0 on EOF or error
- */
-int file_list_read(file_list_t* list)
-{
- char buf[2048];
- file_cleanup(&list->current_file);
- while(fgets(buf, 2048, list->fd)) {
- char *p;
- char* line = buf;
- char *buf_back = buf + sizeof(buf) - 1;
- /* detect and skip BOM */
- if (buf[0] == (char)0xEF && buf[1] == (char)0xBB && buf[2] == (char)0xBF && !(list->state & NotFirstLine))
- line += 3;
- list->state |= NotFirstLine;
- for (p = line; p < buf_back && *p && *p != '\r' && *p != '\n'; p++);
- *p = 0;
- if (*line == '\0') continue; /* skip empty lines */
- file_init(&list->current_file, line, 0);
- return 1;
- }
- return 0;
-}
-
-/****************************************************************************
- * Directory functions *
- ****************************************************************************/
-#ifdef _WIN32
-struct WIN_DIR_t
-{
- WIN32_FIND_DATAW findFileData;
- HANDLE hFind;
- struct win_dirent dir;
- int state; /* 0 - not started, -1 - ended, >=0 file index */
-};
-
-/**
- * Open directory iterator for reading the directory content.
- *
- * @param dir_path directory path
- * @return pointer to directory stream. On error, NULL is returned,
- * and errno is set appropriately.
- */
-WIN_DIR* win_opendir(const char* dir_path)
-{
- WIN_DIR* d;
- wchar_t* wpath;
-
- /* append '\*' to the dir_path */
- size_t len = strlen(dir_path);
- char *path = (char*)malloc(len + 3);
- if (!path) return NULL; /* failed, malloc also set errno = ENOMEM */
- strcpy(path, dir_path);
- strcpy(path + len, "\\*");
-
- d = (WIN_DIR*)malloc(sizeof(WIN_DIR));
- if (!d) {
- free(path);
- return NULL;
- }
- memset(d, 0, sizeof(WIN_DIR));
-
- wpath = c2w_long_path(path, 0);
- d->hFind = (wpath != NULL ?
- FindFirstFileW(wpath, &d->findFileData) : INVALID_HANDLE_VALUE);
- free(wpath);
-
- if (d->hFind == INVALID_HANDLE_VALUE && GetLastError() != ERROR_ACCESS_DENIED) {
- wpath = c2w_long_path(path, 1); /* try to use secondary codepage */
- if (wpath) {
- d->hFind = FindFirstFileW(wpath, &d->findFileData);
- free(wpath);
- }
- }
- free(path);
-
- if (d->hFind == INVALID_HANDLE_VALUE && GetLastError() == ERROR_ACCESS_DENIED) {
- free(d);
- errno = EACCES;
- return NULL;
- }
- set_errno_from_last_file_error();
-
- d->state = (d->hFind == INVALID_HANDLE_VALUE ? -1 : 0);
- d->dir.d_name = NULL;
- return d;
-}
-
-/**
- * Open a directory for reading its content.
- * For simplicity the function supposes that dir_path points to an
- * existing directory and doesn't check for this error.
- * The Unicode version of the function.
- *
- * @param dir_path directory path
- * @return pointer to directory iterator
- */
-WIN_DIR* win_wopendir(const wchar_t* dir_path)
-{
- WIN_DIR* d;
-
- /* append '\*' to the dir_path */
- wchar_t *wpath = make_pathw(dir_path, (size_t)-1, L"*");
- d = (WIN_DIR*)rsh_malloc(sizeof(WIN_DIR));
-
- d->hFind = FindFirstFileW(wpath, &d->findFileData);
- free(wpath);
- if (d->hFind == INVALID_HANDLE_VALUE && GetLastError() == ERROR_ACCESS_DENIED) {
- free(d);
- errno = EACCES;
- return NULL;
- }
-
- /* note: we suppose if INVALID_HANDLE_VALUE was returned, then the file listing is empty */
- d->state = (d->hFind == INVALID_HANDLE_VALUE ? -1 : 0);
- d->dir.d_name = NULL;
- return d;
-}
-
-/**
- * Close a directory iterator.
- *
- * @param d pointer to the directory iterator
- */
-void win_closedir(WIN_DIR* d)
-{
- if (d->hFind != INVALID_HANDLE_VALUE) {
- FindClose(d->hFind);
- }
- free(d->dir.d_name);
- free(d);
-}
-
-/**
- * Read a directory content.
- *
- * @param d pointer to the directory iterator
- * @return directory entry or NULL if no entries left
- */
-struct win_dirent* win_readdir(WIN_DIR* d)
-{
- char* filename;
- int failed;
-
- if (d->state == -1) return NULL;
- if (d->dir.d_name != NULL) {
- free(d->dir.d_name);
- d->dir.d_name = NULL;
- }
-
- for (;;) {
- if (d->state > 0) {
- if ( !FindNextFileW(d->hFind, &d->findFileData) ) {
- /* the directory listing has ended */
- d->state = -1;
- return NULL;
- }
- }
- d->state++;
-
- if (d->findFileData.cFileName[0] == L'.' &&
- (d->findFileData.cFileName[1] == 0 ||
- (d->findFileData.cFileName[1] == L'.' &&
- d->findFileData.cFileName[2] == 0))) {
- /* simplified implementation, skips '.' and '..' names */
- continue;
- }
-
- d->dir.d_name = filename = wchar_to_cstr(d->findFileData.cFileName, WIN_DEFAULT_ENCODING, &failed);
-
- if (filename && !failed) {
- d->dir.d_wname = d->findFileData.cFileName;
- d->dir.d_isdir = (0 != (d->findFileData.dwFileAttributes &
- FILE_ATTRIBUTE_DIRECTORY));
- return &d->dir;
- }
- /* quietly skip an invalid filename and repeat the search */
- if (filename) {
- free(filename);
- d->dir.d_name = NULL;
- }
- }
-}
-#endif /* _WIN32 */
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif /* __cplusplus */
-
+/* file.c - file abstraction layer */
+
+/* use 64-bit off_t.
+ * these macros must be defined before any included file */
+#undef _LARGEFILE64_SOURCE
+#undef _FILE_OFFSET_BITS
+#define _LARGEFILE64_SOURCE
+#define _FILE_OFFSET_BITS 64
+
+#include
+#include
+#include
+#include
+#include
+#include "file.h"
+#include "common_func.h"
+#include "win_utils.h"
+
+#if defined( _WIN32) || defined(__CYGWIN__)
+# include
+#if !defined(__CYGWIN__)
+# include /* for _SH_DENYWR */
+#endif
+# include /* _O_RDONLY, _O_BINARY */
+# include
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=========================================================================
+ * Path functions
+ *=========================================================================*/
+
+/**
+ * Return file name without path.
+ *
+ * @param path file path
+ * @return file name
+ */
+const char* get_basename(const char* path)
+{
+ const char *p = path + strlen(path) - 1;
+ for (; p >= path && !IS_PATH_SEPARATOR(*p); p--);
+ return (p+1);
+}
+
+/**
+ * Return allocated buffer with the directory part of the path.
+ * The buffer must be freed by calling free().
+ *
+ * @param path file path
+ * @return directory
+ */
+char* get_dirname(const char* path)
+{
+ const char *p = path + strlen(path) - 1;
+ char *res;
+ for (; p > path && !IS_PATH_SEPARATOR(*p); p--);
+ if ((p - path) > 1) {
+ res = (char*)rsh_malloc(p-path+1);
+ memcpy(res, path, p-path);
+ res[p-path] = 0;
+ return res;
+ } else {
+ return rsh_strdup(".");
+ }
+}
+
+/**
+ * Assemble a filepath from its directory and filename.
+ *
+ * @param dir_path directory path
+ * @param filename the file name
+ * @return assembled file path
+ */
+char* make_path(const char* dir_path, const char* filename)
+{
+ char* buf;
+ size_t len;
+ assert(dir_path);
+ assert(filename);
+
+ /* remove leading path separators from filename */
+ while (IS_PATH_SEPARATOR(*filename)) filename++;
+
+ if (dir_path[0] == '.' && dir_path[1] == 0) {
+ /* do not extend filename for dir_path="." */
+ return rsh_strdup(filename);
+ }
+
+ /* copy directory path */
+ len = strlen(dir_path);
+ buf = (char*)rsh_malloc(len + strlen(filename) + 2);
+ strcpy(buf, dir_path);
+
+ /* separate directory from filename */
+ if (len > 0 && !IS_PATH_SEPARATOR(buf[len-1])) {
+ buf[len++] = SYS_PATH_SEPARATOR;
+ }
+
+ /* append filename */
+ strcpy(buf+len, filename);
+ return buf;
+}
+
+#define IS_ANY_SLASH(c) ((c) == RSH_T('/') || (c) == RSH_T('\\'))
+
+/**
+ * Compare paths.
+ *
+ * @param a the first path
+ * @param b the second path
+ * @return 1 if paths a equal, 0 otherwise
+ */
+int are_paths_equal(ctpath_t a, ctpath_t b)
+{
+ if (!a || !b) return 0;
+ if (a[0] == RSH_T('.') && IS_ANY_SLASH(a[1])) a += 2;
+ if (b[0] == RSH_T('.') && IS_ANY_SLASH(b[1])) b += 2;
+
+ for (; *a; ++a, ++b) {
+ if (*a != *b && (!IS_ANY_SLASH(*b) || !IS_ANY_SLASH(*a))) {
+ /* paths are different */
+ return 0;
+ }
+ }
+ /* check if both paths terminated */
+ return (*a == *b);
+}
+
+/**
+ * Check if a path points to a regular file.
+ *
+ * @param path the path to check
+ * @return 1 if file exists an is a regular file, 0 otherwise
+ */
+int is_regular_file(const char* path)
+{
+ int is_regular = 0;
+ file_t file;
+ file_init(&file, path, FILE_OPT_DONT_FREE_PATH);
+ if (file_stat(&file, 0) >= 0) {
+ is_regular = FILE_ISREG(&file);
+ }
+ file_cleanup(&file);
+ return is_regular;
+}
+
+/*=========================================================================
+ * file_t functions
+ *=========================================================================*/
+
+/**
+ * Initialize file_t structure, associating it with the given file path.
+ *
+ * @param file the file_t structure to initialize
+ * @param path the file path
+ * @param init_flags initialization flags
+ */
+void file_init(file_t* file, const char* path, int init_flags)
+{
+ memset(file, 0, sizeof(*file));
+ file->mode = (unsigned)init_flags;
+ if ((init_flags & FILE_OPT_DONT_FREE_PATH) != 0) {
+ file->path = (char*)path;
+ } else {
+ file->path = rsh_strdup(path);
+ }
+}
+
+#ifdef _WIN32
+/**
+ * Initialize file_t structure, associating it with the given file path.
+ *
+ * @param file the file_t structure to initialize
+ * @param tpath the file path
+ * @param init_flags initialization flags
+ */
+void file_tinit(file_t* file, ctpath_t tpath, int init_flags)
+{
+ memset(file, 0, sizeof(*file));
+ file->mode = (unsigned)init_flags & ~FILE_OPT_DONT_FREE_PATH;
+ if ((init_flags & FILE_OPT_DONT_FREE_PATH) != 0) {
+ file->wpath = (wchar_t*)tpath;
+ file->mode |= FILE_OPT_DONT_FREE_WPATH;
+ } else {
+ file->wpath = rsh_wcsdup(tpath);
+ }
+}
+
+/**
+ * Get the path of the file as a c-string.
+ * On Windows lossy unicode conversion can be applied.
+ *
+ * @param file the file to get the path
+ * @return the path of the file
+ */
+const char* file_cpath(file_t* file)
+{
+ if (!file->path && file->wpath) file->path = w2c(file->wpath);
+ return file->path;
+}
+#endif
+
+/**
+ * Free the memory allocated by the fields of the file_t structure.
+ *
+ * @param file the file_t structure to clean
+ */
+void file_cleanup(file_t* file)
+{
+ if ((file->mode & FILE_OPT_DONT_FREE_PATH) == 0)
+ free(file->path);
+ file->path = NULL;
+
+#ifdef _WIN32
+ if ((file->mode & FILE_OPT_DONT_FREE_WPATH) == 0)
+ free(file->wpath);
+ file->wpath = NULL;
+#endif /* _WIN32 */
+
+ free(file->data);
+ file->data = NULL;
+ file->mtime = 0;
+ file->size = 0;
+ file->mode = 0;
+}
+
+/**
+ * Append the specified suffix to the src file path.
+ *
+ * @param dst result of appending
+ * @param src the path to append the suffix to
+ * @param suffix the suffix to append
+ */
+void file_path_append(file_t* dst, const file_t* src, const char* suffix)
+{
+ size_t src_len;
+ size_t dst_len;
+ memset(dst, 0, sizeof(*dst));
+#ifdef _WIN32
+ if (src->wpath)
+ {
+ wchar_t* wsuffix = c2w(suffix, 0);
+ assert(wsuffix != 0);
+ src_len = wcslen(src->wpath);
+ dst_len = src_len + wcslen(wsuffix) + 1;
+ dst->wpath = (wchar_t*)rsh_malloc(dst_len * sizeof(wchar_t));
+ wcscpy(dst->wpath, src->wpath);
+ wcscpy(dst->wpath + src_len, wsuffix);
+ dst->path = w2c(dst->wpath); /* for legacy file handling */
+ return;
+ }
+#endif
+ assert(!!src->path);
+ src_len = strlen(src->path);
+ dst_len = src_len + strlen(suffix) + 1;
+ dst->path = (char*)rsh_malloc(dst_len);
+ strcpy(dst->path, src->path);
+ strcpy(dst->path + src_len, suffix);
+}
+
+#ifdef _WIN32
+/**
+ * Retrieve file information (type, size, mtime) into file_t fields.
+ *
+ * @param file the file information
+ * @return 0 on success, -1 on error
+ */
+static int file_statw(file_t* file)
+{
+ WIN32_FILE_ATTRIBUTE_DATA data;
+ wchar_t* long_path = get_long_path_if_needed(file->wpath);
+
+ /* read file attributes */
+ if (GetFileAttributesExW((long_path ? long_path : file->wpath), GetFileExInfoStandard, &data)) {
+ uint64_t u;
+ file->size = (((uint64_t)data.nFileSizeHigh) << 32) + data.nFileSizeLow;
+ file->mode |= (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? FILE_IFDIR : FILE_IFREG);
+ if ((data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0)
+ file->mode |= FILE_IFLNK;
+
+ /* the number of 100-nanosecond intervals since January 1, 1601 */
+ u = (((uint64_t)data.ftLastWriteTime.dwHighDateTime) << 32) + data.ftLastWriteTime.dwLowDateTime;
+ /* convert to second and subtract the epoch difference */
+ file->mtime = u / 10000000 - 11644473600LL;
+ free(long_path);
+ return 0;
+ }
+ free(long_path);
+ set_errno_from_last_file_error();
+ return -1;
+}
+#endif
+
+/**
+ * Retrieve file information (type, size, mtime) into file_t fields.
+ *
+ * @param file the file information
+ * @param fstat_flags bitmask consisting of FileStatModes bits
+ * @return 0 on success, -1 on error
+ */
+int file_stat(file_t* file, int fstat_flags)
+{
+#ifdef _WIN32
+ int i;
+ (void)fstat_flags; /* ignore on windows */
+
+ file->size = 0;
+ file->mtime = 0;
+ file->mode &= (FILE_OPT_DONT_FREE_PATH | FILE_OPT_DONT_FREE_WPATH | FILE_IFROOT | FILE_IFSTDIN);
+ if (file->wpath)
+ return file_statw(file);
+
+ for (i = 0; i < 2; i++) {
+ file->wpath = c2w_long_path(file->path, i);
+ if (file->wpath == NULL) continue;
+ if (file_statw(file) == 0) return 0; /* success */
+ free(file->wpath);
+ file->wpath = NULL;
+ }
+ assert(errno != 0);
+ return -1;
+#else
+ struct stat st;
+ int res = 0;
+ file->size = 0;
+ file->mtime = 0;
+ file->mode &= (FILE_OPT_DONT_FREE_PATH | FILE_IFROOT | FILE_IFSTDIN);
+
+ if ((fstat_flags & FUseLstat) != 0) {
+ if (lstat(file->path, &st) < 0) return -1;
+ if (S_ISLNK(st.st_mode))
+ file->mode |= FILE_IFLNK; /* it's a symlink */
+ }
+ else
+ res = stat(file->path, &st);
+
+ if (res == 0) {
+ file->size = st.st_size;
+ file->mtime = st.st_mtime;
+
+ if (S_ISDIR(st.st_mode)) {
+ file->mode |= FILE_IFDIR;
+ } else if (S_ISREG(st.st_mode)) {
+ /* it's a regular file or a symlink pointing to a regular file */
+ file->mode |= FILE_IFREG;
+ }
+ }
+ return res;
+#endif
+}
+
+
+/**
+ * Open the file and return its decriptor.
+ *
+ * @param file the file information, including the path
+ * @param fopen_flags bitmask consisting of FileFOpenModes bits
+ * @return file descriptor on success, NULL on error
+ */
+FILE* file_fopen(file_t* file, int fopen_flags)
+{
+ const file_tchar* possible_modes[8] = { 0, RSH_T("r"), RSH_T("w"), RSH_T("r+"),
+ 0, RSH_T("rb"), RSH_T("wb"), RSH_T("r+b") };
+ const file_tchar* mode = possible_modes[fopen_flags & FOpenMask];
+ assert((fopen_flags & FOpenRW) != 0);
+ assert((fopen_flags & FOpenRW) != 0);
+#ifdef _WIN32
+ if (!file->wpath)
+ {
+ int i;
+ FILE* fd = 0;
+ for (i = 0; i < 2; i++) {
+ file->wpath = c2w_long_path(file->path, i);
+ if (file->wpath == NULL) continue;
+ fd = _wfsopen(file->wpath, mode, _SH_DENYNO);
+ if (fd || errno != ENOENT) break;
+ free(file->wpath);
+ file->wpath = 0;
+ }
+ return fd;
+ }
+ return _wfsopen(file->wpath, mode, _SH_DENYNO);
+#else
+ return fopen(file->path, mode);
+#endif
+}
+
+/**
+ * Open file at the specified path and return its decriptor.
+ *
+ * @param tpath the file path
+ * @param tmode the mode for file access
+ * @return file descriptor on success, NULL on error
+ */
+FILE* rsh_tfopen(ctpath_t tpath, file_tchar* tmode)
+{
+#ifdef _WIN32
+ return _wfsopen(tpath, tmode, _SH_DENYNO);
+#else
+ return fopen(tpath, tmode);
+#endif
+}
+
+/**
+ * Rename or move the file. The source and destination paths should be on the same device.
+ *
+ * @param from the source file
+ * @param to the destination path
+ * @return 0 on success, -1 on error
+ */
+int file_rename(file_t* from, file_t* to)
+{
+#ifdef _WIN32
+ if (from->wpath && to->wpath)
+ {
+ /* Windows: file must be removed before overwriting it */
+ _wunlink(to->wpath);
+ return _wrename(from->wpath, to->wpath);
+ }
+ assert(from->path && to->path);
+ unlink(to->path);
+#endif
+ return rename(from->path, to->path);
+}
+
+/**
+ * Rename a given file to *.bak, if it exists.
+ *
+ * @param file the file to move
+ * @return 0 on success, -1 on error and errno is set
+ */
+int file_move_to_bak(file_t* file)
+{
+ if (file_stat(file, 0) >= 0) {
+ int res;
+ int save_errno;
+ file_t bak_file;
+ file_path_append(&bak_file, file, ".bak");
+ res = file_rename(file, &bak_file);
+ save_errno = errno;
+ file_cleanup(&bak_file);
+ if (res < 0)
+ errno = save_errno;
+ return res;
+ }
+ return -1;
+}
+
+#ifdef _WIN32
+/**
+ * Check if the given file can't be opened with exclusive write access.
+ *
+ * @param file the file
+ * @return 1 if the file is locked and can't be exclusively opened, 0 otherwise
+ */
+static int can_not_open_exclusive(wchar_t* wpath)
+{
+ int fd = _wsopen(wpath, _O_RDONLY | _O_BINARY, _SH_DENYWR, 0);
+ if (fd < 0) return 1;
+ _close(fd);
+ return 0;
+}
+
+/**
+ * Check if given file is write-locked, i.e. can not be opened
+ * with exclusive write access.
+ *
+ * @param file the file
+ * @return 1 if file can't be opened, 0 otherwise
+ */
+int file_is_write_locked(file_t* file)
+{
+ int i, res = 0;
+ if (file->wpath)
+ return can_not_open_exclusive(file->wpath);
+ for (i = 0; i < 2 && !res; i++) {
+ file->wpath = c2w_long_path(file->path, i);
+ if(file->wpath && can_not_open_exclusive(file->wpath)) return 1;
+ free(file->wpath);
+ }
+ file->wpath = NULL;
+ return 0;
+}
+#endif
+
+
+/*=========================================================================
+ * file-list functions
+ *=========================================================================*/
+
+/**
+ * Open a file, containing a list of file paths, to iterate over those paths
+ * using the file_list_read() function.
+ *
+ * @param list the file_list_t structure to initialize
+ * @param file_path the file to open
+ * @return 0 on success, -1 on error and set errno
+ */
+int file_list_open(file_list_t* list, file_t* file_path)
+{
+ memset(list, 0, sizeof(file_list_t));
+ if (!!(file_path->mode & FILE_IFSTDIN))
+ {
+ list->fd = stdin;
+ return 0;
+ }
+ list->fd = file_fopen(file_path, FOpenRead | FOpenBin);
+ return (list->fd ? 0 : -1);
+}
+
+/**
+ * Close file_list_t and free allocated memory.
+ */
+void file_list_close(file_list_t* list)
+{
+ if (list->fd) {
+ fclose(list->fd);
+ list->fd = 0;
+ }
+ file_cleanup(&list->current_file);
+}
+
+enum FileListStateBits {
+ NotFirstLine = 1
+};
+
+/**
+ * Iterate over file list.
+ *
+ * @param list the file list to iterate over
+ * @return 1 if the next file has been obtained, 0 on EOF or error
+ */
+int file_list_read(file_list_t* list)
+{
+ char buf[2048];
+ file_cleanup(&list->current_file);
+ while(fgets(buf, 2048, list->fd)) {
+ char *p;
+ char* line = buf;
+ char *buf_back = buf + sizeof(buf) - 1;
+ /* detect and skip BOM */
+ if (buf[0] == (char)0xEF && buf[1] == (char)0xBB && buf[2] == (char)0xBF && !(list->state & NotFirstLine))
+ line += 3;
+ list->state |= NotFirstLine;
+ for (p = line; p < buf_back && *p && *p != '\r' && *p != '\n'; p++);
+ *p = 0;
+ if (*line == '\0') continue; /* skip empty lines */
+ file_init(&list->current_file, line, 0);
+ return 1;
+ }
+ return 0;
+}
+
+/****************************************************************************
+ * Directory functions *
+ ****************************************************************************/
+#ifdef _WIN32
+struct WIN_DIR_t
+{
+ WIN32_FIND_DATAW findFileData;
+ HANDLE hFind;
+ struct win_dirent dir;
+ int state; /* 0 - not started, -1 - ended, >=0 file index */
+};
+
+/**
+ * Open directory iterator for reading the directory content.
+ *
+ * @param dir_path directory path
+ * @return pointer to directory stream. On error, NULL is returned,
+ * and errno is set appropriately.
+ */
+WIN_DIR* win_opendir(const char* dir_path)
+{
+ WIN_DIR* d;
+ wchar_t* wpath;
+
+ /* append '\*' to the dir_path */
+ size_t len = strlen(dir_path);
+ char *path = (char*)malloc(len + 3);
+ if (!path) return NULL; /* failed, malloc also set errno = ENOMEM */
+ strcpy(path, dir_path);
+ strcpy(path + len, "\\*");
+
+ d = (WIN_DIR*)malloc(sizeof(WIN_DIR));
+ if (!d) {
+ free(path);
+ return NULL;
+ }
+ memset(d, 0, sizeof(WIN_DIR));
+
+ wpath = c2w_long_path(path, 0);
+ d->hFind = (wpath != NULL ?
+ FindFirstFileW(wpath, &d->findFileData) : INVALID_HANDLE_VALUE);
+ free(wpath);
+
+ if (d->hFind == INVALID_HANDLE_VALUE && GetLastError() != ERROR_ACCESS_DENIED) {
+ wpath = c2w_long_path(path, 1); /* try to use secondary codepage */
+ if (wpath) {
+ d->hFind = FindFirstFileW(wpath, &d->findFileData);
+ free(wpath);
+ }
+ }
+ free(path);
+
+ if (d->hFind == INVALID_HANDLE_VALUE && GetLastError() == ERROR_ACCESS_DENIED) {
+ free(d);
+ errno = EACCES;
+ return NULL;
+ }
+ set_errno_from_last_file_error();
+
+ d->state = (d->hFind == INVALID_HANDLE_VALUE ? -1 : 0);
+ d->dir.d_name = NULL;
+ return d;
+}
+
+/**
+ * Open a directory for reading its content.
+ * For simplicity the function supposes that dir_path points to an
+ * existing directory and doesn't check for this error.
+ * The Unicode version of the function.
+ *
+ * @param dir_path directory path
+ * @return pointer to directory iterator
+ */
+WIN_DIR* win_wopendir(const wchar_t* dir_path)
+{
+ WIN_DIR* d;
+
+ /* append '\*' to the dir_path */
+ wchar_t *wpath = make_pathw(dir_path, (size_t)-1, L"*");
+ d = (WIN_DIR*)rsh_malloc(sizeof(WIN_DIR));
+
+ d->hFind = FindFirstFileW(wpath, &d->findFileData);
+ free(wpath);
+ if (d->hFind == INVALID_HANDLE_VALUE && GetLastError() == ERROR_ACCESS_DENIED) {
+ free(d);
+ errno = EACCES;
+ return NULL;
+ }
+
+ /* note: we suppose if INVALID_HANDLE_VALUE was returned, then the file listing is empty */
+ d->state = (d->hFind == INVALID_HANDLE_VALUE ? -1 : 0);
+ d->dir.d_name = NULL;
+ return d;
+}
+
+/**
+ * Close a directory iterator.
+ *
+ * @param d pointer to the directory iterator
+ */
+void win_closedir(WIN_DIR* d)
+{
+ if (d->hFind != INVALID_HANDLE_VALUE) {
+ FindClose(d->hFind);
+ }
+ free(d->dir.d_name);
+ free(d);
+}
+
+/**
+ * Read a directory content.
+ *
+ * @param d pointer to the directory iterator
+ * @return directory entry or NULL if no entries left
+ */
+struct win_dirent* win_readdir(WIN_DIR* d)
+{
+ char* filename;
+ int failed;
+
+ if (d->state == -1) return NULL;
+ if (d->dir.d_name != NULL) {
+ free(d->dir.d_name);
+ d->dir.d_name = NULL;
+ }
+
+ for (;;) {
+ if (d->state > 0) {
+ if ( !FindNextFileW(d->hFind, &d->findFileData) ) {
+ /* the directory listing has ended */
+ d->state = -1;
+ return NULL;
+ }
+ }
+ d->state++;
+
+ if (d->findFileData.cFileName[0] == L'.' &&
+ (d->findFileData.cFileName[1] == 0 ||
+ (d->findFileData.cFileName[1] == L'.' &&
+ d->findFileData.cFileName[2] == 0))) {
+ /* simplified implementation, skips '.' and '..' names */
+ continue;
+ }
+
+ d->dir.d_name = filename = wchar_to_cstr(d->findFileData.cFileName, WIN_DEFAULT_ENCODING, &failed);
+
+ if (filename && !failed) {
+ d->dir.d_wname = d->findFileData.cFileName;
+ d->dir.d_isdir = (0 != (d->findFileData.dwFileAttributes &
+ FILE_ATTRIBUTE_DIRECTORY));
+ return &d->dir;
+ }
+ /* quietly skip an invalid filename and repeat the search */
+ if (filename) {
+ free(filename);
+ d->dir.d_name = NULL;
+ }
+ }
+}
+#endif /* _WIN32 */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
diff --git a/file.h b/file.h
index 29b6dc2f..738c0ca3 100644
--- a/file.h
+++ b/file.h
@@ -1,150 +1,150 @@
-/* file.h - file abstraction layer */
-#ifndef FILE_H
-#define FILE_H
-
-#include
-#include
-#include /* for wchar_t */
-
-#if _MSC_VER > 1300
-# include "platform.h"
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef _WIN32
-typedef wchar_t file_tchar;
-# define SYS_PATH_SEPARATOR '\\'
-# define IS_PATH_SEPARATOR(c) ((c) == '\\' || (c) == '/')
-# define IS_PATH_SEPARATOR_W(c) ((c) == L'\\' || (c) == L'/')
-#else
-typedef char file_tchar;
-# define SYS_PATH_SEPARATOR '/'
-# define IS_PATH_SEPARATOR(c) ((c) == '/')
-#endif /* _WIN32 */
-typedef file_tchar* tpath_t;
-typedef const file_tchar* ctpath_t;
-
-/* Generic path functions */
-const char* get_basename(const char* path);
-char* get_dirname(const char* path);
-char* make_path(const char* dir, const char* filename);
-int are_paths_equal(ctpath_t a, ctpath_t b);
-
-int is_regular_file(const char* path); /* shall be deprecated */
-
-/**
- * Portable file information.
- */
-typedef struct file_t
-{
- char* path;
-#ifdef _WIN32
- wchar_t* wpath;
-#endif
- char* data;
- uint64_t size;
- uint64_t mtime;
- unsigned mode;
-} file_t;
-
-#ifdef _WIN32
-# define FILE_TPATH(file) ((file)->wpath)
-#else
-# define FILE_TPATH(file) ((file)->path)
-#endif
-
-/* bit constants for the file_t.mode bit mask */
-#define FILE_IFDIR 0x01
-#define FILE_IFLNK 0x02
-#define FILE_IFREG 0x04
-#define FILE_IFROOT 0x10
-#define FILE_IFDATA 0x20
-#define FILE_IFLIST 0x40
-#define FILE_IFSTDIN 0x80
-#define FILE_IFSPEC_MASK (FILE_IFDATA | FILE_IFLIST | FILE_IFSTDIN)
-#define FILE_OPT_DONT_FREE_PATH 0x200
-#define FILE_OPT_DONT_FREE_WPATH 0x400
-
-#define FILE_ISDIR(file) ((file)->mode & FILE_IFDIR)
-#define FILE_ISLNK(file) ((file)->mode & FILE_IFLNK)
-#define FILE_ISREG(file) ((file)->mode & FILE_IFREG)
-#define FILE_ISDATA(file) ((file)->mode & FILE_IFDATA)
-#define FILE_ISLIST(file) ((file)->mode & FILE_IFLIST)
-#define FILE_ISSTDIN(file) ((file)->mode & FILE_IFSTDIN)
-#define FILE_ISSPECIAL(file) ((file)->mode & (FILE_IFSPEC_MASK))
-
-/* file functions */
-void file_init(file_t* file, const char* path, int finit_flags);
-void file_cleanup(file_t* file);
-void file_path_append(file_t* dst, const file_t* src, const char* suffix);
-
-enum FileStatModes {
- FNoMode = 0,
- FUseLstat = 1
-};
-int file_stat(file_t* file, int fstat_flags);
-
-enum FileFOpenModes {
- FOpenRead = 1,
- FOpenWrite = 2,
- FOpenRW = 3,
- FOpenBin = 4,
- FOpenMask = 7
-};
-FILE* file_fopen(file_t* file, int fopen_flags);
-FILE* rsh_tfopen(ctpath_t tpath, file_tchar* tmode);
-
-int file_rename(file_t* from, file_t* to);
-int file_move_to_bak(file_t* file);
-
-#ifdef _WIN32
-void file_tinit(file_t* file, ctpath_t tpath, int finit_flags);
-const char* file_cpath(file_t* file);
-int file_is_write_locked(file_t* file);
-#else
-# define file_tinit(file, tpath, finit_flags) file_init(file, tpath, finit_flags)
-# define file_cpath(file) ((const char*)(file)->path)
-# define file_is_write_locked(f) (0)
-#endif
-
-typedef struct file_list_t {
- FILE* fd;
- file_t current_file;
- unsigned state;
-} file_list_t;
-int file_list_open(file_list_t* list, file_t* file_path);
-int file_list_read(file_list_t* list);
-void file_list_close(file_list_t* list);
-
-#ifdef _WIN32
-/* readdir structures and functions */
-#define DIR WIN_DIR
-#define dirent win_dirent
-#define opendir win_opendir
-#define readdir win_readdir
-#define closedir win_closedir
-
-/* dirent struct for windows to traverse directory content */
-struct win_dirent {
- char* d_name; /* file name */
- wchar_t* d_wname; /* file name in Unicode (UTF-16) */
- int d_isdir; /* non-zero if file is a directory */
-};
-
-struct WIN_DIR_t;
-typedef struct WIN_DIR_t WIN_DIR;
-
-WIN_DIR* win_opendir(const char*);
-WIN_DIR* win_wopendir(const wchar_t*);
-struct win_dirent* win_readdir(WIN_DIR*);
-void win_closedir(WIN_DIR*);
-#endif
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif /* __cplusplus */
-
-#endif /* FILE_H */
+/* file.h - file abstraction layer */
+#ifndef FILE_H
+#define FILE_H
+
+#include
+#include
+#include /* for wchar_t */
+
+#if _MSC_VER > 1300
+# include "platform.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _WIN32
+typedef wchar_t file_tchar;
+# define SYS_PATH_SEPARATOR '\\'
+# define IS_PATH_SEPARATOR(c) ((c) == '\\' || (c) == '/')
+# define IS_PATH_SEPARATOR_W(c) ((c) == L'\\' || (c) == L'/')
+#else
+typedef char file_tchar;
+# define SYS_PATH_SEPARATOR '/'
+# define IS_PATH_SEPARATOR(c) ((c) == '/')
+#endif /* _WIN32 */
+typedef file_tchar* tpath_t;
+typedef const file_tchar* ctpath_t;
+
+/* Generic path functions */
+const char* get_basename(const char* path);
+char* get_dirname(const char* path);
+char* make_path(const char* dir, const char* filename);
+int are_paths_equal(ctpath_t a, ctpath_t b);
+
+int is_regular_file(const char* path); /* shall be deprecated */
+
+/**
+ * Portable file information.
+ */
+typedef struct file_t
+{
+ char* path;
+#ifdef _WIN32
+ wchar_t* wpath;
+#endif
+ char* data;
+ uint64_t size;
+ uint64_t mtime;
+ unsigned mode;
+} file_t;
+
+#ifdef _WIN32
+# define FILE_TPATH(file) ((file)->wpath)
+#else
+# define FILE_TPATH(file) ((file)->path)
+#endif
+
+/* bit constants for the file_t.mode bit mask */
+#define FILE_IFDIR 0x01
+#define FILE_IFLNK 0x02
+#define FILE_IFREG 0x04
+#define FILE_IFROOT 0x10
+#define FILE_IFDATA 0x20
+#define FILE_IFLIST 0x40
+#define FILE_IFSTDIN 0x80
+#define FILE_IFSPEC_MASK (FILE_IFDATA | FILE_IFLIST | FILE_IFSTDIN)
+#define FILE_OPT_DONT_FREE_PATH 0x200
+#define FILE_OPT_DONT_FREE_WPATH 0x400
+
+#define FILE_ISDIR(file) ((file)->mode & FILE_IFDIR)
+#define FILE_ISLNK(file) ((file)->mode & FILE_IFLNK)
+#define FILE_ISREG(file) ((file)->mode & FILE_IFREG)
+#define FILE_ISDATA(file) ((file)->mode & FILE_IFDATA)
+#define FILE_ISLIST(file) ((file)->mode & FILE_IFLIST)
+#define FILE_ISSTDIN(file) ((file)->mode & FILE_IFSTDIN)
+#define FILE_ISSPECIAL(file) ((file)->mode & (FILE_IFSPEC_MASK))
+
+/* file functions */
+void file_init(file_t* file, const char* path, int finit_flags);
+void file_cleanup(file_t* file);
+void file_path_append(file_t* dst, const file_t* src, const char* suffix);
+
+enum FileStatModes {
+ FNoMode = 0,
+ FUseLstat = 1
+};
+int file_stat(file_t* file, int fstat_flags);
+
+enum FileFOpenModes {
+ FOpenRead = 1,
+ FOpenWrite = 2,
+ FOpenRW = 3,
+ FOpenBin = 4,
+ FOpenMask = 7
+};
+FILE* file_fopen(file_t* file, int fopen_flags);
+FILE* rsh_tfopen(ctpath_t tpath, file_tchar* tmode);
+
+int file_rename(file_t* from, file_t* to);
+int file_move_to_bak(file_t* file);
+
+#ifdef _WIN32
+void file_tinit(file_t* file, ctpath_t tpath, int finit_flags);
+const char* file_cpath(file_t* file);
+int file_is_write_locked(file_t* file);
+#else
+# define file_tinit(file, tpath, finit_flags) file_init(file, tpath, finit_flags)
+# define file_cpath(file) ((const char*)(file)->path)
+# define file_is_write_locked(f) (0)
+#endif
+
+typedef struct file_list_t {
+ FILE* fd;
+ file_t current_file;
+ unsigned state;
+} file_list_t;
+int file_list_open(file_list_t* list, file_t* file_path);
+int file_list_read(file_list_t* list);
+void file_list_close(file_list_t* list);
+
+#ifdef _WIN32
+/* readdir structures and functions */
+#define DIR WIN_DIR
+#define dirent win_dirent
+#define opendir win_opendir
+#define readdir win_readdir
+#define closedir win_closedir
+
+/* dirent struct for windows to traverse directory content */
+struct win_dirent {
+ char* d_name; /* file name */
+ wchar_t* d_wname; /* file name in Unicode (UTF-16) */
+ int d_isdir; /* non-zero if file is a directory */
+};
+
+struct WIN_DIR_t;
+typedef struct WIN_DIR_t WIN_DIR;
+
+WIN_DIR* win_opendir(const char*);
+WIN_DIR* win_wopendir(const wchar_t*);
+struct win_dirent* win_readdir(WIN_DIR*);
+void win_closedir(WIN_DIR*);
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* FILE_H */
diff --git a/file_mask.c b/file_mask.c
index 69b8b82b..1283e240 100644
--- a/file_mask.c
+++ b/file_mask.c
@@ -1,86 +1,86 @@
-/* file_mask.c - matching file against a list of file masks */
-#include
-#include
-#include
-#include
-
-#include "file_mask.h"
-#include "common_func.h"
-
-/**
- * Convert the given string to lower-case then put it into
- * the specified array of 'file masks'.
- *
- * @param arr array of file masks
- * @param mask a string to add
- */
-static void file_mask_add(file_mask_array* vect, const char* mask)
-{
- rsh_vector_add_ptr(vect, str_tolower(mask));
-}
-
-/**
- * Construct array from a comma-separated list of strings.
- *
- * @param comma_separated_list the comma-separated list of strings
- * @return constructed array
- */
-file_mask_array* file_mask_new_from_list(const char* comma_separated_list)
-{
- file_mask_array* vect = file_mask_new();
- file_mask_add_list(vect, comma_separated_list);
- return vect;
-}
-
-/**
- * Split the given string by comma and put the parts into array.
- *
- * @param vect the array to put the parsed elements to
- * @param comma_separated_list the string to split
- */
-void file_mask_add_list(file_mask_array* vect, const char* comma_separated_list)
-{
- char *buf, *cur, *next;
- if (!comma_separated_list || !*comma_separated_list) {
- return;
- }
- buf = rsh_strdup(comma_separated_list);
- for (cur = buf; cur && *cur; cur = next) {
- next = strchr(cur, ',');
- if (next) *(next++) = '\0';
- if (*cur != '\0') file_mask_add(vect, cur);
- }
- free(buf);
-}
-
-/**
- * Match a given name against a list of string trailers.
- * Usually used to match a filename against list of file extensions.
- *
- * @param vect the array of string trailers
- * @param name the name to match
- * @return 1 if matched, 0 otherwise
- */
-int file_mask_match(file_mask_array* vect, const char* name)
-{
- unsigned i;
- int res = 0;
- size_t len, namelen;
- char* buf;
-
- /* all names should match against an empty array */
- if (!vect || !vect->size) return 1;
-
- /* get a lowercase name version to ignore case when matching */
- buf = str_tolower(name);
- namelen = strlen(buf);
- for (i = 0; i < vect->size; i++) {
- len = strlen((char*)vect->array[i]);
- if (namelen >= len && memcmp(buf + namelen - len, vect->array[i], len) == 0) {
- res = 1; /* matched */
- break;
- }
- }
- free(buf);
- return res;
-}
+/* file_mask.c - matching file against a list of file masks */
+#include
+#include
+#include
+#include
+
+#include "file_mask.h"
+#include "common_func.h"
+
+/**
+ * Convert the given string to lower-case then put it into
+ * the specified array of 'file masks'.
+ *
+ * @param arr array of file masks
+ * @param mask a string to add
+ */
+static void file_mask_add(file_mask_array* vect, const char* mask)
+{
+ rsh_vector_add_ptr(vect, str_tolower(mask));
+}
+
+/**
+ * Construct array from a comma-separated list of strings.
+ *
+ * @param comma_separated_list the comma-separated list of strings
+ * @return constructed array
+ */
+file_mask_array* file_mask_new_from_list(const char* comma_separated_list)
+{
+ file_mask_array* vect = file_mask_new();
+ file_mask_add_list(vect, comma_separated_list);
+ return vect;
+}
+
+/**
+ * Split the given string by comma and put the parts into array.
+ *
+ * @param vect the array to put the parsed elements to
+ * @param comma_separated_list the string to split
+ */
+void file_mask_add_list(file_mask_array* vect, const char* comma_separated_list)
+{
+ char *buf, *cur, *next;
+ if (!comma_separated_list || !*comma_separated_list) {
+ return;
+ }
+ buf = rsh_strdup(comma_separated_list);
+ for (cur = buf; cur && *cur; cur = next) {
+ next = strchr(cur, ',');
+ if (next) *(next++) = '\0';
+ if (*cur != '\0') file_mask_add(vect, cur);
+ }
+ free(buf);
+}
+
+/**
+ * Match a given name against a list of string trailers.
+ * Usually used to match a filename against list of file extensions.
+ *
+ * @param vect the array of string trailers
+ * @param name the name to match
+ * @return 1 if matched, 0 otherwise
+ */
+int file_mask_match(file_mask_array* vect, const char* name)
+{
+ unsigned i;
+ int res = 0;
+ size_t len, namelen;
+ char* buf;
+
+ /* all names should match against an empty array */
+ if (!vect || !vect->size) return 1;
+
+ /* get a lowercase name version to ignore case when matching */
+ buf = str_tolower(name);
+ namelen = strlen(buf);
+ for (i = 0; i < vect->size; i++) {
+ len = strlen((char*)vect->array[i]);
+ if (namelen >= len && memcmp(buf + namelen - len, vect->array[i], len) == 0) {
+ res = 1; /* matched */
+ break;
+ }
+ }
+ free(buf);
+ return res;
+}
diff --git a/file_mask.h b/file_mask.h
index 9c5d5e58..542c9625 100644
--- a/file_mask.h
+++ b/file_mask.h
@@ -1,25 +1,25 @@
-/* file_mask.h */
-#ifndef FILE_MASK_H
-#define FILE_MASK_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "common_func.h"
-
-/* an array to store rules for file acceptance */
-typedef struct vector_t file_mask_array;
-
-#define file_mask_new() rsh_vector_new_simple()
-#define file_mask_free(v) rsh_vector_free(v)
-
-file_mask_array* file_mask_new_from_list(const char* comma_separated_list);
-void file_mask_add_list(file_mask_array* vect, const char* comma_separated_list);
-int file_mask_match(file_mask_array* vect, const char* name);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif /* __cplusplus */
-
-#endif /* FILE_MASK_H */
+/* file_mask.h */
+#ifndef FILE_MASK_H
+#define FILE_MASK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "common_func.h"
+
+/* an array to store rules for file acceptance */
+typedef struct vector_t file_mask_array;
+
+#define file_mask_new() rsh_vector_new_simple()
+#define file_mask_free(v) rsh_vector_free(v)
+
+file_mask_array* file_mask_new_from_list(const char* comma_separated_list);
+void file_mask_add_list(file_mask_array* vect, const char* comma_separated_list);
+int file_mask_match(file_mask_array* vect, const char* name);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* FILE_MASK_H */
diff --git a/file_set.c b/file_set.c
index c65d9ccb..7d8d9312 100644
--- a/file_set.c
+++ b/file_set.c
@@ -1,192 +1,192 @@
-/* file_set.c - functions to manipulate a set of files */
-#include
-#include /* isspace */
-#include /* ptrdiff_t */
-#include /* qsort */
-#include
-
-#include "file_set.h"
-#include "common_func.h"
-#include "hash_print.h"
-#include "output.h"
-#include "parse_cmdline.h"
-#include "rhash_main.h"
-#include "librhash/rhash.h"
-
-/**
- * Generate a hash for a string.
- *
- * @param string the string to hash
- * @return a string hash
- */
-static unsigned file_set_make_hash(const char* string)
-{
- unsigned hash;
- if (rhash_msg(RHASH_CRC32, string, strlen(string), (unsigned char*)&hash) < 0)
- return 0;
- return hash;
-}
-
-/**
- * Set file path of the given item.
- *
- * @param item pointer to the item to change
- * @param filepath the file path to set
- */
-static int file_set_item_set_filepath(file_set_item* item, const char* filepath)
-{
- if (item->search_filepath != item->filepath)
- free(item->search_filepath);
- free(item->filepath);
- item->filepath = rsh_strdup(filepath);
- if (!item->filepath) return 0;
-
- /* apply str_tolower if CASE_INSENSITIVE */
- /* Note: strcasecmp() is not used instead of search_filepath due to portability issue */
- /* Note: item->search_filepath is always correctly freed by file_set_item_free() */
- item->search_filepath = (opt.flags & OPT_IGNORE_CASE ? str_tolower(item->filepath) : item->filepath);
- item->hash = file_set_make_hash(item->search_filepath);
- return 1;
-}
-
-/**
- * Allocate a file_set_item structure and initialize it with a filepath.
- *
- * @param filepath a filepath to initialize the file_set_item
- * @return allocated file_set_item structure
- */
-static file_set_item* file_set_item_new(const char* filepath)
-{
- file_set_item *item = (file_set_item*)rsh_malloc(sizeof(file_set_item));
- memset(item, 0, sizeof(file_set_item));
-
- if (filepath) {
- if (!file_set_item_set_filepath(item, filepath)) {
- free(item);
- return NULL;
- }
- }
- return item;
-}
-
-/**
- * Free memory allocated by file_set_item.
- *
- * @param item the item to delete
- */
-void file_set_item_free(file_set_item *item)
-{
- if (item->search_filepath != item->filepath) {
- free(item->search_filepath);
- }
- free(item->filepath);
- free(item);
-}
-
-/**
- * Call-back function to compare two file items by search_filepath, using hashes
- *
- * @param pp_rec1 the first item to compare
- * @param pp_rec2 the second item to compare
- * @return 0 if items are equal, -1 if pp_rec1 < pp_rec2, 1 otherwise
- */
-static int crc_pp_rec_compare(const void *pp_rec1, const void *pp_rec2)
-{
- const file_set_item *rec1 = *(file_set_item *const *)pp_rec1;
- const file_set_item *rec2 = *(file_set_item *const *)pp_rec2;
- if (rec1->hash != rec2->hash) return (rec1->hash < rec2->hash ? -1 : 1);
- return strcmp(rec1->search_filepath, rec2->search_filepath);
-}
-
-/**
- * Compare two file items by filepath.
- *
- * @param rec1 pointer to the first file_set_item structure
- * @param rec2 pointer to the second file_set_item structure
- * @return 0 if files have the same filepath, and -1 or 1 (strcmp result) if not
- */
-static int path_compare(const void *rec1, const void *rec2)
-{
- return strcmp((*(file_set_item *const *)rec1)->filepath,
- (*(file_set_item *const *)rec2)->filepath);
-}
-
-/**
- * Sort given file_set using hashes of search_filepath for fast binary search.
- *
- * @param set the file_set to sort
- */
-void file_set_sort(file_set *set)
-{
- if (set->array) qsort(set->array, set->size, sizeof(file_set_item*), crc_pp_rec_compare);
-}
-
-/**
- * Sort files in the specified file_set by file path.
- *
- * @param set the file-set to sort
- */
-void file_set_sort_by_path(file_set *set)
-{
- qsort(set->array, set->size, sizeof(file_set_item*), path_compare);
-}
-
-/**
- * Create and add a file_set_item with given filepath to given file_set
- *
- * @param set the file_set to add the item to
- * @param filepath the item file path
- */
-void file_set_add_name(file_set *set, const char* filepath)
-{
- file_set_item* item = file_set_item_new(filepath);
- if (item) file_set_add(set, item);
-}
-
-/**
- * Find a file path in the file_set.
- *
- * @param set the file_set to search
- * @param filepath the file path to search for
- * @return 1 if filepath is found, 0 otherwise
- */
-int file_set_exist(file_set *set, const char* filepath)
-{
- int a, b, c;
- int cmp, res = 0;
- unsigned hash;
- char* search_filepath;
-
- if (!set->size) return 0; /* not found */
- assert(set->array != NULL);
-
- /* apply str_tolower if case shall be ignored */
- search_filepath = (opt.flags & OPT_IGNORE_CASE ?
- str_tolower(filepath) : (char*)filepath);
-
- /* generate hash to speedup the search */
- hash = file_set_make_hash(search_filepath);
-
- /* fast binary search */
- for (a = -1, b = (int)set->size; (a + 1) < b;) {
- file_set_item *item;
-
- c = (a + b) / 2;
- assert(0 <= c && c < (int)set->size);
-
- item = (file_set_item*)set->array[c];
- if (hash != item->hash) {
- cmp = (hash < item->hash ? -1 : 1);
- } else {
- cmp = strcmp(search_filepath, item->search_filepath);
- if (cmp == 0) {
- res = 1; /* file path has been found */
- break;
- }
- }
- if (cmp < 0) b = c;
- else a = c;
- }
- if (search_filepath != filepath) free(search_filepath);
- return res;
-}
+/* file_set.c - functions to manipulate a set of files */
+#include
+#include /* isspace */
+#include /* ptrdiff_t */
+#include /* qsort */
+#include
+
+#include "file_set.h"
+#include "common_func.h"
+#include "hash_print.h"
+#include "output.h"
+#include "parse_cmdline.h"
+#include "rhash_main.h"
+#include "librhash/rhash.h"
+
+/**
+ * Generate a hash for a string.
+ *
+ * @param string the string to hash
+ * @return a string hash
+ */
+static unsigned file_set_make_hash(const char* string)
+{
+ unsigned hash;
+ if (rhash_msg(RHASH_CRC32, string, strlen(string), (unsigned char*)&hash) < 0)
+ return 0;
+ return hash;
+}
+
+/**
+ * Set file path of the given item.
+ *
+ * @param item pointer to the item to change
+ * @param filepath the file path to set
+ */
+static int file_set_item_set_filepath(file_set_item* item, const char* filepath)
+{
+ if (item->search_filepath != item->filepath)
+ free(item->search_filepath);
+ free(item->filepath);
+ item->filepath = rsh_strdup(filepath);
+ if (!item->filepath) return 0;
+
+ /* apply str_tolower if CASE_INSENSITIVE */
+ /* Note: strcasecmp() is not used instead of search_filepath due to portability issue */
+ /* Note: item->search_filepath is always correctly freed by file_set_item_free() */
+ item->search_filepath = (opt.flags & OPT_IGNORE_CASE ? str_tolower(item->filepath) : item->filepath);
+ item->hash = file_set_make_hash(item->search_filepath);
+ return 1;
+}
+
+/**
+ * Allocate a file_set_item structure and initialize it with a filepath.
+ *
+ * @param filepath a filepath to initialize the file_set_item
+ * @return allocated file_set_item structure
+ */
+static file_set_item* file_set_item_new(const char* filepath)
+{
+ file_set_item *item = (file_set_item*)rsh_malloc(sizeof(file_set_item));
+ memset(item, 0, sizeof(file_set_item));
+
+ if (filepath) {
+ if (!file_set_item_set_filepath(item, filepath)) {
+ free(item);
+ return NULL;
+ }
+ }
+ return item;
+}
+
+/**
+ * Free memory allocated by file_set_item.
+ *
+ * @param item the item to delete
+ */
+void file_set_item_free(file_set_item *item)
+{
+ if (item->search_filepath != item->filepath) {
+ free(item->search_filepath);
+ }
+ free(item->filepath);
+ free(item);
+}
+
+/**
+ * Call-back function to compare two file items by search_filepath, using hashes
+ *
+ * @param pp_rec1 the first item to compare
+ * @param pp_rec2 the second item to compare
+ * @return 0 if items are equal, -1 if pp_rec1 < pp_rec2, 1 otherwise
+ */
+static int crc_pp_rec_compare(const void *pp_rec1, const void *pp_rec2)
+{
+ const file_set_item *rec1 = *(file_set_item *const *)pp_rec1;
+ const file_set_item *rec2 = *(file_set_item *const *)pp_rec2;
+ if (rec1->hash != rec2->hash) return (rec1->hash < rec2->hash ? -1 : 1);
+ return strcmp(rec1->search_filepath, rec2->search_filepath);
+}
+
+/**
+ * Compare two file items by filepath.
+ *
+ * @param rec1 pointer to the first file_set_item structure
+ * @param rec2 pointer to the second file_set_item structure
+ * @return 0 if files have the same filepath, and -1 or 1 (strcmp result) if not
+ */
+static int path_compare(const void *rec1, const void *rec2)
+{
+ return strcmp((*(file_set_item *const *)rec1)->filepath,
+ (*(file_set_item *const *)rec2)->filepath);
+}
+
+/**
+ * Sort given file_set using hashes of search_filepath for fast binary search.
+ *
+ * @param set the file_set to sort
+ */
+void file_set_sort(file_set *set)
+{
+ if (set->array) qsort(set->array, set->size, sizeof(file_set_item*), crc_pp_rec_compare);
+}
+
+/**
+ * Sort files in the specified file_set by file path.
+ *
+ * @param set the file-set to sort
+ */
+void file_set_sort_by_path(file_set *set)
+{
+ qsort(set->array, set->size, sizeof(file_set_item*), path_compare);
+}
+
+/**
+ * Create and add a file_set_item with given filepath to given file_set
+ *
+ * @param set the file_set to add the item to
+ * @param filepath the item file path
+ */
+void file_set_add_name(file_set *set, const char* filepath)
+{
+ file_set_item* item = file_set_item_new(filepath);
+ if (item) file_set_add(set, item);
+}
+
+/**
+ * Find a file path in the file_set.
+ *
+ * @param set the file_set to search
+ * @param filepath the file path to search for
+ * @return 1 if filepath is found, 0 otherwise
+ */
+int file_set_exist(file_set *set, const char* filepath)
+{
+ int a, b, c;
+ int cmp, res = 0;
+ unsigned hash;
+ char* search_filepath;
+
+ if (!set->size) return 0; /* not found */
+ assert(set->array != NULL);
+
+ /* apply str_tolower if case shall be ignored */
+ search_filepath = (opt.flags & OPT_IGNORE_CASE ?
+ str_tolower(filepath) : (char*)filepath);
+
+ /* generate hash to speedup the search */
+ hash = file_set_make_hash(search_filepath);
+
+ /* fast binary search */
+ for (a = -1, b = (int)set->size; (a + 1) < b;) {
+ file_set_item *item;
+
+ c = (a + b) / 2;
+ assert(0 <= c && c < (int)set->size);
+
+ item = (file_set_item*)set->array[c];
+ if (hash != item->hash) {
+ cmp = (hash < item->hash ? -1 : 1);
+ } else {
+ cmp = strcmp(search_filepath, item->search_filepath);
+ if (cmp == 0) {
+ res = 1; /* file path has been found */
+ break;
+ }
+ }
+ if (cmp < 0) b = c;
+ else a = c;
+ }
+ if (search_filepath != filepath) free(search_filepath);
+ return res;
+}
diff --git a/file_set.h b/file_set.h
index f4e43fd4..5a2f253d 100644
--- a/file_set.h
+++ b/file_set.h
@@ -1,40 +1,40 @@
-/* file_set.h - functions to manipulate a set of files with their hash sums */
-#ifndef FILE_SET_H
-#define FILE_SET_H
-
-#include "calc_sums.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Filepath with its string-hash (for fast search).
- */
-typedef struct file_set_item
-{
- unsigned hash;
- char* filepath;
- char* search_filepath; /* for case-insensitive comparison */
-} file_set_item;
-
-/* array to store filenames from a parsed hash file */
-struct vector_t;
-typedef struct vector_t file_set;
-
-#define file_set_new() rsh_vector_new((void(*)(void*))file_set_item_free) /* allocate new file set */
-#define file_set_free(set) rsh_vector_free(set) /* free memory */
-#define file_set_get(set, index) ((file_set_item*)((set)->array[index])) /* get i-th element */
-#define file_set_add(set, item) rsh_vector_add_ptr(set, item) /* add a file_set_item to file_set */
-
-void file_set_item_free(file_set_item *item);
-void file_set_add_name(file_set *set, const char* filename);
-void file_set_sort(file_set *set);
-void file_set_sort_by_path(file_set *set);
-int file_set_exist(file_set *set, const char* filename);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif /* __cplusplus */
-
-#endif /* FILE_SET_H */
+/* file_set.h - functions to manipulate a set of files with their hash sums */
+#ifndef FILE_SET_H
+#define FILE_SET_H
+
+#include "calc_sums.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Filepath with its string-hash (for fast search).
+ */
+typedef struct file_set_item
+{
+ unsigned hash;
+ char* filepath;
+ char* search_filepath; /* for case-insensitive comparison */
+} file_set_item;
+
+/* array to store filenames from a parsed hash file */
+struct vector_t;
+typedef struct vector_t file_set;
+
+#define file_set_new() rsh_vector_new((void(*)(void*))file_set_item_free) /* allocate new file set */
+#define file_set_free(set) rsh_vector_free(set) /* free memory */
+#define file_set_get(set, index) ((file_set_item*)((set)->array[index])) /* get i-th element */
+#define file_set_add(set, item) rsh_vector_add_ptr(set, item) /* add a file_set_item to file_set */
+
+void file_set_item_free(file_set_item *item);
+void file_set_add_name(file_set *set, const char* filename);
+void file_set_sort(file_set *set);
+void file_set_sort_by_path(file_set *set);
+int file_set_exist(file_set *set, const char* filename);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* FILE_SET_H */
diff --git a/find_file.c b/find_file.c
index ff607095..250c47fa 100644
--- a/find_file.c
+++ b/find_file.c
@@ -1,528 +1,528 @@
-/* find_file.c - functions for recursive scan of directories. */
-
-#include
-#include
-#include
-#include
-#include
-
-#include "platform.h"
-#include "find_file.h"
-#include "common_func.h"
-#include "output.h"
-#include "win_utils.h"
-
-#ifdef _WIN32
-# include
-#else
-# include /* opendir/readdir */
-#endif
-
-#define IS_DASH_TSTR(s) ((s)[0] == RSH_T('-') && (s)[1] == RSH_T('\0'))
-#define IS_CURRENT_OR_PARENT_DIR(s) ((s)[0]=='.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2])))
-#define IS_CURRENT_OR_PARENT_DIRW(s) ((s)[0]==L'.' && (!(s)[1] || ((s)[1] == L'.' && !(s)[2])))
-
-#define RF_BLOCK_SIZE 256
-#define add_root_file(data, file) rsh_blocks_vector_add(&(data)->root_files, (file), RF_BLOCK_SIZE, sizeof(file_t))
-#define get_root_file(data, index) rsh_blocks_vector_get_item(&(data)->root_files, (index), RF_BLOCK_SIZE, file_t)
-
-static int dir_scan(file_t* start_dir, file_search_data* data);
-
-/* allocate and fill the file_search_data */
-file_search_data* file_search_data_new(void)
-{
- file_search_data* data = (file_search_data*)rsh_malloc(sizeof(file_search_data));
- memset(data, 0, sizeof(file_search_data));
- rsh_blocks_vector_init(&data->root_files);
- data->max_depth = -1;
- return data;
-}
-
-static void file_search_add_special_file(file_search_data* search_data, unsigned file_mode, tstr_t str)
-{
- file_t file;
- char* filename = (file_mode & FILE_IFSTDIN ? "(stdin)" : "(message)");
- char* ext_data = 0;
- if (file_mode & FILE_IFDATA)
- {
-#ifdef _WIN32
- ext_data = wcs_to_utf8(str);
- /* we assume that conversion alwais succeed and the following condition is never met */
- if (!ext_data)
- return;
-#else
- ext_data = rsh_strdup(str);
-#endif
- }
- file_init(&file, filename, file_mode);
- if (file_mode & FILE_IFDATA)
- {
- file.data = ext_data;
- file.size = strlen(ext_data);
- }
- add_root_file(search_data, &file);
-}
-
-void file_search_add_file(file_search_data* data, tstr_t path, unsigned file_mode)
-{
-#ifdef _WIN32
- size_t length, index;
- wchar_t* p;
-#endif
- file_t file;
-
- file_mode &= (FILE_IFLIST | FILE_IFDATA);
- assert((file_mode & (file_mode - 1)) == 0);
- if ((file_mode & FILE_IFDATA) != 0)
- {
- file_search_add_special_file(data, (FILE_IFROOT | FILE_IFDATA), path);
- return;
- }
- if (IS_DASH_TSTR(path))
- {
- file_search_add_special_file(data, (FILE_IFROOT | FILE_IFSTDIN), NULL);
- return;
- }
-
-#ifdef _WIN32
- /* remove trailing path separators, except a separator preceded by ':' */
- p = wcschr(path, L'\0') - 1;
- for (; p > path && IS_PATH_SEPARATOR_W(*p) && p[-1] != L':'; p--)
- *p = 0;
-
- length = p - path + 1;
- index = wcscspn(path, L"*?");
-
- if (index < length && wcscspn(path + index, L"/\\") >= (length - index))
- {
- /* a wildcard is found without a directory separator after it */
- wchar_t* parent;
- WIN32_FIND_DATAW d;
- HANDLE handle;
-
- /* Expand the wildcard, found in the provided file path, and store the results into
- * data->root_files. If the wildcard is not found then error is reported.
- * NB, only wildcards in the basename (the last filename) of the path are expanded. */
-
- /* find a directory separator before the file name */
- for (; index > 0 && !IS_PATH_SEPARATOR(path[index]); index--);
- parent = (IS_PATH_SEPARATOR(path[index]) ? path : 0);
-
- handle = FindFirstFileW(path, &d);
- if (INVALID_HANDLE_VALUE != handle)
- {
- do
- {
- int failed;
- if (IS_CURRENT_OR_PARENT_DIRW(d.cFileName))
- continue;
- memset(&file, 0, sizeof(file));
- file.wpath = make_pathw(parent, index + 1, d.cFileName);
- if (!file.wpath)
- continue;
-
- /* skip directories unless we are in recursive mode */
- if (data->max_depth == 0 && (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
- continue;
-
- /* convert file name */
- file.path = wchar_to_cstr(file.wpath, WIN_DEFAULT_ENCODING, &failed);
- if (!failed)
- failed = (file_stat(&file, 0) < 0);
-
- /* quietly skip unconvertible file names and nonexistent files */
- if (!file.path || failed)
- {
- if (failed)
- data->errors_count++;
- free(file.path);
- free(file.wpath);
- continue;
- }
-
- /* fill the file information */
- file.mode |= FILE_IFROOT;
- add_root_file(data, &file);
- }
- while (FindNextFileW(handle, &d));
- FindClose(handle);
- }
- else
- {
- /* report error on the specified wildcard */
- char * cpath = wchar_to_cstr(path, WIN_DEFAULT_ENCODING, NULL);
- set_errno_from_last_file_error();
- log_file_error(cpath);
- free(cpath);
- data->errors_count++;
- }
- }
- else
- {
- int failed;
- memset(&file, 0, sizeof(file));
-
- file.path = wchar_to_cstr(path, WIN_DEFAULT_ENCODING, &failed);
- if (failed)
- {
- log_error(_("can't convert the file path to local encoding: %s\n"), file.path);
- free(file.path);
- data->errors_count++;
- return;
- }
- file.wpath = path;
- if (file_stat(&file, 0) < 0)
- {
- log_file_t_error(&file);
- free(file.path);
- data->errors_count++;
- return;
- }
-
- /* mark the file as obtained from the command line */
- file.mode |= (file_mode | FILE_IFROOT);
- file.wpath = rsh_wcsdup(path);
- add_root_file(data, &file);
- }
-#else
- /* init the file and test for its existence */
- file_init(&file, path, 0);
- if (file_stat(&file, FUseLstat) < 0)
- {
- log_file_t_error(&file);
- file_cleanup(&file);
- data->errors_count++;
- return;
- }
- file.mode |= (FILE_IFROOT | file_mode);
- add_root_file(data, &file);
-#endif /* _WIN32 */
-}
-
-/**
- * Free memory allocated by the file_search_data structure
- */
-void file_search_data_free(file_search_data* data)
-{
- if (data)
- {
- size_t i;
- /* clean the memory allocated by file_t elements */
- for (i = 0; i < data->root_files.size; i++)
- {
- file_t* file = get_root_file(data, i);
- file_cleanup(file);
- }
- rsh_blocks_vector_destroy(&data->root_files);
- free(data);
- }
-}
-
-void scan_files(file_search_data* data)
-{
- size_t i;
- size_t count = data->root_files.size;
- int skip_symlinked_dirs = (data->options & FIND_FOLLOW_SYMLINKS ? 0 : FUseLstat);
-
- for (i = 0; i < count && !(data->options & FIND_CANCEL); i++)
- {
- file_t* file = get_root_file(data, i);
- assert(!!(file->mode & FILE_IFROOT));
-
- /* check if file is a directory */
- if (FILE_ISLIST(file))
- {
- file_list_t list;
- if (file_list_open(&list, file) < 0)
- {
- log_file_t_error(file);
- continue;
- }
- while (file_list_read(&list))
- {
- data->call_back(&list.current_file, data->call_back_data);
- }
- file_list_close(&list);
- }
- else if (FILE_ISDIR(file))
- {
- /* silently skip symlinks to directories if required */
- if (skip_symlinked_dirs && FILE_ISLNK(file))
- continue;
-
- if (data->max_depth != 0)
- {
- dir_scan(file, data);
- }
- else if ((data->options & FIND_LOG_ERRORS) != 0)
- {
- errno = EISDIR;
- log_file_t_error(file);
- }
- }
- else
- {
- /* process a regular file or a dash '-' path */
- data->call_back(file, data->call_back_data);
- }
- }
-}
-
-/**
- * An entry of a list containing content of a directory.
- */
-typedef struct dir_entry
-{
- struct dir_entry *next;
- char* filename;
- unsigned type; /* a directory, symlink, etc. */
-} dir_entry;
-
-/**
- * Allocate and initialize a dir_entry.
- *
- * @param next next dir_entry in list
- * @param filename a filename to store in the dir_entry
- * @param type type of dir_entry
- * @return allocated dir_entry
- */
-static dir_entry* dir_entry_new(dir_entry *next, char* filename, unsigned type)
-{
- dir_entry* e = (dir_entry*)malloc(sizeof(dir_entry));
- if (!e)
- return NULL;
- if (filename)
- {
- e->filename = rsh_strdup(filename);
- if (!e->filename)
- {
- free(e);
- return NULL;
- }
- }
- else
- {
- e->filename = NULL;
- }
- e->next = next;
- e->type = type;
- return e;
-}
-
-/**
- * Insert a dir_entry with given filename and type in list.
- *
- * @param at the position before which the entry will be inserted
- * @param filename file name
- * @param type file type
- * @return pointer to the inserted dir_entry
- */
-static dir_entry* dir_entry_insert(dir_entry **at, char* filename, unsigned type)
-{
- dir_entry* e = dir_entry_new(*at, filename, type);
- if (e)
- *at = e;
- return e;
-}
-
-/**
- * Free the first entry of the list of dir_entry elements.
- *
- * @param p pointer to the list.
- */
-static void dir_entry_drop_head(dir_entry** p)
-{
- dir_entry* e = *p;
- *p = e->next;
- free(e->filename);
- free(e);
-}
-
-/**
- * Directory iterator.
- */
-typedef struct dir_iterator
-{
- int count;
- char* dir_path;
-} dir_iterator;
-#define MAX_DIRS_DEPTH 64
-
-/**
- * Walk directory tree and call given callback function to process each file/directory.
- *
- * @param start_dir path to the directory to walk recursively
- * @param data the options specifying how to walk the directory tree
- * @return 0 on success, -1 on error
- */
-static int dir_scan(file_t* start_dir, file_search_data* data)
-{
- dir_entry *dirs_stack = NULL; /* root of the dir_list */
- dir_iterator* it;
- int level = 0;
- int max_depth = data->max_depth;
- int options = data->options;
- int fstat_flags = (data->options & FIND_FOLLOW_SYMLINKS ? 0 : FUseLstat);
- file_t file;
-
- if (max_depth < 0 || max_depth >= MAX_DIRS_DEPTH)
- max_depth = MAX_DIRS_DEPTH - 1;
-
- /* skip the directory if max_depth == 0 */
- if (!max_depth)
- return 0;
-
- if (!FILE_ISDIR(start_dir))
- {
- errno = ENOTDIR;
- return -1;
- }
-
- /* check if we should descend into the root directory */
- if ((options & (FIND_WALK_DEPTH_FIRST | FIND_SKIP_DIRS)) == 0)
- {
- if (!data->call_back(start_dir, data->call_back_data))
- return 0;
- }
-
- /* allocate array of counters of directory elements */
- it = (dir_iterator*)malloc((MAX_DIRS_DEPTH + 1) * sizeof(dir_iterator));
- if (!it)
- return -1;
-
- /* push dummy counter for the root element */
- it[0].count = 1;
- it[0].dir_path = 0;
-
- memset(&file, 0, sizeof(file));
-
- while (!(data->options & FIND_CANCEL))
- {
- dir_entry **insert_at;
- char* dir_path;
- DIR *dp;
- struct dirent *de;
-
- /* climb down from the tree */
- while (--it[level].count < 0)
- {
- /* do not need this dir_path anymore */
- free(it[level].dir_path);
-
- if (--level < 0)
- {
- /* walked the whole tree */
- assert(!dirs_stack);
- free(it);
- return 0;
- }
- }
- assert(level >= 0 && it[level].count >= 0);
-
- /* take a filename from dirs_stack and construct the next path */
- if (level)
- {
- assert(dirs_stack != NULL);
- dir_path = make_path(it[level].dir_path, dirs_stack->filename);
- dir_entry_drop_head(&dirs_stack);
- }
- else
- {
- /* the first cycle: start from a root directory */
- dir_path = rsh_strdup(start_dir->path);
- }
-
- if (!dir_path)
- continue;
-
- /* fill the next level of directories */
- level++;
- assert(level < MAX_DIRS_DEPTH);
- it[level].count = 0;
- it[level].dir_path = dir_path;
-
- if ((options & (FIND_WALK_DEPTH_FIRST | FIND_SKIP_DIRS)) == FIND_WALK_DEPTH_FIRST)
- {
- int res;
- file_init(&file, dir_path, 1);
- res = file_stat(&file, fstat_flags);
-
- /* check if we should skip the directory */
- if (res < 0 || !data->call_back(&file, data->call_back_data))
- {
- if (res < 0 && (options & FIND_LOG_ERRORS))
- data->errors_count++;
- file_cleanup(&file);
- continue;
- }
- }
- file_cleanup(&file);
-
- /* step into directory */
- dp = opendir(dir_path);
- if (!dp)
- continue;
- insert_at = &dirs_stack;
-
- while ((de = readdir(dp)) != NULL)
- {
- int res;
-
- /* skip the "." and ".." directories */
- if (IS_CURRENT_OR_PARENT_DIR(de->d_name))
- continue;
- file.mode = 0;
- file.path = make_path(dir_path, de->d_name);
- if (!file.path)
- continue;
- res = file_stat(&file, fstat_flags);
- if (res >= 0)
- {
- /* process the file or directory */
- if (FILE_ISDIR(&file) && (options & (FIND_WALK_DEPTH_FIRST | FIND_SKIP_DIRS)))
- {
- res = ((options & FIND_FOLLOW_SYMLINKS) || !FILE_ISLNK(&file));
- }
- else if (FILE_ISREG(&file))
- {
- /* handle file by callback function */
- res = data->call_back(&file, data->call_back_data);
- }
-
- /* check if file is a directory and we need to walk it, */
- /* but don't go deeper than max_depth */
- if (FILE_ISDIR(&file) && res && level < max_depth &&
- ((options & FIND_FOLLOW_SYMLINKS) || !FILE_ISLNK(&file)))
- {
- /* add the directory name to the dirs_stack */
- if (dir_entry_insert(insert_at, de->d_name, file.mode))
- {
- /* the directory name was successfully inserted */
- insert_at = &((*insert_at)->next);
- it[level].count++;
- }
- }
- }
- else if (options & FIND_LOG_ERRORS)
- {
- /* report error only if FIND_LOG_ERRORS option is set */
- log_file_t_error(&file);
- data->errors_count++;
- }
- file_cleanup(&file);
- }
- closedir(dp);
- }
-
- while (dirs_stack)
- {
- dir_entry_drop_head(&dirs_stack);
- }
- while (level)
- {
- free(it[level--].dir_path);
- }
- free(it);
- assert(file.path == 0);
- return 0;
-}
+/* find_file.c - functions for recursive scan of directories. */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "platform.h"
+#include "find_file.h"
+#include "common_func.h"
+#include "output.h"
+#include "win_utils.h"
+
+#ifdef _WIN32
+# include
+#else
+# include /* opendir/readdir */
+#endif
+
+#define IS_DASH_TSTR(s) ((s)[0] == RSH_T('-') && (s)[1] == RSH_T('\0'))
+#define IS_CURRENT_OR_PARENT_DIR(s) ((s)[0]=='.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2])))
+#define IS_CURRENT_OR_PARENT_DIRW(s) ((s)[0]==L'.' && (!(s)[1] || ((s)[1] == L'.' && !(s)[2])))
+
+#define RF_BLOCK_SIZE 256
+#define add_root_file(data, file) rsh_blocks_vector_add(&(data)->root_files, (file), RF_BLOCK_SIZE, sizeof(file_t))
+#define get_root_file(data, index) rsh_blocks_vector_get_item(&(data)->root_files, (index), RF_BLOCK_SIZE, file_t)
+
+static int dir_scan(file_t* start_dir, file_search_data* data);
+
+/* allocate and fill the file_search_data */
+file_search_data* file_search_data_new(void)
+{
+ file_search_data* data = (file_search_data*)rsh_malloc(sizeof(file_search_data));
+ memset(data, 0, sizeof(file_search_data));
+ rsh_blocks_vector_init(&data->root_files);
+ data->max_depth = -1;
+ return data;
+}
+
+static void file_search_add_special_file(file_search_data* search_data, unsigned file_mode, tstr_t str)
+{
+ file_t file;
+ char* filename = (file_mode & FILE_IFSTDIN ? "(stdin)" : "(message)");
+ char* ext_data = 0;
+ if (file_mode & FILE_IFDATA)
+ {
+#ifdef _WIN32
+ ext_data = wcs_to_utf8(str);
+ /* we assume that conversion alwais succeed and the following condition is never met */
+ if (!ext_data)
+ return;
+#else
+ ext_data = rsh_strdup(str);
+#endif
+ }
+ file_init(&file, filename, file_mode);
+ if (file_mode & FILE_IFDATA)
+ {
+ file.data = ext_data;
+ file.size = strlen(ext_data);
+ }
+ add_root_file(search_data, &file);
+}
+
+void file_search_add_file(file_search_data* data, tstr_t path, unsigned file_mode)
+{
+#ifdef _WIN32
+ size_t length, index;
+ wchar_t* p;
+#endif
+ file_t file;
+
+ file_mode &= (FILE_IFLIST | FILE_IFDATA);
+ assert((file_mode & (file_mode - 1)) == 0);
+ if ((file_mode & FILE_IFDATA) != 0)
+ {
+ file_search_add_special_file(data, (FILE_IFROOT | FILE_IFDATA), path);
+ return;
+ }
+ if (IS_DASH_TSTR(path))
+ {
+ file_search_add_special_file(data, (FILE_IFROOT | FILE_IFSTDIN), NULL);
+ return;
+ }
+
+#ifdef _WIN32
+ /* remove trailing path separators, except a separator preceded by ':' */
+ p = wcschr(path, L'\0') - 1;
+ for (; p > path && IS_PATH_SEPARATOR_W(*p) && p[-1] != L':'; p--)
+ *p = 0;
+
+ length = p - path + 1;
+ index = wcscspn(path, L"*?");
+
+ if (index < length && wcscspn(path + index, L"/\\") >= (length - index))
+ {
+ /* a wildcard is found without a directory separator after it */
+ wchar_t* parent;
+ WIN32_FIND_DATAW d;
+ HANDLE handle;
+
+ /* Expand the wildcard, found in the provided file path, and store the results into
+ * data->root_files. If the wildcard is not found then error is reported.
+ * NB, only wildcards in the basename (the last filename) of the path are expanded. */
+
+ /* find a directory separator before the file name */
+ for (; index > 0 && !IS_PATH_SEPARATOR(path[index]); index--);
+ parent = (IS_PATH_SEPARATOR(path[index]) ? path : 0);
+
+ handle = FindFirstFileW(path, &d);
+ if (INVALID_HANDLE_VALUE != handle)
+ {
+ do
+ {
+ int failed;
+ if (IS_CURRENT_OR_PARENT_DIRW(d.cFileName))
+ continue;
+ memset(&file, 0, sizeof(file));
+ file.wpath = make_pathw(parent, index + 1, d.cFileName);
+ if (!file.wpath)
+ continue;
+
+ /* skip directories unless we are in recursive mode */
+ if (data->max_depth == 0 && (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ continue;
+
+ /* convert file name */
+ file.path = wchar_to_cstr(file.wpath, WIN_DEFAULT_ENCODING, &failed);
+ if (!failed)
+ failed = (file_stat(&file, 0) < 0);
+
+ /* quietly skip unconvertible file names and nonexistent files */
+ if (!file.path || failed)
+ {
+ if (failed)
+ data->errors_count++;
+ free(file.path);
+ free(file.wpath);
+ continue;
+ }
+
+ /* fill the file information */
+ file.mode |= FILE_IFROOT;
+ add_root_file(data, &file);
+ }
+ while (FindNextFileW(handle, &d));
+ FindClose(handle);
+ }
+ else
+ {
+ /* report error on the specified wildcard */
+ char * cpath = wchar_to_cstr(path, WIN_DEFAULT_ENCODING, NULL);
+ set_errno_from_last_file_error();
+ log_file_error(cpath);
+ free(cpath);
+ data->errors_count++;
+ }
+ }
+ else
+ {
+ int failed;
+ memset(&file, 0, sizeof(file));
+
+ file.path = wchar_to_cstr(path, WIN_DEFAULT_ENCODING, &failed);
+ if (failed)
+ {
+ log_error(_("can't convert the file path to local encoding: %s\n"), file.path);
+ free(file.path);
+ data->errors_count++;
+ return;
+ }
+ file.wpath = path;
+ if (file_stat(&file, 0) < 0)
+ {
+ log_file_t_error(&file);
+ free(file.path);
+ data->errors_count++;
+ return;
+ }
+
+ /* mark the file as obtained from the command line */
+ file.mode |= (file_mode | FILE_IFROOT);
+ file.wpath = rsh_wcsdup(path);
+ add_root_file(data, &file);
+ }
+#else
+ /* init the file and test for its existence */
+ file_init(&file, path, 0);
+ if (file_stat(&file, FUseLstat) < 0)
+ {
+ log_file_t_error(&file);
+ file_cleanup(&file);
+ data->errors_count++;
+ return;
+ }
+ file.mode |= (FILE_IFROOT | file_mode);
+ add_root_file(data, &file);
+#endif /* _WIN32 */
+}
+
+/**
+ * Free memory allocated by the file_search_data structure
+ */
+void file_search_data_free(file_search_data* data)
+{
+ if (data)
+ {
+ size_t i;
+ /* clean the memory allocated by file_t elements */
+ for (i = 0; i < data->root_files.size; i++)
+ {
+ file_t* file = get_root_file(data, i);
+ file_cleanup(file);
+ }
+ rsh_blocks_vector_destroy(&data->root_files);
+ free(data);
+ }
+}
+
+void scan_files(file_search_data* data)
+{
+ size_t i;
+ size_t count = data->root_files.size;
+ int skip_symlinked_dirs = (data->options & FIND_FOLLOW_SYMLINKS ? 0 : FUseLstat);
+
+ for (i = 0; i < count && !(data->options & FIND_CANCEL); i++)
+ {
+ file_t* file = get_root_file(data, i);
+ assert(!!(file->mode & FILE_IFROOT));
+
+ /* check if file is a directory */
+ if (FILE_ISLIST(file))
+ {
+ file_list_t list;
+ if (file_list_open(&list, file) < 0)
+ {
+ log_file_t_error(file);
+ continue;
+ }
+ while (file_list_read(&list))
+ {
+ data->call_back(&list.current_file, data->call_back_data);
+ }
+ file_list_close(&list);
+ }
+ else if (FILE_ISDIR(file))
+ {
+ /* silently skip symlinks to directories if required */
+ if (skip_symlinked_dirs && FILE_ISLNK(file))
+ continue;
+
+ if (data->max_depth != 0)
+ {
+ dir_scan(file, data);
+ }
+ else if ((data->options & FIND_LOG_ERRORS) != 0)
+ {
+ errno = EISDIR;
+ log_file_t_error(file);
+ }
+ }
+ else
+ {
+ /* process a regular file or a dash '-' path */
+ data->call_back(file, data->call_back_data);
+ }
+ }
+}
+
+/**
+ * An entry of a list containing content of a directory.
+ */
+typedef struct dir_entry
+{
+ struct dir_entry *next;
+ char* filename;
+ unsigned type; /* a directory, symlink, etc. */
+} dir_entry;
+
+/**
+ * Allocate and initialize a dir_entry.
+ *
+ * @param next next dir_entry in list
+ * @param filename a filename to store in the dir_entry
+ * @param type type of dir_entry
+ * @return allocated dir_entry
+ */
+static dir_entry* dir_entry_new(dir_entry *next, char* filename, unsigned type)
+{
+ dir_entry* e = (dir_entry*)malloc(sizeof(dir_entry));
+ if (!e)
+ return NULL;
+ if (filename)
+ {
+ e->filename = rsh_strdup(filename);
+ if (!e->filename)
+ {
+ free(e);
+ return NULL;
+ }
+ }
+ else
+ {
+ e->filename = NULL;
+ }
+ e->next = next;
+ e->type = type;
+ return e;
+}
+
+/**
+ * Insert a dir_entry with given filename and type in list.
+ *
+ * @param at the position before which the entry will be inserted
+ * @param filename file name
+ * @param type file type
+ * @return pointer to the inserted dir_entry
+ */
+static dir_entry* dir_entry_insert(dir_entry **at, char* filename, unsigned type)
+{
+ dir_entry* e = dir_entry_new(*at, filename, type);
+ if (e)
+ *at = e;
+ return e;
+}
+
+/**
+ * Free the first entry of the list of dir_entry elements.
+ *
+ * @param p pointer to the list.
+ */
+static void dir_entry_drop_head(dir_entry** p)
+{
+ dir_entry* e = *p;
+ *p = e->next;
+ free(e->filename);
+ free(e);
+}
+
+/**
+ * Directory iterator.
+ */
+typedef struct dir_iterator
+{
+ int count;
+ char* dir_path;
+} dir_iterator;
+#define MAX_DIRS_DEPTH 64
+
+/**
+ * Walk directory tree and call given callback function to process each file/directory.
+ *
+ * @param start_dir path to the directory to walk recursively
+ * @param data the options specifying how to walk the directory tree
+ * @return 0 on success, -1 on error
+ */
+static int dir_scan(file_t* start_dir, file_search_data* data)
+{
+ dir_entry *dirs_stack = NULL; /* root of the dir_list */
+ dir_iterator* it;
+ int level = 0;
+ int max_depth = data->max_depth;
+ int options = data->options;
+ int fstat_flags = (data->options & FIND_FOLLOW_SYMLINKS ? 0 : FUseLstat);
+ file_t file;
+
+ if (max_depth < 0 || max_depth >= MAX_DIRS_DEPTH)
+ max_depth = MAX_DIRS_DEPTH - 1;
+
+ /* skip the directory if max_depth == 0 */
+ if (!max_depth)
+ return 0;
+
+ if (!FILE_ISDIR(start_dir))
+ {
+ errno = ENOTDIR;
+ return -1;
+ }
+
+ /* check if we should descend into the root directory */
+ if ((options & (FIND_WALK_DEPTH_FIRST | FIND_SKIP_DIRS)) == 0)
+ {
+ if (!data->call_back(start_dir, data->call_back_data))
+ return 0;
+ }
+
+ /* allocate array of counters of directory elements */
+ it = (dir_iterator*)malloc((MAX_DIRS_DEPTH + 1) * sizeof(dir_iterator));
+ if (!it)
+ return -1;
+
+ /* push dummy counter for the root element */
+ it[0].count = 1;
+ it[0].dir_path = 0;
+
+ memset(&file, 0, sizeof(file));
+
+ while (!(data->options & FIND_CANCEL))
+ {
+ dir_entry **insert_at;
+ char* dir_path;
+ DIR *dp;
+ struct dirent *de;
+
+ /* climb down from the tree */
+ while (--it[level].count < 0)
+ {
+ /* do not need this dir_path anymore */
+ free(it[level].dir_path);
+
+ if (--level < 0)
+ {
+ /* walked the whole tree */
+ assert(!dirs_stack);
+ free(it);
+ return 0;
+ }
+ }
+ assert(level >= 0 && it[level].count >= 0);
+
+ /* take a filename from dirs_stack and construct the next path */
+ if (level)
+ {
+ assert(dirs_stack != NULL);
+ dir_path = make_path(it[level].dir_path, dirs_stack->filename);
+ dir_entry_drop_head(&dirs_stack);
+ }
+ else
+ {
+ /* the first cycle: start from a root directory */
+ dir_path = rsh_strdup(start_dir->path);
+ }
+
+ if (!dir_path)
+ continue;
+
+ /* fill the next level of directories */
+ level++;
+ assert(level < MAX_DIRS_DEPTH);
+ it[level].count = 0;
+ it[level].dir_path = dir_path;
+
+ if ((options & (FIND_WALK_DEPTH_FIRST | FIND_SKIP_DIRS)) == FIND_WALK_DEPTH_FIRST)
+ {
+ int res;
+ file_init(&file, dir_path, 1);
+ res = file_stat(&file, fstat_flags);
+
+ /* check if we should skip the directory */
+ if (res < 0 || !data->call_back(&file, data->call_back_data))
+ {
+ if (res < 0 && (options & FIND_LOG_ERRORS))
+ data->errors_count++;
+ file_cleanup(&file);
+ continue;
+ }
+ }
+ file_cleanup(&file);
+
+ /* step into directory */
+ dp = opendir(dir_path);
+ if (!dp)
+ continue;
+ insert_at = &dirs_stack;
+
+ while ((de = readdir(dp)) != NULL)
+ {
+ int res;
+
+ /* skip the "." and ".." directories */
+ if (IS_CURRENT_OR_PARENT_DIR(de->d_name))
+ continue;
+ file.mode = 0;
+ file.path = make_path(dir_path, de->d_name);
+ if (!file.path)
+ continue;
+ res = file_stat(&file, fstat_flags);
+ if (res >= 0)
+ {
+ /* process the file or directory */
+ if (FILE_ISDIR(&file) && (options & (FIND_WALK_DEPTH_FIRST | FIND_SKIP_DIRS)))
+ {
+ res = ((options & FIND_FOLLOW_SYMLINKS) || !FILE_ISLNK(&file));
+ }
+ else if (FILE_ISREG(&file))
+ {
+ /* handle file by callback function */
+ res = data->call_back(&file, data->call_back_data);
+ }
+
+ /* check if file is a directory and we need to walk it, */
+ /* but don't go deeper than max_depth */
+ if (FILE_ISDIR(&file) && res && level < max_depth &&
+ ((options & FIND_FOLLOW_SYMLINKS) || !FILE_ISLNK(&file)))
+ {
+ /* add the directory name to the dirs_stack */
+ if (dir_entry_insert(insert_at, de->d_name, file.mode))
+ {
+ /* the directory name was successfully inserted */
+ insert_at = &((*insert_at)->next);
+ it[level].count++;
+ }
+ }
+ }
+ else if (options & FIND_LOG_ERRORS)
+ {
+ /* report error only if FIND_LOG_ERRORS option is set */
+ log_file_t_error(&file);
+ data->errors_count++;
+ }
+ file_cleanup(&file);
+ }
+ closedir(dp);
+ }
+
+ while (dirs_stack)
+ {
+ dir_entry_drop_head(&dirs_stack);
+ }
+ while (level)
+ {
+ free(it[level--].dir_path);
+ }
+ free(it);
+ assert(file.path == 0);
+ return 0;
+}
diff --git a/find_file.h b/find_file.h
index f9cb8d6c..c8499d80 100644
--- a/find_file.h
+++ b/find_file.h
@@ -1,42 +1,42 @@
-/* find_file.h - functions for recursive scan of directories. */
-#ifndef FIND_FILE_H
-#define FIND_FILE_H
-
-#include "common_func.h"
-#include "file.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* find_file options */
-#define FIND_WALK_DEPTH_FIRST 1
-#define FIND_FOLLOW_SYMLINKS 2
-#define FIND_SKIP_DIRS 4
-#define FIND_LOG_ERRORS 8
-#define FIND_CANCEL 16
-
-/**
- * Options for file search.
- */
-typedef struct file_search_data
-{
- int options;
- int max_depth;
- blocks_vector_t root_files;
- int (*call_back)(file_t* file, int data);
- int call_back_data;
- int errors_count;
-} file_search_data;
-
-file_search_data* file_search_data_new(void);
-void file_search_add_file(file_search_data* data, tstr_t path, unsigned file_mode);
-void file_search_data_free(file_search_data* data);
-
-void scan_files(file_search_data* data);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif /* __cplusplus */
-
-#endif /* FIND_FILE_H */
+/* find_file.h - functions for recursive scan of directories. */
+#ifndef FIND_FILE_H
+#define FIND_FILE_H
+
+#include "common_func.h"
+#include "file.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* find_file options */
+#define FIND_WALK_DEPTH_FIRST 1
+#define FIND_FOLLOW_SYMLINKS 2
+#define FIND_SKIP_DIRS 4
+#define FIND_LOG_ERRORS 8
+#define FIND_CANCEL 16
+
+/**
+ * Options for file search.
+ */
+typedef struct file_search_data
+{
+ int options;
+ int max_depth;
+ blocks_vector_t root_files;
+ int (*call_back)(file_t* file, int data);
+ int call_back_data;
+ int errors_count;
+} file_search_data;
+
+file_search_data* file_search_data_new(void);
+void file_search_add_file(file_search_data* data, tstr_t path, unsigned file_mode);
+void file_search_data_free(file_search_data* data);
+
+void scan_files(file_search_data* data);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* FIND_FILE_H */
diff --git a/hash_check.c b/hash_check.c
index b5371374..1e46b253 100644
--- a/hash_check.c
+++ b/hash_check.c
@@ -1,715 +1,715 @@
-/* hash_check.c - verification of hashes of files */
-
-#include
-#include /* isspace */
-#include
-
-#include "hash_check.h"
-#include "hash_print.h"
-#include "common_func.h"
-#include "output.h"
-#include "parse_cmdline.h"
-#include "librhash/rhash.h"
-
-/* hash conversion macros and functions */
-#define HEX2DIGIT(c) ((c) <= '9' ? (c) & 0xF : ((c) - 'a' + 10) & 0xF)
-#define BASE32_TO_DIGIT(c) ((c) < 'A' ? (c) - '2' + 26 : ((c) & ~0x20) - 'A')
-#define BASE32_LENGTH(bytes) (((bytes) * 8 + 4) / 5)
-
-/**
- * Convert a hexadecimal string to a string of bytes.
- *
- * @param str string to parse
- * @param bin result
- * @param len string length
- */
-void rhash_hex_to_byte(const char* str, unsigned char* bin, int len)
-{
- /* parse the highest hexadecimal digit */
- if ((len & 1) != 0) {
- *(bin++) = HEX2DIGIT(*(str++));
- len--;
- }
-
- /* parse the rest - an even-sized hexadecimal string */
- for (; len >= 2; len -= 2, str += 2) {
- *(bin++) = (HEX2DIGIT(str[0]) << 4) | HEX2DIGIT(str[1]);
- }
-}
-
-/**
- * Decode an URL-encoded string in the specified buffer.
- *
- * @param buffer the 0-terminated URL-encoded string
- */
-static void urldecode(char *buffer)
-{
- char *wpos = buffer; /* set writing position */
- for (; *buffer; wpos++) {
- *wpos = *(buffer++); /* copy non-escaped characters */
- if (*wpos == '%') {
- if (*buffer == '%') {
- buffer++; /* interpret '%%' as single '%' */
- } else if (IS_HEX(*buffer)) {
- /* decode character from the % form */
- int ch = HEX2DIGIT(*buffer);
- buffer++;
- if (IS_HEX(*buffer)) {
- ch = (ch << 4) | HEX2DIGIT(*buffer);
- buffer++;
- }
- *wpos = (char)ch;
- }
- }
- }
- *wpos = '\0'; /* terminate decoded string */
-}
-
-#ifndef _WIN32
-/**
- * Convert a windows file path to a UNIX one, replacing '\\' by '/'.
- *
- * @param path the path to convert
- * @return converted path
- */
-static void process_backslashes(char* path)
-{
- for (;*path;path++) {
- if (*path == '\\') *path = '/';
- }
-}
-#else /* _WIN32 */
-#define process_backslashes(path)
-#endif /* _WIN32 */
-
-
-/* convert a hash flag to index */
-#if __GNUC__ >= 4 || (__GNUC__ ==3 && __GNUC_MINOR__ >= 4) /* GCC < 3.4 */
-# define get_ctz(x) __builtin_ctz(x)
-#else
-
-/**
- * Returns index of the trailing bit of a 32-bit number.
- * This is a plain C equivalent for GCC __builtin_ctz() bit scan.
- *
- * @param x the number to process
- * @return zero-based index of the trailing bit
- */
-static unsigned get_ctz(unsigned x)
-{
- /* see http://graphics.stanford.edu/~seander/bithacks.html */
- static unsigned char bit_pos[32] = {
- 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
- 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
- };
- return bit_pos[((uint32_t)((x & -(int)x) * 0x077CB531U)) >> 27];
-}
-#endif /* (GCC >= 4.3) */
-
-/**
- * Encode a hash function digest size into a small number in [0,...,7].
- * The digest size must be in the set { 4, 16, 20, 24, 28, 32, 48, 64 }.
- *
- * @param digest_size digest size (aka hash length) in bytes
- * @return code for digest size on success, 32 on error
- */
-static int code_digest_size(int digest_size)
-{
- static int size_codes[17] = {
- -1, 0,-1, -1, 1, 2, 3, 4, 5, -1,
- -1, -1, 6, -1, -1, -1, 7
- };
- return (digest_size <= 64 ? size_codes[digest_size / 4] : -1);
-}
-
-/**
- * Calculate an OR-ed mask of hash-ids by a length of hash in bytes.
- *
- * @param digest_size length of a hash in bytes.
- * @return mask of hash-ids with given hash length, 0 on fail.
- */
-static unsigned hash_check_mask_by_digest_size(int digest_size)
-{
- static unsigned mask[10] = { 0,0,0,0,0,0,0,0,0,0 };
- int code;
- if (mask[9] == 0) {
- unsigned hid;
- for (hid = 1; hid <= RHASH_ALL_HASHES; hid <<= 1) {
- code = code_digest_size(rhash_get_digest_size(hid));
- assert(0 <= code && code <= 7);
- if (code >= 0) mask[code] |= hid;
- }
- mask[9] = 1;
- }
- code = code_digest_size(digest_size);
- return (code >= 0 ? mask[code] : 0);
-}
-
-#define HV_BIN 0
-#define HV_HEX 1
-#define HV_B32 2
-
-/**
- * Test if a character is a hexadecimal/base32 digit.
- *
- * @param c the character to test
- * @return result of the test, a combination of flags HV_HEX and HV_B32
- */
-static int test_hash_char(char c)
-{
- return (IS_HEX(c) ? HV_HEX : 0) | (IS_BASE32(c) ? HV_B32 : 0);
-}
-
-/**
- * Detect if given string contains a hexadecimal or base32 hash.
- *
- * @param ptr the pointer to start scanning from
- * @param end pointer to scan to
- * @param p_len pointer to a number to store length of detected hash string
- * @return type of detected hash as combination of HV_HEX and HV_B32 flags
- */
-static int detect_hash_type(char **ptr, char *end, int *p_len)
-{
- int len = 0;
- int char_type = 0, next_type = (HV_HEX | HV_B32);
-
- if (*ptr < end) {
- /* search forward (but no more then 129 symbols) */
- if ((end - *ptr) >= 129) end = *ptr + 129;
- for (; (next_type &= test_hash_char(**ptr)) && *ptr <= end; len++, (*ptr)++) {
- char_type = next_type;
- }
- } else {
- /* search backward (but no more then 129 symbols) */
- if ((*ptr-end) >= 129) end = *ptr - 129;
- for (; (next_type &= test_hash_char((*ptr)[-1])) && *ptr >= end; len++, (*ptr)--) {
- char_type = next_type;
- }
- }
- *p_len = len;
- return char_type;
-}
-
-/**
- * Test that the given string contain a hexadecimal or base32 hash string
- * of one of supported hash sums.
- *
- * @param ptr the pointer to start scanning from
- * @param end pointer to scan to
- * @param p_len pointer to a number to store length of detected hash string
- * @return possible type of detected hash as algorithm RHASH id
- */
-static unsigned char test_hash_string(char **ptr, char *end, int *p_len)
-{
- int len = 0;
- int char_type = detect_hash_type(ptr, end, &len);
- unsigned char hash_type = 0;
-
- if ((char_type & HV_HEX) && (len & 7) == 0 && len <= 256) {
- int pow = get_ctz(len >> 3);
- int code = ((len >> (pow + 4)) << 3) | pow;
- if (code < 32 && ((1 << code) & 0x101061d)) hash_type |= HV_HEX;
- }
- if ((char_type & HV_B32) && (len == 32 || len == 39)) {
- hash_type |= HV_B32;
- }
- if (hash_type != 0) {
- *p_len = len;
- }
- return hash_type;
-}
-
-/**
- * Detect ASCII-7 white spaces (not including Unicode whitespaces).
- * Note that isspace() is locale specific and detect Unicode spaces,
- * like U+00A0.
- */
-static int rhash_isspace(char ch)
-{
- return (((unsigned char)ch) <= 0x7F && isspace((unsigned char)ch));
-}
-
-/**
- * Information about found token
- */
-typedef struct hc_search
-{
- char* begin; /* start of the buffer to search */
- char* end; /* end of the buffer to search */
- hash_check* hc;
- unsigned expected_hash_id;
- int hash_type;
- char* url_name;
- size_t url_length;
-} hc_search;
-
-/**
- * Parse the buffer pointed by search->begin, into tokens specified by format
- * string. The format string can contain the following special characters:
- * '\1' - hash function name, '\2' - any hash, '\3' - specified hash,
- * '\4' - an URL-encoded file name, '\5' - a file size,
- * '\6' - a required-space, '\7' - a space or string end.
- * A space ' ' means 0 or more space characters.
- * '$' - parse the rest of the buffer and the format string backward.
- * Other (non-special) symbols mean themselves.
- * The function updates search->begin and search->end pointers on success.
- *
- * @param search the structure to store parsed tokens info
- * @param format the format string
- * @return 1 on success, 0 if couldn't find specified token(s)
- */
-static int hash_check_find_str(hc_search *search, const char* format)
-{
- int backward = 0;
- char buf[20];
- const char *fend = strchr(format, '\0');
- char* begin = search->begin;
- char* end = search->end;
- hash_check* hc = search->hc;
- hash_value hv;
- int unsaved_hashval = 0;
- memset(&hv, 0, sizeof(hash_value));
-
- while (format < fend) {
- const char *search_str;
- int i, len = 0;
- uint64_t file_size;
-
- if (backward) {
- for (; fend[-1] >= '-' && format < fend; fend--, len++);
- if (len == 0) --fend;
- search_str = fend;
- } else {
- search_str = format;
- for (; *format >= '-' && format < fend; format++, len++);
- if (len == 0) format++;
- }
- if (len > 0) {
- if ((end - begin) < len) return 0;
- if (0 != memcmp(search_str, (backward ? end - len : begin), len)) return 0;
- if (backward) end -= len;
- else begin += len;
- continue;
- }
- assert(len == 0);
-
- /* find substring specified by single character */
- switch (*search_str) {
- case '\1': /* parse hash function name */
- /* the name should contain alphanumeric or '-' symbols, but */
- /* actually the loop shall stop at characters [:& \(\t] */
- for (; (begin[len] <= '9' ? begin[len] >= '0' || begin[len]=='-' : begin[len] >= 'A'); len++) {
- if (len >= 20) return 0; /* limit name length */
- buf[len] = toupper(begin[len]);
- }
- begin += len;
- if (len == 0) return 0; /* not alpha-numeric sequence */
- buf[len] = '\0';
- search->expected_hash_id = 0;
-
- /* find hash_id by a hash function name */
- for (i = 0; i < RHASH_HASH_COUNT; i++) {
- if (strcmp(buf, hash_info_table[i].name) == 0) {
- search->expected_hash_id = 1 << i;
- search->hash_type = (HV_HEX | HV_B32);
- break;
- }
- }
- break;
- case '\2':
- case '\3':
- if (backward) {
- hv.format = test_hash_string(&end, begin, &len);
- hv.offset = (unsigned short)(end - hc->data);
- } else {
- hv.offset = (unsigned short)(begin - hc->data);
- hv.format = test_hash_string(&begin, end, &len);
- }
- if (!hv.format) return 0;
- if (*search_str == '\3') {
- /* verify hash type */
- int dlen = rhash_get_digest_size(search->expected_hash_id);
- hv.format &= search->hash_type;
- if ((!(hv.format & HV_HEX) || len != (dlen * 2)) &&
- (!(hv.format & HV_B32) || len != BASE32_LENGTH(dlen)))
- return 0;
- hv.hash_id = search->expected_hash_id;
- } else hv.hash_id = 0;
- hv.length = (unsigned char)len;
- unsaved_hashval = 1;
- break;
- case '\4': /* get URL-encoded name */
- search->url_name = begin;
- search->url_length = strcspn(begin, "?&|");
- if (search->url_length == 0) return 0; /* empty name */
- begin += search->url_length;
- break;
- case '\5': /* retrieve file size */
- assert(!backward);
- file_size = 0L;
- for (; '0' <= *begin && *begin <= '9'; begin++, len++) {
- file_size = file_size * 10 + (*begin - '0');
- }
- if (len == 0) return 0;
- else {
- hc->file_size = file_size;
- hc->flags |= HC_HAS_FILESIZE;
- }
- break;
- case '\6':
- case '\7':
- case ' ':
- if (backward) for (; begin < end && rhash_isspace(end[-1]); end--, len++);
- else for (; rhash_isspace(*begin) && begin < end; begin++, len++);
- /* check if space is mandatory */
- if (*search_str != ' ' && len == 0) {
- /* for '\6' check (len > 0) */
- /* for '\7' check (len > 0 || begin == end) */
- if (*search_str == '\6' || begin < end) return 0;
- }
- break;
- case '$':
- backward = 1; /* switch to parsing string backward */
- break;
- default:
- if ((backward ? *(--end) : *(begin++)) != *search_str) return 0;
- }
- }
-
- if (unsaved_hashval && hc->hashes_num < HC_MAX_HASHES) {
- hc->hashes[hc->hashes_num++] = hv;
- }
- search->begin = begin;
- search->end = end;
-
- return 1;
-}
-
-/* macros used by hash_check_parse_line() */
-#define THREEC2U(c1, c2, c3) (((unsigned)(c1) << 16) | \
- ((unsigned)(c2) << 8) | (unsigned)(c3))
-#define FOURC2U(c1, c2, c3, c4) (((unsigned)(c1) << 24) | \
- ((unsigned)(c2) << 16) | ((unsigned)(c3) << 8) | (unsigned)(c4))
-
-/**
- * Parse a line of a hash-file. This function accepts five formats.
- *
- * magnet links
- * EDonkey/EMule ed2k links
- * BSD format: HASH_FUNCTION ( filepath ) = FILE_HASH
- * filepath FILE_HASH1 FILE_HASH2...
- * FILE_HASH1 FILE_HASH2... filepath
- *
- * For a magnet/ed2k links file size is also parsed.
- *
- * @param line the line to parse
- * @param hashes structure to store parsed hashes, file path and file size
- * @return 1 on success, 0 if couldn't parse the line
- */
-int hash_check_parse_line(char* line, hash_check* hashes, int check_eol)
-{
- hc_search hs;
- char* le = strchr(line, '\0'); /* set pointer to the end of line */
- char* url_name = NULL;
- size_t url_length = 0;
- int single_hash = 0;
- int reversed = 0;
- int bad = 0;
- int i, j;
-
- /* return if EOL not found at the end of the line */
- if ( line[0]=='\0' || (le[-1] != '\n' && check_eol) ) return 0;
-
- /* note: not using str_tim because 'le' is re-used below */
-
- /* remove trailing white spaces */
- while (rhash_isspace(le[-1]) && le > line) *(--le) = 0;
- /* skip white spaces at the start of the line */
- while (rhash_isspace(*line)) line++;
-
- memset(&hs, 0, sizeof(hs));
- hs.begin = line;
- hs.end = le;
- hs.hc = hashes;
-
- memset(hashes, 0, sizeof(hash_check));
- hashes->data = line;
- hashes->file_size = (uint64_t)-1;
-
- if (strncmp(line, "magnet:?", 8) == 0) {
- hs.begin += 8;
-
- /* loop by magnet link parameters */
- while (1) {
- char* next = strchr(hs.begin, '&');
- char* param_end = (next ? next++ : hs.end);
- char* hf_end;
-
- if ((hs.begin += 3) < param_end) {
- switch (THREEC2U(hs.begin[-3], hs.begin[-2], hs.begin[-1])) {
- case THREEC2U('d', 'n', '='): /* URL-encoded file path */
- url_name = hs.begin;
- url_length = param_end - hs.begin;
- break;
- case THREEC2U('x', 'l', '='): /* file size */
- if (!hash_check_find_str(&hs, "\5")) bad = 1;
- if (hs.begin != param_end) bad = 1;
- break;
- case THREEC2U('x', 't', '='): /* a file hash */
- /* find last ':' character (hash name can be complex like tree:tiger) */
- for (hf_end = param_end - 1; *hf_end != ':' && hf_end > hs.begin; hf_end--);
-
- /* test for the "urn:" string */
- if ((hs.begin += 4) >= hf_end) return 0;
- if (FOURC2U('u', 'r', 'n', ':') != FOURC2U(hs.begin[-4],
- hs.begin[-3], hs.begin[-2], hs.begin[-1])) return 0;
-
- /* find hash by its magnet link specific URN name */
- for (i = 0; i < RHASH_HASH_COUNT; i++) {
- const char* urn = rhash_get_magnet_name(1 << i);
- size_t len = hf_end - hs.begin;
- if (strncmp(hs.begin, urn, len) == 0 &&
- urn[len] == '\0') break;
- }
- if (i >= RHASH_HASH_COUNT) {
- if (opt.flags & OPT_VERBOSE) {
- *hf_end = '\0';
- log_warning(_("unknown hash in magnet link: %s\n"), hs.begin);
- }
- return 0;
- }
-
- hs.begin = hf_end + 1;
- hs.expected_hash_id = 1 << i;
- hs.hash_type = (HV_HEX | HV_B32);
- if (!hash_check_find_str(&hs, "\3")) bad = 1;
- if (hs.begin != param_end) bad = 1;
- break;
-
- /* note: this switch () skips all unknown parameters */
- }
- }
- if (!bad && next) hs.begin = next;
- else break;
- }
- if (!url_name) bad = 1; /* file path parameter is mandatory */
- } else if (strncmp(line, "ed2k://|file|", 13) == 0) {
- hs.begin += 13;
- hs.expected_hash_id = RHASH_ED2K;
- hs.hash_type = HV_HEX;
- if (hash_check_find_str(&hs, "\4|\5|\3|")) {
- url_name = hs.url_name;
- url_length = hs.url_length;
- } else bad = 1;
-
- /* try to parse optional AICH hash */
- hs.expected_hash_id = RHASH_AICH;
- hs.hash_type = (HV_HEX | HV_B32); /* AICH is usually base32-encoded*/
- hash_check_find_str(&hs, "h=\3|");
- } else {
- if (hash_check_find_str(&hs, "\1 ( $ ) = \3")) {
- /* BSD-formatted line has been processed */
- } else if (hash_check_find_str(&hs, "$\6\2")) {
- while (hash_check_find_str(&hs, "$\6\2"));
- if (hashes->hashes_num > 1) reversed = 1;
- } else if (hash_check_find_str(&hs, "\2\7")) {
- if (hs.begin == hs.end) {
- /* the line contains no file path, only a single hash */
- single_hash = 1;
- } else {
- while (hash_check_find_str(&hs, "\2\6"));
- /* drop an asterisk before filename if present */
- if (*hs.begin == '*') hs.begin++;
- }
- } else bad = 1;
-
- if (hs.begin >= hs.end && !single_hash) bad = 1;
- }
-
- if (bad) {
- log_warning(_("can't parse line: %s\n"), line);
- return 0;
- }
-
- assert(hashes->file_path == 0);
-
- /* if !single_hash then we shall extract filepath from the line */
- if (url_name) {
- hashes->file_path = url_name;
- url_name[url_length] = '\0';
- urldecode(url_name); /* decode filename from URL */
- process_backslashes(url_name);
- } else if (!single_hash) {
- assert(hs.begin < hs.end);
- hashes->file_path = hs.begin;
- *hs.end = '\0';
- process_backslashes(hs.begin);
- }
-
- if (reversed) {
- /* change the order of hash values from reversed back to forward */
- for (i = 0, j = hashes->hashes_num - 1; i < j; i++, j--) {
- hash_value tmp = hashes->hashes[i];
- hashes->hashes[i] = hashes->hashes[j];
- hashes->hashes[j] = tmp;
- }
- }
-
- /* post-process parsed hashes */
- for (i = 0; i < hashes->hashes_num; i++) {
- hash_value *hv = &hashes->hashes[i];
- char *hash_str = hashes->data + hv->offset;
-
- if (hv->hash_id == 0) {
- /* calculate hash mask */
- unsigned mask = 0;
- if (hv->format & HV_HEX) {
- mask |= hash_check_mask_by_digest_size(hv->length >> 1);
- }
- if (hv->format & HV_B32) {
- assert(((hv->length * 5 / 8) & 3) == 0);
- mask |= hash_check_mask_by_digest_size(hv->length * 5 / 8);
- }
- assert(mask != 0);
- if ((mask & opt.sum_flags) != 0) mask &= opt.sum_flags;
- hv->hash_id = mask;
- }
- hashes->hash_mask |= hv->hash_id;
-
- /* change the hash string to be upper-case */
- for (j = 0; j < (int)hv->length; j++) {
- if (hash_str[j] >= 'a') hash_str[j] &= ~0x20;
- }
- hash_str[j] = '\0'; /* terminate the hash string */
- }
-
- return 1;
-}
-
-/**
- * Forward and reverse hex string compare. Compares two hexadecimal strings
- * using forward and reversed byte order. The function is used to compare
- * GOST hashes which can be reversed, because byte order of
- * an output string is not specified by GOST standard.
- * The function acts almost the same way as memcmp, but always returns
- * 1 for unmatched strings.
- *
- * @param mem1 the first byte string
- * @param mem2 the second byte string
- * @param size the length of byte strings to much
- * @return 0 if strings are matched, 1 otherwise.
- */
-static int fr_hex_cmp(const void* mem1, const void* mem2, size_t size)
-{
- const char *p1, *p2, *pe;
- if (memcmp(mem1, mem2, size) == 0) return 0;
- if ((size & 1) != 0) return 1; /* support only even size */
-
- p1 = (const char*)mem1, p2 = ((const char*)mem2) + size - 2;
- for (pe = ((const char*)mem1) + size / 2; p1 < pe; p1 += 2, p2 -= 2) {
- if (p1[0] != p2[0] || p1[1] != p2[1]) return 1;
- }
- return 0;
-}
-
-/**
- * Obtain CRC32 from rhash context. The function assumes that
- * context contains CRC32 and makes no checks for this.
- *
- * @param rhash context
- * @return crc32 hash sum
- */
-unsigned get_crc32(struct rhash_context* ctx)
-{
- unsigned char c[4];
- rhash_print((char*)c, ctx, RHASH_CRC32, RHPR_RAW);
- return ((unsigned)c[0] << 24) | ((unsigned)c[1] << 16) |
- ((unsigned)c[2] << 8) | (unsigned)c[3];
-}
-
-/**
- * Verify calculated hashes against original values.
- * Also verify the file size and embedded CRC32 if present.
- * The HC_WRONG_* bits are set in the hashes->flags field on fail.
- *
- * @param hashes 'original' parsed hash values, to verify against
- * @param ctx the rhash context containing calculated hash values
- * @return 1 on success, 0 on fail
- */
-int hash_check_verify(hash_check* hashes, struct rhash_context* ctx)
-{
- unsigned unverified_mask;
- unsigned hid;
- unsigned printed;
- char hex[132], b32[104];
- int j;
-
- /* verify file size, if present */
- if ((hashes->flags & HC_HAS_FILESIZE) != 0 && hashes->file_size != ctx->msg_size)
- hashes->flags |= HC_WRONG_FILESIZE;
-
- /* verify embedded CRC32 hash sum, if present */
- if ((hashes->flags & HC_HAS_EMBCRC32) != 0 && get_crc32(ctx) != hashes->embedded_crc32)
- hashes->flags |= HC_WRONG_EMBCRC32;
-
- /* return if nothing else to verify */
- if (hashes->hashes_num == 0)
- return !HC_FAILED(hashes->flags);
-
- unverified_mask = (1 << hashes->hashes_num) - 1;
-
- for (hid = 1; hid <= RHASH_ALL_HASHES; hid <<= 1) {
- if ((hashes->hash_mask & hid) == 0) continue;
- printed = 0;
-
- for (j = 0; j < hashes->hashes_num; j++) {
- hash_value *hv = &hashes->hashes[j];
- char *hash_str, *hash_orig;
- int dgst_size;
-
- /* skip already verified hashes and hashes with different digest size */
- if (!(unverified_mask & (1 << j)) || !(hv->hash_id & hid)) continue;
- dgst_size = rhash_get_digest_size(hid);
- if (hv->length == (dgst_size * 2)) {
- assert(hv->format & HV_HEX);
- assert(hv->length <= 128);
-
- /* print hexadecimal value, if not printed yet */
- if ((printed & HV_HEX) == 0) {
- rhash_print(hex, ctx, hid, RHPR_HEX | RHPR_UPPERCASE);
- printed |= HV_HEX;
- }
- hash_str = hex;
- } else {
- assert(hv->format & HV_B32);
- assert(hv->length == BASE32_LENGTH(dgst_size));
- assert(hv->length <= 103);
-
- /* print base32 value, if not printed yet */
- if ((printed & HV_B32) == 0) {
- rhash_print(b32, ctx, hid, RHPR_BASE32 | RHPR_UPPERCASE);
- printed |= HV_B32;
- }
- hash_str = b32;
- }
- hash_orig = hashes->data + hv->offset;
-
- if ((hid & (RHASH_GOST94 | RHASH_GOST94_CRYPTOPRO)) != 0) {
- if (fr_hex_cmp(hash_orig, hash_str, hv->length) != 0) continue;
- } else {
- if (memcmp(hash_orig, hash_str, hv->length) != 0) continue;
- }
-
- unverified_mask &= ~(1 << j); /* the j-th hash verified */
- hashes->found_hash_ids |= hid;
-
- /* end loop if all hashes were successfully verified */
- if (unverified_mask == 0) goto hc_verify_exit;
- }
- }
-
-hc_verify_exit: /* we use label/goto to jump out of two nested loops */
- hashes->wrong_hashes = unverified_mask;
- if (unverified_mask != 0) hashes->flags |= HC_WRONG_HASHES;
- return !HC_FAILED(hashes->flags);
-}
+/* hash_check.c - verification of hashes of files */
+
+#include
+#include /* isspace */
+#include
+
+#include "hash_check.h"
+#include "hash_print.h"
+#include "common_func.h"
+#include "output.h"
+#include "parse_cmdline.h"
+#include "librhash/rhash.h"
+
+/* hash conversion macros and functions */
+#define HEX2DIGIT(c) ((c) <= '9' ? (c) & 0xF : ((c) - 'a' + 10) & 0xF)
+#define BASE32_TO_DIGIT(c) ((c) < 'A' ? (c) - '2' + 26 : ((c) & ~0x20) - 'A')
+#define BASE32_LENGTH(bytes) (((bytes) * 8 + 4) / 5)
+
+/**
+ * Convert a hexadecimal string to a string of bytes.
+ *
+ * @param str string to parse
+ * @param bin result
+ * @param len string length
+ */
+void rhash_hex_to_byte(const char* str, unsigned char* bin, int len)
+{
+ /* parse the highest hexadecimal digit */
+ if ((len & 1) != 0) {
+ *(bin++) = HEX2DIGIT(*(str++));
+ len--;
+ }
+
+ /* parse the rest - an even-sized hexadecimal string */
+ for (; len >= 2; len -= 2, str += 2) {
+ *(bin++) = (HEX2DIGIT(str[0]) << 4) | HEX2DIGIT(str[1]);
+ }
+}
+
+/**
+ * Decode an URL-encoded string in the specified buffer.
+ *
+ * @param buffer the 0-terminated URL-encoded string
+ */
+static void urldecode(char *buffer)
+{
+ char *wpos = buffer; /* set writing position */
+ for (; *buffer; wpos++) {
+ *wpos = *(buffer++); /* copy non-escaped characters */
+ if (*wpos == '%') {
+ if (*buffer == '%') {
+ buffer++; /* interpret '%%' as single '%' */
+ } else if (IS_HEX(*buffer)) {
+ /* decode character from the % form */
+ int ch = HEX2DIGIT(*buffer);
+ buffer++;
+ if (IS_HEX(*buffer)) {
+ ch = (ch << 4) | HEX2DIGIT(*buffer);
+ buffer++;
+ }
+ *wpos = (char)ch;
+ }
+ }
+ }
+ *wpos = '\0'; /* terminate decoded string */
+}
+
+#ifndef _WIN32
+/**
+ * Convert a windows file path to a UNIX one, replacing '\\' by '/'.
+ *
+ * @param path the path to convert
+ * @return converted path
+ */
+static void process_backslashes(char* path)
+{
+ for (;*path;path++) {
+ if (*path == '\\') *path = '/';
+ }
+}
+#else /* _WIN32 */
+#define process_backslashes(path)
+#endif /* _WIN32 */
+
+
+/* convert a hash flag to index */
+#if __GNUC__ >= 4 || (__GNUC__ ==3 && __GNUC_MINOR__ >= 4) /* GCC < 3.4 */
+# define get_ctz(x) __builtin_ctz(x)
+#else
+
+/**
+ * Returns index of the trailing bit of a 32-bit number.
+ * This is a plain C equivalent for GCC __builtin_ctz() bit scan.
+ *
+ * @param x the number to process
+ * @return zero-based index of the trailing bit
+ */
+static unsigned get_ctz(unsigned x)
+{
+ /* see http://graphics.stanford.edu/~seander/bithacks.html */
+ static unsigned char bit_pos[32] = {
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+ };
+ return bit_pos[((uint32_t)((x & -(int)x) * 0x077CB531U)) >> 27];
+}
+#endif /* (GCC >= 4.3) */
+
+/**
+ * Encode a hash function digest size into a small number in [0,...,7].
+ * The digest size must be in the set { 4, 16, 20, 24, 28, 32, 48, 64 }.
+ *
+ * @param digest_size digest size (aka hash length) in bytes
+ * @return code for digest size on success, 32 on error
+ */
+static int code_digest_size(int digest_size)
+{
+ static int size_codes[17] = {
+ -1, 0,-1, -1, 1, 2, 3, 4, 5, -1,
+ -1, -1, 6, -1, -1, -1, 7
+ };
+ return (digest_size <= 64 ? size_codes[digest_size / 4] : -1);
+}
+
+/**
+ * Calculate an OR-ed mask of hash-ids by a length of hash in bytes.
+ *
+ * @param digest_size length of a hash in bytes.
+ * @return mask of hash-ids with given hash length, 0 on fail.
+ */
+static unsigned hash_check_mask_by_digest_size(int digest_size)
+{
+ static unsigned mask[10] = { 0,0,0,0,0,0,0,0,0,0 };
+ int code;
+ if (mask[9] == 0) {
+ unsigned hid;
+ for (hid = 1; hid <= RHASH_ALL_HASHES; hid <<= 1) {
+ code = code_digest_size(rhash_get_digest_size(hid));
+ assert(0 <= code && code <= 7);
+ if (code >= 0) mask[code] |= hid;
+ }
+ mask[9] = 1;
+ }
+ code = code_digest_size(digest_size);
+ return (code >= 0 ? mask[code] : 0);
+}
+
+#define HV_BIN 0
+#define HV_HEX 1
+#define HV_B32 2
+
+/**
+ * Test if a character is a hexadecimal/base32 digit.
+ *
+ * @param c the character to test
+ * @return result of the test, a combination of flags HV_HEX and HV_B32
+ */
+static int test_hash_char(char c)
+{
+ return (IS_HEX(c) ? HV_HEX : 0) | (IS_BASE32(c) ? HV_B32 : 0);
+}
+
+/**
+ * Detect if given string contains a hexadecimal or base32 hash.
+ *
+ * @param ptr the pointer to start scanning from
+ * @param end pointer to scan to
+ * @param p_len pointer to a number to store length of detected hash string
+ * @return type of detected hash as combination of HV_HEX and HV_B32 flags
+ */
+static int detect_hash_type(char **ptr, char *end, int *p_len)
+{
+ int len = 0;
+ int char_type = 0, next_type = (HV_HEX | HV_B32);
+
+ if (*ptr < end) {
+ /* search forward (but no more then 129 symbols) */
+ if ((end - *ptr) >= 129) end = *ptr + 129;
+ for (; (next_type &= test_hash_char(**ptr)) && *ptr <= end; len++, (*ptr)++) {
+ char_type = next_type;
+ }
+ } else {
+ /* search backward (but no more then 129 symbols) */
+ if ((*ptr-end) >= 129) end = *ptr - 129;
+ for (; (next_type &= test_hash_char((*ptr)[-1])) && *ptr >= end; len++, (*ptr)--) {
+ char_type = next_type;
+ }
+ }
+ *p_len = len;
+ return char_type;
+}
+
+/**
+ * Test that the given string contain a hexadecimal or base32 hash string
+ * of one of supported hash sums.
+ *
+ * @param ptr the pointer to start scanning from
+ * @param end pointer to scan to
+ * @param p_len pointer to a number to store length of detected hash string
+ * @return possible type of detected hash as algorithm RHASH id
+ */
+static unsigned char test_hash_string(char **ptr, char *end, int *p_len)
+{
+ int len = 0;
+ int char_type = detect_hash_type(ptr, end, &len);
+ unsigned char hash_type = 0;
+
+ if ((char_type & HV_HEX) && (len & 7) == 0 && len <= 256) {
+ int pow = get_ctz(len >> 3);
+ int code = ((len >> (pow + 4)) << 3) | pow;
+ if (code < 32 && ((1 << code) & 0x101061d)) hash_type |= HV_HEX;
+ }
+ if ((char_type & HV_B32) && (len == 32 || len == 39)) {
+ hash_type |= HV_B32;
+ }
+ if (hash_type != 0) {
+ *p_len = len;
+ }
+ return hash_type;
+}
+
+/**
+ * Detect ASCII-7 white spaces (not including Unicode whitespaces).
+ * Note that isspace() is locale specific and detect Unicode spaces,
+ * like U+00A0.
+ */
+static int rhash_isspace(char ch)
+{
+ return (((unsigned char)ch) <= 0x7F && isspace((unsigned char)ch));
+}
+
+/**
+ * Information about found token
+ */
+typedef struct hc_search
+{
+ char* begin; /* start of the buffer to search */
+ char* end; /* end of the buffer to search */
+ hash_check* hc;
+ unsigned expected_hash_id;
+ int hash_type;
+ char* url_name;
+ size_t url_length;
+} hc_search;
+
+/**
+ * Parse the buffer pointed by search->begin, into tokens specified by format
+ * string. The format string can contain the following special characters:
+ * '\1' - hash function name, '\2' - any hash, '\3' - specified hash,
+ * '\4' - an URL-encoded file name, '\5' - a file size,
+ * '\6' - a required-space, '\7' - a space or string end.
+ * A space ' ' means 0 or more space characters.
+ * '$' - parse the rest of the buffer and the format string backward.
+ * Other (non-special) symbols mean themselves.
+ * The function updates search->begin and search->end pointers on success.
+ *
+ * @param search the structure to store parsed tokens info
+ * @param format the format string
+ * @return 1 on success, 0 if couldn't find specified token(s)
+ */
+static int hash_check_find_str(hc_search *search, const char* format)
+{
+ int backward = 0;
+ char buf[20];
+ const char *fend = strchr(format, '\0');
+ char* begin = search->begin;
+ char* end = search->end;
+ hash_check* hc = search->hc;
+ hash_value hv;
+ int unsaved_hashval = 0;
+ memset(&hv, 0, sizeof(hash_value));
+
+ while (format < fend) {
+ const char *search_str;
+ int i, len = 0;
+ uint64_t file_size;
+
+ if (backward) {
+ for (; fend[-1] >= '-' && format < fend; fend--, len++);
+ if (len == 0) --fend;
+ search_str = fend;
+ } else {
+ search_str = format;
+ for (; *format >= '-' && format < fend; format++, len++);
+ if (len == 0) format++;
+ }
+ if (len > 0) {
+ if ((end - begin) < len) return 0;
+ if (0 != memcmp(search_str, (backward ? end - len : begin), len)) return 0;
+ if (backward) end -= len;
+ else begin += len;
+ continue;
+ }
+ assert(len == 0);
+
+ /* find substring specified by single character */
+ switch (*search_str) {
+ case '\1': /* parse hash function name */
+ /* the name should contain alphanumeric or '-' symbols, but */
+ /* actually the loop shall stop at characters [:& \(\t] */
+ for (; (begin[len] <= '9' ? begin[len] >= '0' || begin[len]=='-' : begin[len] >= 'A'); len++) {
+ if (len >= 20) return 0; /* limit name length */
+ buf[len] = toupper(begin[len]);
+ }
+ begin += len;
+ if (len == 0) return 0; /* not alpha-numeric sequence */
+ buf[len] = '\0';
+ search->expected_hash_id = 0;
+
+ /* find hash_id by a hash function name */
+ for (i = 0; i < RHASH_HASH_COUNT; i++) {
+ if (strcmp(buf, hash_info_table[i].name) == 0) {
+ search->expected_hash_id = 1 << i;
+ search->hash_type = (HV_HEX | HV_B32);
+ break;
+ }
+ }
+ break;
+ case '\2':
+ case '\3':
+ if (backward) {
+ hv.format = test_hash_string(&end, begin, &len);
+ hv.offset = (unsigned short)(end - hc->data);
+ } else {
+ hv.offset = (unsigned short)(begin - hc->data);
+ hv.format = test_hash_string(&begin, end, &len);
+ }
+ if (!hv.format) return 0;
+ if (*search_str == '\3') {
+ /* verify hash type */
+ int dlen = rhash_get_digest_size(search->expected_hash_id);
+ hv.format &= search->hash_type;
+ if ((!(hv.format & HV_HEX) || len != (dlen * 2)) &&
+ (!(hv.format & HV_B32) || len != BASE32_LENGTH(dlen)))
+ return 0;
+ hv.hash_id = search->expected_hash_id;
+ } else hv.hash_id = 0;
+ hv.length = (unsigned char)len;
+ unsaved_hashval = 1;
+ break;
+ case '\4': /* get URL-encoded name */
+ search->url_name = begin;
+ search->url_length = strcspn(begin, "?&|");
+ if (search->url_length == 0) return 0; /* empty name */
+ begin += search->url_length;
+ break;
+ case '\5': /* retrieve file size */
+ assert(!backward);
+ file_size = 0L;
+ for (; '0' <= *begin && *begin <= '9'; begin++, len++) {
+ file_size = file_size * 10 + (*begin - '0');
+ }
+ if (len == 0) return 0;
+ else {
+ hc->file_size = file_size;
+ hc->flags |= HC_HAS_FILESIZE;
+ }
+ break;
+ case '\6':
+ case '\7':
+ case ' ':
+ if (backward) for (; begin < end && rhash_isspace(end[-1]); end--, len++);
+ else for (; rhash_isspace(*begin) && begin < end; begin++, len++);
+ /* check if space is mandatory */
+ if (*search_str != ' ' && len == 0) {
+ /* for '\6' check (len > 0) */
+ /* for '\7' check (len > 0 || begin == end) */
+ if (*search_str == '\6' || begin < end) return 0;
+ }
+ break;
+ case '$':
+ backward = 1; /* switch to parsing string backward */
+ break;
+ default:
+ if ((backward ? *(--end) : *(begin++)) != *search_str) return 0;
+ }
+ }
+
+ if (unsaved_hashval && hc->hashes_num < HC_MAX_HASHES) {
+ hc->hashes[hc->hashes_num++] = hv;
+ }
+ search->begin = begin;
+ search->end = end;
+
+ return 1;
+}
+
+/* macros used by hash_check_parse_line() */
+#define THREEC2U(c1, c2, c3) (((unsigned)(c1) << 16) | \
+ ((unsigned)(c2) << 8) | (unsigned)(c3))
+#define FOURC2U(c1, c2, c3, c4) (((unsigned)(c1) << 24) | \
+ ((unsigned)(c2) << 16) | ((unsigned)(c3) << 8) | (unsigned)(c4))
+
+/**
+ * Parse a line of a hash-file. This function accepts five formats.
+ *
+ * magnet links
+ * EDonkey/EMule ed2k links
+ * BSD format: HASH_FUNCTION ( filepath ) = FILE_HASH
+ * filepath FILE_HASH1 FILE_HASH2...
+ * FILE_HASH1 FILE_HASH2... filepath
+ *
+ * For a magnet/ed2k links file size is also parsed.
+ *
+ * @param line the line to parse
+ * @param hashes structure to store parsed hashes, file path and file size
+ * @return 1 on success, 0 if couldn't parse the line
+ */
+int hash_check_parse_line(char* line, hash_check* hashes, int check_eol)
+{
+ hc_search hs;
+ char* le = strchr(line, '\0'); /* set pointer to the end of line */
+ char* url_name = NULL;
+ size_t url_length = 0;
+ int single_hash = 0;
+ int reversed = 0;
+ int bad = 0;
+ int i, j;
+
+ /* return if EOL not found at the end of the line */
+ if ( line[0]=='\0' || (le[-1] != '\n' && check_eol) ) return 0;
+
+ /* note: not using str_tim because 'le' is re-used below */
+
+ /* remove trailing white spaces */
+ while (rhash_isspace(le[-1]) && le > line) *(--le) = 0;
+ /* skip white spaces at the start of the line */
+ while (rhash_isspace(*line)) line++;
+
+ memset(&hs, 0, sizeof(hs));
+ hs.begin = line;
+ hs.end = le;
+ hs.hc = hashes;
+
+ memset(hashes, 0, sizeof(hash_check));
+ hashes->data = line;
+ hashes->file_size = (uint64_t)-1;
+
+ if (strncmp(line, "magnet:?", 8) == 0) {
+ hs.begin += 8;
+
+ /* loop by magnet link parameters */
+ while (1) {
+ char* next = strchr(hs.begin, '&');
+ char* param_end = (next ? next++ : hs.end);
+ char* hf_end;
+
+ if ((hs.begin += 3) < param_end) {
+ switch (THREEC2U(hs.begin[-3], hs.begin[-2], hs.begin[-1])) {
+ case THREEC2U('d', 'n', '='): /* URL-encoded file path */
+ url_name = hs.begin;
+ url_length = param_end - hs.begin;
+ break;
+ case THREEC2U('x', 'l', '='): /* file size */
+ if (!hash_check_find_str(&hs, "\5")) bad = 1;
+ if (hs.begin != param_end) bad = 1;
+ break;
+ case THREEC2U('x', 't', '='): /* a file hash */
+ /* find last ':' character (hash name can be complex like tree:tiger) */
+ for (hf_end = param_end - 1; *hf_end != ':' && hf_end > hs.begin; hf_end--);
+
+ /* test for the "urn:" string */
+ if ((hs.begin += 4) >= hf_end) return 0;
+ if (FOURC2U('u', 'r', 'n', ':') != FOURC2U(hs.begin[-4],
+ hs.begin[-3], hs.begin[-2], hs.begin[-1])) return 0;
+
+ /* find hash by its magnet link specific URN name */
+ for (i = 0; i < RHASH_HASH_COUNT; i++) {
+ const char* urn = rhash_get_magnet_name(1 << i);
+ size_t len = hf_end - hs.begin;
+ if (strncmp(hs.begin, urn, len) == 0 &&
+ urn[len] == '\0') break;
+ }
+ if (i >= RHASH_HASH_COUNT) {
+ if (opt.flags & OPT_VERBOSE) {
+ *hf_end = '\0';
+ log_warning(_("unknown hash in magnet link: %s\n"), hs.begin);
+ }
+ return 0;
+ }
+
+ hs.begin = hf_end + 1;
+ hs.expected_hash_id = 1 << i;
+ hs.hash_type = (HV_HEX | HV_B32);
+ if (!hash_check_find_str(&hs, "\3")) bad = 1;
+ if (hs.begin != param_end) bad = 1;
+ break;
+
+ /* note: this switch () skips all unknown parameters */
+ }
+ }
+ if (!bad && next) hs.begin = next;
+ else break;
+ }
+ if (!url_name) bad = 1; /* file path parameter is mandatory */
+ } else if (strncmp(line, "ed2k://|file|", 13) == 0) {
+ hs.begin += 13;
+ hs.expected_hash_id = RHASH_ED2K;
+ hs.hash_type = HV_HEX;
+ if (hash_check_find_str(&hs, "\4|\5|\3|")) {
+ url_name = hs.url_name;
+ url_length = hs.url_length;
+ } else bad = 1;
+
+ /* try to parse optional AICH hash */
+ hs.expected_hash_id = RHASH_AICH;
+ hs.hash_type = (HV_HEX | HV_B32); /* AICH is usually base32-encoded*/
+ hash_check_find_str(&hs, "h=\3|");
+ } else {
+ if (hash_check_find_str(&hs, "\1 ( $ ) = \3")) {
+ /* BSD-formatted line has been processed */
+ } else if (hash_check_find_str(&hs, "$\6\2")) {
+ while (hash_check_find_str(&hs, "$\6\2"));
+ if (hashes->hashes_num > 1) reversed = 1;
+ } else if (hash_check_find_str(&hs, "\2\7")) {
+ if (hs.begin == hs.end) {
+ /* the line contains no file path, only a single hash */
+ single_hash = 1;
+ } else {
+ while (hash_check_find_str(&hs, "\2\6"));
+ /* drop an asterisk before filename if present */
+ if (*hs.begin == '*') hs.begin++;
+ }
+ } else bad = 1;
+
+ if (hs.begin >= hs.end && !single_hash) bad = 1;
+ }
+
+ if (bad) {
+ log_warning(_("can't parse line: %s\n"), line);
+ return 0;
+ }
+
+ assert(hashes->file_path == 0);
+
+ /* if !single_hash then we shall extract filepath from the line */
+ if (url_name) {
+ hashes->file_path = url_name;
+ url_name[url_length] = '\0';
+ urldecode(url_name); /* decode filename from URL */
+ process_backslashes(url_name);
+ } else if (!single_hash) {
+ assert(hs.begin < hs.end);
+ hashes->file_path = hs.begin;
+ *hs.end = '\0';
+ process_backslashes(hs.begin);
+ }
+
+ if (reversed) {
+ /* change the order of hash values from reversed back to forward */
+ for (i = 0, j = hashes->hashes_num - 1; i < j; i++, j--) {
+ hash_value tmp = hashes->hashes[i];
+ hashes->hashes[i] = hashes->hashes[j];
+ hashes->hashes[j] = tmp;
+ }
+ }
+
+ /* post-process parsed hashes */
+ for (i = 0; i < hashes->hashes_num; i++) {
+ hash_value *hv = &hashes->hashes[i];
+ char *hash_str = hashes->data + hv->offset;
+
+ if (hv->hash_id == 0) {
+ /* calculate hash mask */
+ unsigned mask = 0;
+ if (hv->format & HV_HEX) {
+ mask |= hash_check_mask_by_digest_size(hv->length >> 1);
+ }
+ if (hv->format & HV_B32) {
+ assert(((hv->length * 5 / 8) & 3) == 0);
+ mask |= hash_check_mask_by_digest_size(hv->length * 5 / 8);
+ }
+ assert(mask != 0);
+ if ((mask & opt.sum_flags) != 0) mask &= opt.sum_flags;
+ hv->hash_id = mask;
+ }
+ hashes->hash_mask |= hv->hash_id;
+
+ /* change the hash string to be upper-case */
+ for (j = 0; j < (int)hv->length; j++) {
+ if (hash_str[j] >= 'a') hash_str[j] &= ~0x20;
+ }
+ hash_str[j] = '\0'; /* terminate the hash string */
+ }
+
+ return 1;
+}
+
+/**
+ * Forward and reverse hex string compare. Compares two hexadecimal strings
+ * using forward and reversed byte order. The function is used to compare
+ * GOST hashes which can be reversed, because byte order of
+ * an output string is not specified by GOST standard.
+ * The function acts almost the same way as memcmp, but always returns
+ * 1 for unmatched strings.
+ *
+ * @param mem1 the first byte string
+ * @param mem2 the second byte string
+ * @param size the length of byte strings to much
+ * @return 0 if strings are matched, 1 otherwise.
+ */
+static int fr_hex_cmp(const void* mem1, const void* mem2, size_t size)
+{
+ const char *p1, *p2, *pe;
+ if (memcmp(mem1, mem2, size) == 0) return 0;
+ if ((size & 1) != 0) return 1; /* support only even size */
+
+ p1 = (const char*)mem1, p2 = ((const char*)mem2) + size - 2;
+ for (pe = ((const char*)mem1) + size / 2; p1 < pe; p1 += 2, p2 -= 2) {
+ if (p1[0] != p2[0] || p1[1] != p2[1]) return 1;
+ }
+ return 0;
+}
+
+/**
+ * Obtain CRC32 from rhash context. The function assumes that
+ * context contains CRC32 and makes no checks for this.
+ *
+ * @param rhash context
+ * @return crc32 hash sum
+ */
+unsigned get_crc32(struct rhash_context* ctx)
+{
+ unsigned char c[4];
+ rhash_print((char*)c, ctx, RHASH_CRC32, RHPR_RAW);
+ return ((unsigned)c[0] << 24) | ((unsigned)c[1] << 16) |
+ ((unsigned)c[2] << 8) | (unsigned)c[3];
+}
+
+/**
+ * Verify calculated hashes against original values.
+ * Also verify the file size and embedded CRC32 if present.
+ * The HC_WRONG_* bits are set in the hashes->flags field on fail.
+ *
+ * @param hashes 'original' parsed hash values, to verify against
+ * @param ctx the rhash context containing calculated hash values
+ * @return 1 on success, 0 on fail
+ */
+int hash_check_verify(hash_check* hashes, struct rhash_context* ctx)
+{
+ unsigned unverified_mask;
+ unsigned hid;
+ unsigned printed;
+ char hex[132], b32[104];
+ int j;
+
+ /* verify file size, if present */
+ if ((hashes->flags & HC_HAS_FILESIZE) != 0 && hashes->file_size != ctx->msg_size)
+ hashes->flags |= HC_WRONG_FILESIZE;
+
+ /* verify embedded CRC32 hash sum, if present */
+ if ((hashes->flags & HC_HAS_EMBCRC32) != 0 && get_crc32(ctx) != hashes->embedded_crc32)
+ hashes->flags |= HC_WRONG_EMBCRC32;
+
+ /* return if nothing else to verify */
+ if (hashes->hashes_num == 0)
+ return !HC_FAILED(hashes->flags);
+
+ unverified_mask = (1 << hashes->hashes_num) - 1;
+
+ for (hid = 1; hid <= RHASH_ALL_HASHES; hid <<= 1) {
+ if ((hashes->hash_mask & hid) == 0) continue;
+ printed = 0;
+
+ for (j = 0; j < hashes->hashes_num; j++) {
+ hash_value *hv = &hashes->hashes[j];
+ char *hash_str, *hash_orig;
+ int dgst_size;
+
+ /* skip already verified hashes and hashes with different digest size */
+ if (!(unverified_mask & (1 << j)) || !(hv->hash_id & hid)) continue;
+ dgst_size = rhash_get_digest_size(hid);
+ if (hv->length == (dgst_size * 2)) {
+ assert(hv->format & HV_HEX);
+ assert(hv->length <= 128);
+
+ /* print hexadecimal value, if not printed yet */
+ if ((printed & HV_HEX) == 0) {
+ rhash_print(hex, ctx, hid, RHPR_HEX | RHPR_UPPERCASE);
+ printed |= HV_HEX;
+ }
+ hash_str = hex;
+ } else {
+ assert(hv->format & HV_B32);
+ assert(hv->length == BASE32_LENGTH(dgst_size));
+ assert(hv->length <= 103);
+
+ /* print base32 value, if not printed yet */
+ if ((printed & HV_B32) == 0) {
+ rhash_print(b32, ctx, hid, RHPR_BASE32 | RHPR_UPPERCASE);
+ printed |= HV_B32;
+ }
+ hash_str = b32;
+ }
+ hash_orig = hashes->data + hv->offset;
+
+ if ((hid & (RHASH_GOST94 | RHASH_GOST94_CRYPTOPRO)) != 0) {
+ if (fr_hex_cmp(hash_orig, hash_str, hv->length) != 0) continue;
+ } else {
+ if (memcmp(hash_orig, hash_str, hv->length) != 0) continue;
+ }
+
+ unverified_mask &= ~(1 << j); /* the j-th hash verified */
+ hashes->found_hash_ids |= hid;
+
+ /* end loop if all hashes were successfully verified */
+ if (unverified_mask == 0) goto hc_verify_exit;
+ }
+ }
+
+hc_verify_exit: /* we use label/goto to jump out of two nested loops */
+ hashes->wrong_hashes = unverified_mask;
+ if (unverified_mask != 0) hashes->flags |= HC_WRONG_HASHES;
+ return !HC_FAILED(hashes->flags);
+}
diff --git a/hash_check.h b/hash_check.h
index d0bb389f..5e281db2 100644
--- a/hash_check.h
+++ b/hash_check.h
@@ -1,66 +1,66 @@
-/* hash_check.h - functions to parse a file with hash sums to verify it */
-#ifndef HASH_CHECK_H
-#define HASH_CHECK_H
-
-#include
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* bit flags for hash_check.flags */
-#define HC_HAS_FILESIZE 1
-#define HC_HAS_EMBCRC32 2
-#define HC_WRONG_FILESIZE 4
-#define HC_WRONG_EMBCRC32 8
-#define HC_WRONG_HASHES 16
-#define HC_FAILED(flags) ((flags) & (HC_WRONG_FILESIZE | HC_WRONG_EMBCRC32 | HC_WRONG_HASHES))
-
-#define HC_MAX_HASHES 32
-
-/**
- * Parsed hash value.
- */
-typedef struct hash_value
-{
- unsigned hash_id; /* the id of hash, if it was detected */
- unsigned short offset;
- unsigned char length;
- unsigned char format;
-} hash_value;
-
-struct rhash_context;
-
-/**
- * Parsed file info, like the path, size and file hash values.
- */
-typedef struct hash_check
-{
- char *file_path; /* parsed file path */
- uint64_t file_size; /* parsed file size, e.g. from magnet link */
- unsigned hash_mask; /* the mask of hash ids to verify against */
- unsigned flags; /* bit flags */
- unsigned embedded_crc32; /* CRC32 embedded into filename */
- char *data; /* the buffer with the current hash file line */
- unsigned found_hash_ids; /* bit mask for matched hash ids */
- unsigned wrong_hashes; /* bit mask for mismatched hashes */
- int hashes_num; /* number of parsed hashes */
- hash_value hashes[HC_MAX_HASHES];
-} hash_check;
-
-int hash_check_parse_line(char* line, hash_check* hashes, int check_eol);
-int hash_check_verify(hash_check* hashes, struct rhash_context* ctx);
-
-void rhash_base32_to_byte(const char* str, unsigned char* bin, int len);
-void rhash_hex_to_byte(const char* str, unsigned char* bin, int len);
-unsigned get_crc32(struct rhash_context* ctx);
-
-/* note: IS_HEX() is defined on ASCII-8 while isxdigit() only when isascii()==true */
-#define IS_HEX(c) ((c) <= '9' ? (c) >= '0' : (unsigned)(((c) - 'A') & ~0x20) <= ('F' - 'A' + 0U))
-#define IS_BASE32(c) (((c) <= '7' ? ('2' <= (c)) : (unsigned)(((c) - 'A') & ~0x20) <= ('Z' - 'A' + 0U)))
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif /* __cplusplus */
-
-#endif /* HASH_CHECK_H */
+/* hash_check.h - functions to parse a file with hash sums to verify it */
+#ifndef HASH_CHECK_H
+#define HASH_CHECK_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* bit flags for hash_check.flags */
+#define HC_HAS_FILESIZE 1
+#define HC_HAS_EMBCRC32 2
+#define HC_WRONG_FILESIZE 4
+#define HC_WRONG_EMBCRC32 8
+#define HC_WRONG_HASHES 16
+#define HC_FAILED(flags) ((flags) & (HC_WRONG_FILESIZE | HC_WRONG_EMBCRC32 | HC_WRONG_HASHES))
+
+#define HC_MAX_HASHES 32
+
+/**
+ * Parsed hash value.
+ */
+typedef struct hash_value
+{
+ unsigned hash_id; /* the id of hash, if it was detected */
+ unsigned short offset;
+ unsigned char length;
+ unsigned char format;
+} hash_value;
+
+struct rhash_context;
+
+/**
+ * Parsed file info, like the path, size and file hash values.
+ */
+typedef struct hash_check
+{
+ char *file_path; /* parsed file path */
+ uint64_t file_size; /* parsed file size, e.g. from magnet link */
+ unsigned hash_mask; /* the mask of hash ids to verify against */
+ unsigned flags; /* bit flags */
+ unsigned embedded_crc32; /* CRC32 embedded into filename */
+ char *data; /* the buffer with the current hash file line */
+ unsigned found_hash_ids; /* bit mask for matched hash ids */
+ unsigned wrong_hashes; /* bit mask for mismatched hashes */
+ int hashes_num; /* number of parsed hashes */
+ hash_value hashes[HC_MAX_HASHES];
+} hash_check;
+
+int hash_check_parse_line(char* line, hash_check* hashes, int check_eol);
+int hash_check_verify(hash_check* hashes, struct rhash_context* ctx);
+
+void rhash_base32_to_byte(const char* str, unsigned char* bin, int len);
+void rhash_hex_to_byte(const char* str, unsigned char* bin, int len);
+unsigned get_crc32(struct rhash_context* ctx);
+
+/* note: IS_HEX() is defined on ASCII-8 while isxdigit() only when isascii()==true */
+#define IS_HEX(c) ((c) <= '9' ? (c) >= '0' : (unsigned)(((c) - 'A') & ~0x20) <= ('F' - 'A' + 0U))
+#define IS_BASE32(c) (((c) <= '7' ? ('2' <= (c)) : (unsigned)(((c) - 'A') & ~0x20) <= ('Z' - 'A' + 0U)))
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* HASH_CHECK_H */
diff --git a/hash_print.c b/hash_print.c
index 63c787a6..03f0f89c 100644
--- a/hash_print.c
+++ b/hash_print.c
@@ -1,705 +1,705 @@
-/* hash_print.c - output hash sums using printf-like format */
-
-#include
-#include
-#include
-#include
-#ifdef _WIN32
-# include
-# include
-#endif /* _WIN32 */
-
-#include "hash_print.h"
-#include "calc_sums.h"
-#include "common_func.h"
-#include "file.h"
-#include "parse_cmdline.h"
-#include "win_utils.h"
-#include "librhash/rhash.h"
-
-/*=========================================================================
-* Formatted output functions and structures
-*=========================================================================*/
-
-/**
- * The table with information about hash functions.
- */
-print_hash_info hash_info_table[32];
-
-/**
- * Possible types of a print_item.
- */
-enum {
- PRINT_ED2K_LINK = 0x100000,
- PRINT_FLAG_UPPERCASE = 0x200000,
- PRINT_FLAG_RAW = 0x0400000,
- PRINT_FLAG_HEX = 0x0800000,
- PRINT_FLAG_BASE32 = 0x1000000,
- PRINT_FLAG_BASE64 = 0x2000000,
- PRINT_FLAG_PAD_WITH_ZERO = 0x4000000,
- PRINT_FLAGS_ALL = PRINT_FLAG_UPPERCASE | PRINT_FLAG_PAD_WITH_ZERO | PRINT_FLAG_RAW
- | PRINT_FLAG_HEX | PRINT_FLAG_BASE32 | PRINT_FLAG_BASE64,
- PRINT_STR = 0x10000000,
- PRINT_ZERO,
- PRINT_NEWLINE,
- PRINT_FILEPATH,
- PRINT_BASENAME,
- PRINT_URLNAME,
- PRINT_SIZE,
- PRINT_MTIME /*PRINT_ATIME, PRINT_CTIME*/
-};
-
-/* parse a token following a percent sign '%' */
-static print_item* parse_percent_item(const char** str);
-
-/**
- * Allocate new print_item.
- *
- * @param flags the print_item flags
- * @param hash_id optional hash_id
- * @param data optional string to store
- * @return allocated print_item
- */
-static print_item* new_print_item(unsigned flags, unsigned hash_id, const char *data)
-{
- print_item* item = (print_item*)rsh_malloc(sizeof(print_item));
- item->flags = flags;
- item->hash_id = hash_id;
- item->width = 0;
- item->data = (data ? rsh_strdup(data) : NULL);
- item->next = NULL;
- return item;
-}
-
-/**
- * Parse an escaped sequence in a printf-like format string.
- *
- * @param pformat pointer to the sequence, the pointer
- * is changed to point to the next symbol after parsed sequence
- * @return result character
- */
-static char parse_escaped_char(const char **pformat)
-{
- const char* start = *pformat;
- switch ( *((*pformat)++) ) {
- case '0': return '\0';
- case 't': return '\t';
- case 'r': return '\r';
- case 'n': return '\n';
- case '\\': return '\\';
- case 'x':
- /* \xNN byte with hexadecimal value NN (1 to 2 digits) */
- if ( IS_HEX(**pformat) ) {
- int ch;
- ch = (**pformat <= '9' ? **pformat & 15 : (**pformat + 9) & 15);
- (*pformat) ++;
- if (IS_HEX(**pformat)) {
- /* read the second digit */
- ch = 16 * ch + (**pformat <= '9' ? **pformat & 15 : (**pformat + 9) & 15);
- (*pformat)++;
- }
- return ch;
- }
- break;
- default:
- (*pformat)--;
- /* \NNN - character with octal value NNN (1 to 3 digits) */
- if ('0' < **pformat && **pformat <= '7') {
- int ch = *((*pformat)++) - '0';
- if ('0' <= **pformat && **pformat <= '7') {
- ch = ch * 8 + *((*pformat)++) - '0';
- if ('0' <= **pformat && **pformat <= '7')
- ch = ch * 8 + *((*pformat)++) - '0';
- }
- return (char)ch;
- }
- }
- *pformat = start;
- return '\\';
-}
-
-/**
- * Parse format string.
- *
- * @return a print_item list with parsed information
- */
-print_item* parse_print_string(const char* format, unsigned *sum_mask)
-{
- char *buf, *p;
- print_item *list = NULL, **tail, *item = NULL;
-
- buf = p = (char*)rsh_malloc( strlen(format) + 1 );
- tail = &list;
- *sum_mask = 0;
-
- for (;;) {
- while (*format && *format != '%' && *format != '\\')
- *(p++) = *(format++);
-
- if (*format == '\\') {
- format++;
- *p = parse_escaped_char(&format);
- if (*p == '\0') {
- item = new_print_item(PRINT_ZERO, 0, NULL);
-#ifdef _WIN32
- } else if (*p == '\n') {
- item = new_print_item(PRINT_NEWLINE, 0, NULL);
-#endif
- } else {
- p++;
- continue;
- }
- } else if (*format == '%') {
- if ( *(++format) == '%' ) {
- *(p++) = *format++;
- continue;
- } else {
- item = parse_percent_item(&format);
- if (!item) {
- *(p++) = '%';
- continue;
- }
- if (item->hash_id)
- *sum_mask |= item->hash_id;
- }
- }
- if (p > buf || (!*format && list == NULL && item == NULL)) {
- *p = '\0';
- *tail = new_print_item(PRINT_STR, 0, buf);
- tail = &(*tail)->next;
- p = buf;
- }
- if (item) {
- *tail = item;
- tail = &item->next;
- item = NULL;
- }
- if (!*format)
- break;
- };
- free(buf);
- return list;
-}
-
-/**
- * Convert given case-insensitive name to a printf directive id
- *
- * @param name printf directive name (not a 0-terminated)
- * @param length name length
- * @return directive id on success, 0 on fail
- */
-static unsigned printf_name_to_id(const char* name, size_t length, unsigned *flags)
-{
- char buf[20];
- size_t i;
- print_hash_info *info = hash_info_table;
- unsigned bit;
-
- if (length > (sizeof(buf)-1)) return 0;
- for (i = 0; i < length; i++) buf[i] = tolower(name[i]);
-
- /* check for old '%{urlname}' directive for compatibility */
- if (length == 7 && memcmp(buf, "urlname", 7) == 0) {
- *flags = PRINT_URLNAME;
- return 0;
- } else if (length == 5 && memcmp(buf, "mtime", 5) == 0) {
- *flags = PRINT_MTIME;
- return 0;
- }
-
- for (bit = 1; bit <= RHASH_ALL_HASHES; bit = bit << 1, info++) {
- if (memcmp(buf, info->short_name, length) == 0 &&
- info->short_name[length] == 0) return bit;
- }
- return 0;
-}
-
-/**
- * Parse a token followed by a percent sign in a printf-like format string.
- *
- * @return a print_item with parsed information
- */
-print_item* parse_percent_item(const char** str)
-{
- const char* format = *str;
- const char* p = NULL;
- unsigned hash_id = 0;
- unsigned modifier_flags = 0;
- int id_found = 0;
- int width = 0;
- int pad_with_zero_bit = 0;
- print_item* item = NULL;
-
- static const char *short_hash = "CMHTGWRAE";
- static const char *short_other = "Llpfus";
- static const unsigned hash_ids[] = {
- RHASH_CRC32, RHASH_MD5, RHASH_SHA1, RHASH_TTH, RHASH_GOST12_256,
- RHASH_WHIRLPOOL, RHASH_RIPEMD160, RHASH_AICH, RHASH_ED2K
- };
- static const unsigned other_flags[] = {
- PRINT_ED2K_LINK, PRINT_ED2K_LINK, PRINT_FILEPATH, PRINT_BASENAME,
- PRINT_URLNAME, PRINT_SIZE
- };
- /* detect the padding by zeros */
- if (*format == '0') {
- pad_with_zero_bit = PRINT_FLAG_PAD_WITH_ZERO;
- format++;
- }
-
- /* parse the 'b','B','x' and '@' flags */
- if (*format == 'x') {
- modifier_flags |= PRINT_FLAG_HEX;
- format++;
- } else if (*format == 'b') {
- modifier_flags |= PRINT_FLAG_BASE32;
- format++;
- } else if (*format == 'B') {
- modifier_flags |= PRINT_FLAG_BASE64;
- format++;
- } else if (*format == '@') {
- modifier_flags |= PRINT_FLAG_RAW;
- format++;
- }
- for (; isdigit((unsigned char)*format); format++) width = 10 * width + (*format - '0');
-
- /* if a complicated token enconuntered */
- if (*format == '{') {
- /* parse the token of the kind "%{some-token}" */
- const char* p = ++format;
- for (; isalnum((unsigned char)*p) || (*p == '-'); p++);
- if (*p == '}') {
- hash_id = printf_name_to_id(format, (int)(p - (format)), &modifier_flags);
- format--;
- if (hash_id || modifier_flags == PRINT_URLNAME || modifier_flags == PRINT_MTIME) {
- /* set uppercase flag if the first letter of printf-entity is uppercase */
- modifier_flags |= (format[1] & 0x20 ? 0 : PRINT_FLAG_UPPERCASE);
- format = p;
- id_found = 1;
- }
- } else {
- format--;
- }
- }
-
- /* if still not found a token denoting a hash function */
- if (!id_found) {
- const char upper = *format & ~0x20;
- /* if the string terminated just after the '%' character */
- if ( *format == '\0' ) return NULL;
- /* look for a known token */
- if ( (p = strchr(short_hash, upper)) ) {
- assert( (p - short_hash) < (int)(sizeof(hash_ids) / sizeof(unsigned)) );
- hash_id = hash_ids[p - short_hash];
- modifier_flags |= (*format & 0x20 ? 0 : PRINT_FLAG_UPPERCASE);
- }
- else if ( (p = strchr(short_other, *format)) ) {
- assert( (p - short_other) < (int)(sizeof(other_flags) / sizeof(unsigned)) );
- modifier_flags = other_flags[p - short_other];
-
- if (modifier_flags == PRINT_ED2K_LINK) {
- modifier_flags |= (*p & 0x20 ? 0 : PRINT_FLAG_UPPERCASE);
- hash_id = RHASH_ED2K | RHASH_AICH;
- }
- } else {
- return 0; /* no valid token found */
- }
- }
- modifier_flags |= pad_with_zero_bit;
-
- item = new_print_item(modifier_flags, hash_id, NULL);
- item->width = width;
- *str = ++format;
- return item;
-}
-
-/**
- * Print EDonkey 2000 url for given file to a stream.
- *
- * @param out the stream where to print url to
- * @param filename the file name
- * @param filesize the file size
- * @param sums the file hash sums
- */
-static void fprint_ed2k_url(FILE* out, struct file_info *info, int print_type)
-{
- const char *filename = get_basename(file_info_get_utf8_print_path(info));
- int upper_case = (print_type & PRINT_FLAG_UPPERCASE ? RHPR_UPPERCASE : 0);
- int len = urlencode(NULL, filename) + int_len(info->size) + (info->sums_flags & RHASH_AICH ? 84 : 49);
- char* buf = (char*)rsh_malloc( len + 1 );
- char* dst = buf;
-
- assert(info->sums_flags & (RHASH_ED2K|RHASH_AICH));
- assert(info->rctx);
-
- strcpy(dst, "ed2k://|file|");
- dst += 13;
- dst += urlencode(dst, filename);
- *dst++ = '|';
- sprintI64(dst, info->size, 0);
- dst += strlen(dst);
- *dst++ = '|';
- rhash_print(dst, info->rctx, RHASH_ED2K, upper_case);
- dst += 32;
- if ((info->sums_flags & RHASH_AICH) != 0) {
- strcpy(dst, "|h=");
- rhash_print(dst += 3, info->rctx, RHASH_AICH, RHPR_BASE32 | upper_case);
- dst += 32;
- }
- strcpy(dst, "|/");
- rsh_fprintf(out, "%s", buf);
- free(buf);
-}
-
-/**
- * Output aligned uint64_t number to specified output stream.
- *
- * @param out the stream to output to
- * @param filesize the 64-bit integer to output, usually a file size
- * @param width minimal width of integer to output
- * @param flag =1 if the integer shall be prepended by zeros
- */
-static void fprintI64(FILE* out, uint64_t filesize, int width, int zero_pad)
-{
- char *buf = (char*)rsh_malloc(width > 40 ? width + 1 : 41);
- int len = int_len(filesize);
- sprintI64(buf, filesize, width);
- if (len < width && zero_pad) {
- memset(buf, '0', width-len);
- }
- rsh_fprintf(out, "%s", buf);
- free(buf);
-}
-
-/**
-* Print time formatted as hh:mm.ss YYYY-MM-DD to a file stream.
-*
-* @param out the stream to print the time to
-* @param time the time to print
-*/
-static void print_time(FILE *out, time_t time)
-{
- struct tm *t = localtime(&time);
- static struct tm zero_tm;
- if (t == NULL) {
- /* if a strange day, then print `00:00.00 1900-01-00' */
- t = &zero_tm;
- t->tm_hour = t->tm_min = t->tm_sec =
- t->tm_year = t->tm_mon = t->tm_mday = 0;
- }
- rsh_fprintf(out, "%02u:%02u.%02u %4u-%02u-%02u", t->tm_hour, t->tm_min,
- t->tm_sec, (1900 + t->tm_year), t->tm_mon + 1, t->tm_mday);
-}
-
-/**
-* Print time formatted as hh:mm.ss YYYY-MM-DD to a file stream.
-*
-* @param out the stream to print the time to
-* @param time the time to print
-*/
-static void print_time64(FILE *out, uint64_t time)
-{
- print_time(out, (time_t)time);
-}
-
-/**
- * Print formatted file information to given output stream.
- *
- * @param out the stream to print information to
- * @param list the format according to which information shall be printed
- * @param info the file information
- */
-void print_line(FILE* out, print_item* list, struct file_info *info)
-{
- const char* basename = get_basename(info->print_path), *tmp;
- char *url = NULL, *ed2k_url = NULL;
- char buffer[130];
-#ifdef _WIN32
- /* switch to binary mode to correctly output binary hashes */
- int out_fd = _fileno(out);
- int old_mode = (out_fd > 0 && !isatty(out_fd) ? _setmode(out_fd, _O_BINARY) : -1);
-#endif
-
- for (; list; list = list->next) {
- int print_type = list->flags & ~(PRINT_FLAGS_ALL);
- size_t len;
-
- /* output a hash function digest */
- if (list->hash_id && print_type != PRINT_ED2K_LINK) {
- unsigned hash_id = list->hash_id;
- int print_flags = (list->flags & PRINT_FLAG_UPPERCASE ? RHPR_UPPERCASE : 0)
- | (list->flags & PRINT_FLAG_RAW ? RHPR_RAW : 0)
- | (list->flags & PRINT_FLAG_BASE32 ? RHPR_BASE32 : 0)
- | (list->flags & PRINT_FLAG_BASE64 ? RHPR_BASE64 : 0)
- | (list->flags & PRINT_FLAG_HEX ? RHPR_HEX : 0);
- if ((hash_id == RHASH_GOST94 || hash_id == RHASH_GOST94_CRYPTOPRO) && (opt.flags & OPT_GOST_REVERSE))
- print_flags |= RHPR_REVERSE;
-
- len = rhash_print(buffer, info->rctx, hash_id, print_flags);
- assert(len < sizeof(buffer));
-
- /* output the hash, exit on fail */
- rsh_fwrite(buffer, 1, len, out);
- continue;
- }
-
- /* output other special items: filepath, URL-encoded filename etc. */
- switch (print_type) {
- case PRINT_STR:
- rsh_fprintf(out, "%s", list->data);
- break;
- case PRINT_ZERO: /* the '\0' character */
- rsh_fprintf(out, "%c", 0);
- break;
-#ifdef _WIN32
- case PRINT_NEWLINE:
- rsh_fprintf(out, "%s", "\r\n");
- break;
-#endif
- case PRINT_FILEPATH:
- rsh_fprintf(out, "%s", info->print_path);
- break;
- case PRINT_BASENAME: /* the filename without directory */
- rsh_fprintf(out, "%s", basename);
- break;
- case PRINT_URLNAME: /* URL-encoded filename */
- if (!url) {
- tmp = get_basename(file_info_get_utf8_print_path(info));
- url = (char*)rsh_malloc(urlencode(NULL, tmp) + 1);
- urlencode(url, tmp);
- }
- rsh_fprintf(out, "%s", url);
- break;
- case PRINT_MTIME: /* the last-modified tine of the filename */
- print_time64(out, info->file->mtime);
- break;
- case PRINT_SIZE: /* file size */
- fprintI64(out, info->size, list->width, (list->flags & PRINT_FLAG_PAD_WITH_ZERO));
- break;
- case PRINT_ED2K_LINK:
- fprint_ed2k_url(out, info, list->flags);
- break;
- }
- }
- free(url);
- free(ed2k_url);
- fflush(out);
-#ifdef _WIN32
- if (old_mode >= 0)
- _setmode(out_fd, old_mode);
-#endif
-}
-
-/**
- * Release memory allocated by given print_item list.
- *
- * @param list the list to free
- */
-void free_print_list(print_item* list)
-{
- while (list) {
- print_item* next = list->next;
- free((char*)list->data);
- free(list);
- list = next;
- }
-}
-
-/*=========================================================================
-* initialization of internal data
-*=========================================================================*/
-
-/**
- * Initialize information about hashes, stored in the
- * hash_info_table global variable.
- */
-void init_hash_info_table(void)
-{
- unsigned bit;
- unsigned short_opt_mask = RHASH_CRC32 | RHASH_MD5 | RHASH_SHA1 | RHASH_TTH | RHASH_ED2K |
- RHASH_AICH | RHASH_WHIRLPOOL | RHASH_RIPEMD160 | RHASH_GOST12_256 | OPT_ED2K_LINK;
- char* short_opt = "cmhteawrgl";
- print_hash_info *info = hash_info_table;
- unsigned fullmask = RHASH_ALL_HASHES | OPT_ED2K_LINK;
-
- memset(hash_info_table, 0, sizeof(hash_info_table));
-
- for (bit = 1; bit && bit <= fullmask; bit = bit << 1) {
- const char *p;
- char *e, *d;
-
- if (!(bit & fullmask))
- continue;
-
- info->short_char = ((bit & short_opt_mask) != 0 && *short_opt ?
- *(short_opt++) : 0);
-
- info->name = (bit & RHASH_ALL_HASHES ? rhash_get_name(bit) : "ED2K-LINK");
- assert(strlen(info->name) < 19);
- p = info->name;
- d = info->short_name;
- e = info->short_name + 19; /* buffer overflow protection */
-
- if (memcmp(info->name, "SHA", 3) == 0 || memcmp(info->name, "GOST", 4) == 0) {
- strcpy(d, p);
- for (; *d && d < e; d++) {
- if ('A' <= *d && *d <= 'Z') {
- *d |= 0x20;
- }
- }
- } else {
- for (; *p && d < e; p++) {
- if (*p != '-' || p[1] >= '9') {
- *(d++) = (*p | 0x20);
- }
- }
- }
- *d = 0;
- ++info;
- }
-}
-
-/**
- * Initialize printf string according to program options.
- * The function is called only when a printf format string is not specified
- * from command line, so it should be constructed from other options.
- *
- * @param out a string buffer to place the resulting format string into.
- */
-void init_printf_format(strbuf_t* out)
-{
- const char* fmt, *tail = 0;
- unsigned bit, index = 0;
- int uppercase;
- char up_flag;
- unsigned force_base32_mask = 0;
-
- if (!opt.fmt) {
- /* print SFV header for CRC32 or if no hash sums options specified */
- opt.fmt = (opt.sum_flags == RHASH_CRC32 || !opt.sum_flags ? FMT_SFV : FMT_SIMPLE);
- }
- uppercase = ((opt.flags & OPT_UPPERCASE) ||
- (!(opt.flags & OPT_LOWERCASE) && (opt.fmt & FMT_SFV)));
- up_flag = (uppercase ? ~0x20 : 0xFF);
-
- rsh_str_ensure_size(out, 1024); /* allocate big enough buffer */
-
- if (opt.sum_flags & OPT_ED2K_LINK) {
- rsh_str_append_n(out, "%l", 2);
- out->str[1] &= up_flag;
- return;
- }
-
- if (opt.sum_flags == 0) return;
-
- if (opt.fmt == FMT_BSD) {
- fmt = "\003(%p) = \001\\n";
- } else if (opt.fmt == FMT_MAGNET) {
- rsh_str_append(out, "magnet:?xl=%s&dn=%{urlname}");
- fmt = "&xt=urn:\002:\001";
- force_base32_mask = (RHASH_SHA1 | RHASH_BTIH);
- tail = "\\n";
- } else if (opt.fmt == FMT_SIMPLE && 0 == (opt.sum_flags & (opt.sum_flags - 1))) {
- fmt = "\001 %p\\n";
- } else {
- rsh_str_append_n(out, "%p", 2);
- fmt = (opt.fmt == FMT_SFV ? " \001" : " \001");
- tail = "\\n";
- }
-
- /* loop by hashes */
- for (bit = 1 << index; bit && bit <= opt.sum_flags; bit = bit << 1, index++) {
- const char *p;
- print_hash_info *info;
-
- if ((bit & opt.sum_flags) == 0) continue;
- p = fmt;
- info = &hash_info_table[index];
-
- /* ensure the output buffer have enough space */
- rsh_str_ensure_size(out, out->len + 256);
-
- for (;;) {
- int i;
- while (*p >= 0x20) out->str[out->len++] = *(p++);
- if (*p == 0) break;
- switch ((int)*(p++)) {
- case 1:
- out->str[out->len++] = '%';
- if ( (bit & force_base32_mask) != 0 ) {
- out->str[out->len++] = 'b';
- }
- if (info->short_char) out->str[out->len++] = info->short_char & up_flag;
- else {
- char *letter;
- out->str[out->len++] = '{';
- letter = out->str + out->len;
- rsh_str_append(out, info->short_name);
- *letter &= up_flag;
- out->str[out->len++] = '}';
- }
- break;
- case 2:
- rsh_str_append(out, rhash_get_magnet_name(bit));
- break;
- case 3:
- rsh_str_append(out, info->name);
- i = (int)strlen(info->name);
- for (i = (i < 5 ? 6 - i : 1); i > 0; i--) out->str[out->len++] = ' ';
- break;
- }
- }
- }
- if (tail) {
- rsh_str_append(out, tail);
- }
- out->str[out->len] = '\0';
-}
-
-/*=========================================================================
-* SFV format output functions
-*=========================================================================*/
-
-/**
-* Format file information into SFV line and print it to the specified stream.
-*
-* @param out the stream to print the file information to
-* @param file the file info to print
-* @return 0 on success, -1 on fail with error code stored in errno
-*/
-int print_sfv_header_line(FILE* out, file_t* file, const char* printpath)
-{
- char buf[24];
-
- /* skip stdin stream */
- if ((file->mode & FILE_IFSTDIN) != 0) return 0;
-
- /* skip file if it can't be opened with exclusive sharing rights */
- if (file_is_write_locked(file)) return 0;
-
- if (!printpath) printpath = file->path;
- if (printpath[0] == '.' && IS_PATH_SEPARATOR(printpath[1])) printpath += 2;
-
- sprintI64(buf, file->size, 12);
- rsh_fprintf(out, "; %s ", buf);
- print_time64(out, file->mtime);
- rsh_fprintf(out, " %s\n", printpath);
- return 0;
-}
-
-/**
-* Print an SFV header banner. The banner consist of 3 comment lines,
-* with the program description and current time.
-*
-* @param out a stream to print to
-*/
-void print_sfv_banner(FILE* out)
-{
- time_t cur_time = time(NULL);
- struct tm *t = localtime(&cur_time);
- if (t) {
- rsh_fprintf(out, _("; Generated by %s v%s on %4u-%02u-%02u at %02u:%02u.%02u\n"),
- PROGRAM_NAME, get_version_string(),
- (1900 + t->tm_year), t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
- rsh_fprintf(out, _("; Written by Kravchenko Aleksey (Akademgorodok) - http://rhash.sf.net/\n;\n"));
- }
-}
+/* hash_print.c - output hash sums using printf-like format */
+
+#include