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 HashTypes 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 HashTypes 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 -Support RHash -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 +Support RHash +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 +#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")); + } +} diff --git a/hash_print.h b/hash_print.h index 243f34ae..88e207b7 100644 --- a/hash_print.h +++ b/hash_print.h @@ -1,55 +1,55 @@ -/* hash_print.h - functions to print hash sums */ -#ifndef HASH_PRINT_H -#define HASH_PRINT_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * An element of a list specifying an output format. - */ -typedef struct print_item { - struct print_item *next; - unsigned flags; - unsigned hash_id; - unsigned width; - const char *data; -} print_item; - -/** - * Name and other info of a hash function - */ -typedef struct print_hash_info -{ - const char *name; - char short_name[20]; - char short_char; -} print_hash_info; - -extern print_hash_info hash_info_table[]; - -struct file_info; -struct file_t; -struct strbuf_t; - -/* initialization of static data */ -void init_hash_info_table(void); -void init_printf_format(struct strbuf_t* out); - -/* formatted output of hash sums and file information */ -print_item* parse_print_string(const char* format, unsigned *sum_mask); -void print_line(FILE* out, print_item* list, struct file_info *info); -void free_print_list(print_item* list); - -/* SFV format functions */ -void print_sfv_banner(FILE* out); -int print_sfv_header_line(FILE* out, struct file_t* file, const char* printpath); - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ - -#endif /* HASH_PRINT_H */ +/* hash_print.h - functions to print hash sums */ +#ifndef HASH_PRINT_H +#define HASH_PRINT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * An element of a list specifying an output format. + */ +typedef struct print_item { + struct print_item *next; + unsigned flags; + unsigned hash_id; + unsigned width; + const char *data; +} print_item; + +/** + * Name and other info of a hash function + */ +typedef struct print_hash_info +{ + const char *name; + char short_name[20]; + char short_char; +} print_hash_info; + +extern print_hash_info hash_info_table[]; + +struct file_info; +struct file_t; +struct strbuf_t; + +/* initialization of static data */ +void init_hash_info_table(void); +void init_printf_format(struct strbuf_t* out); + +/* formatted output of hash sums and file information */ +print_item* parse_print_string(const char* format, unsigned *sum_mask); +void print_line(FILE* out, print_item* list, struct file_info *info); +void free_print_list(print_item* list); + +/* SFV format functions */ +void print_sfv_banner(FILE* out); +int print_sfv_header_line(FILE* out, struct file_t* file, const char* printpath); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* HASH_PRINT_H */ diff --git a/hash_update.c b/hash_update.c index e6024c2a..b23c70fd 100644 --- a/hash_update.c +++ b/hash_update.c @@ -1,356 +1,356 @@ -/* hash_update.c - functions to update a crc file */ - -#include -#include -#include -#include -#ifndef _WIN32 -# include -#endif - -#include "calc_sums.h" -#include "common_func.h" -#include "file.h" -#include "file_set.h" -#include "file_mask.h" -#include "hash_print.h" -#include "hash_update.h" -#include "output.h" -#include "parse_cmdline.h" -#include "rhash_main.h" -#include "win_utils.h" - -/* first define some internal functions, implemented later in this file */ -static int add_new_crc_entries(file_t* file, file_set *crc_entries); -static int file_set_load_from_crc_file(file_set *set, file_t* file); -static int fix_sfv_header(file_t* file); - -/** - * Update given crc file, by adding to it hashes of files from the same - * directory, but which the crc file doesn't contain yet. - * - * @param file the file containing hash sums - * @return 0 on success, -1 on fail - */ -int update_hash_file(file_t* file) -{ - file_set* crc_entries; - timedelta_t timer; - int res; - - if (opt.flags & OPT_VERBOSE) { - log_msg(_("Updating: %s\n"), file->path); - } - - crc_entries = file_set_new(); - res = file_set_load_from_crc_file(crc_entries, file); - - if (opt.flags & OPT_SPEED) rsh_timer_start(&timer); - rhash_data.total_size = 0; - rhash_data.processed = 0; - - if (res == 0) { - /* add the crc file itself to the set of excluded from re-calculation files */ - file_set_add_name(crc_entries, get_basename(file->path)); - file_set_sort(crc_entries); - - /* update crc file with sums of files not present in the crc_entries */ - res = add_new_crc_entries(file, crc_entries); - } - file_set_free(crc_entries); - - if (opt.flags & OPT_SPEED && rhash_data.processed > 0) { - double time = rsh_timer_stop(&timer); - print_time_stats(time, rhash_data.total_size, 1); - } - - return res; -} - -/** - * Load a set of files from given crc file. - * - * @param set the file set to store loaded files - * @param file the file containing hash sums to load - * @return 0 on success, -1 on fail with error code in errno - */ -static int file_set_load_from_crc_file(file_set *set, file_t* file) -{ - FILE *fd; - int line_num; - char buf[2048]; - hash_check hc; - - if ( !(fd = file_fopen(file, FOpenRead | FOpenBin) )) { - /* if file not exist, it will be created */ - return (errno == ENOENT ? 0 : -1); - } - for (line_num = 0; fgets(buf, 2048, fd); line_num++) { - char* line = buf; - - /* 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(_("skipping binary file %s\n"), file->path); - fclose(fd); - return -1; - } - - if (IS_COMMENT(*line) || *line == '\r' || *line == '\n') continue; - - /* parse a hash file line */ - if (hash_check_parse_line(line, &hc, !feof(fd))) { - /* store file info to the file set */ - if (hc.file_path) file_set_add_name(set, hc.file_path); - } - } - fclose(fd); - return 0; -} - -/** - * Add hash sums of files from given file-set to a specified hash-file. - * A specified directory path will be prepended to the path of added files, - * if it is not a current directory. - * - * @param file the hash file to add the hash sums to - * @param dir_path the directory path to prepend - * @param files_to_add the set of files to hash and add - * @return 0 on success, -1 on error - */ -static int add_sums_to_file(file_t* file, char* dir_path, file_set *files_to_add) -{ - FILE* fd; - unsigned i; - int ch; - - /* SFV banner will be printed only in SFV mode and only for empty crc files */ - int print_banner = (opt.fmt == FMT_SFV); - - file->size = 0; - if (file_stat(file, 0) == 0) { - if (print_banner && file->size > 0) print_banner = 0; - } - - /* open the hash file for writing */ - if ( !(fd = file_fopen(file, FOpenRead | FOpenWrite) )) { - log_file_t_error(file); - return -1; - } - rhash_data.upd_fd = fd; - - if (file->size > 0) { - /* read the last character of the file to check if it is EOL */ - if (fseek(fd, -1, SEEK_END) != 0) { - log_file_t_error(file); - return -1; - } - ch = fgetc(fd); - - /* somehow writing doesn't work without seeking */ - if (fseek(fd, 0, SEEK_END) != 0) { - log_file_t_error(file); - return -1; - } - - /* write EOL if it wasn't present */ - if (ch != '\n' && ch != '\r') { - /* fputc('\n', fd); */ - rsh_fprintf(fd, "\n"); - } - } - - /* append hash sums to the updated crc file */ - for (i = 0; i < files_to_add->size; i++, rhash_data.processed++) { - file_t file; - char *print_path = file_set_get(files_to_add, i)->filepath; - memset(&file, 0, sizeof(file)); - - if (dir_path[0] != '.' || dir_path[1] != 0) { - /* prepend the file path by directory path */ - file_init(&file, make_path(dir_path, print_path), 0); - } else { - file_init(&file, print_path, FILE_OPT_DONT_FREE_PATH); - } - - if (opt.fmt == FMT_SFV) { - if (print_banner) { - print_sfv_banner(fd); - print_banner = 0; - } - } - file_stat(&file, 0); - - /* print hash sums to the crc file */ - calculate_and_print_sums(fd, &file, print_path); - - file_cleanup(&file); - - if (rhash_data.interrupted) { - fclose(fd); - return 0; - } - } - fclose(fd); - log_msg(_("Updated: %s\n"), file->path); - return 0; -} - -/** - * Read a directory and load files not present in the crc_entries file-set - * into the files_to_add file-set. - * - * @param dir_path the path of the directory to load files from - * @param crc_entries file-set of files which should be skipped - * @param files_to_add file-set to load the list of files into - * @return 0 on success, -1 on error (and errno is set) - */ -static int load_filtered_dir(const char* dir_path, file_set *crc_entries, file_set *files_to_add) -{ - DIR *dp; - struct dirent *de; - - /* read directory */ - dp = opendir(dir_path); - if (!dp) return -1; - - while ((de = readdir(dp)) != NULL) { - char *path; - unsigned is_regular; - - /* skip "." and ".." directories */ - if (de->d_name[0] == '.' && (de->d_name[1] == 0 || - (de->d_name[1] == '.' && de->d_name[2] == 0))) { - continue; - } - - /* check if the file is a regular one */ - path = make_path(dir_path, de->d_name); - is_regular = is_regular_file(path); - free(path); - - /* skip non-regular files (directories, device files, e.t.c.), - * as well as files not accepted by current file filter - * and files already present in the crc_entries file set */ - if (!is_regular || !file_mask_match(opt.files_accept, de->d_name) || - (opt.files_exclude && file_mask_match(opt.files_exclude, de->d_name)) || - file_set_exist(crc_entries, de->d_name)) - { - continue; - } - - file_set_add_name(files_to_add, de->d_name); - } - return 0; -} - -/** - * Calculate and add to the given hash-file the hash-sums for all files - * from the same directory as the hash-file, but absent from given - * crc_entries file-set. - * - *

If SFV format was specified by a command line switch, the after adding - * hash sums SFV header of the file is fixed by moving all lines starting - * with a semicolon before other lines. So an SFV-formatted hash-file - * will remain correct. - * - * @param file the hash-file to add sums into - * @param crc_entries file-set of files to omit from adding - * @return 0 on success, -1 on error - */ -static int add_new_crc_entries(file_t* file, file_set *crc_entries) -{ - file_set* files_to_add; - char* dir_path; - int res = 0; - - dir_path = get_dirname(file->path); - files_to_add = file_set_new(); - - /* load into files_to_add files from directory not present in the crc_entries */ - load_filtered_dir(dir_path, crc_entries, files_to_add); - - if (files_to_add->size > 0) { - /* sort files by path */ - file_set_sort_by_path(files_to_add); - - /* calculate and write crc sums to the file */ - res = add_sums_to_file(file, dir_path, files_to_add); - - if (res == 0 && opt.fmt == FMT_SFV && !rhash_data.interrupted) { - /* move SFV header from the end of updated file to its head */ - res = fix_sfv_header(file); - } - } - - file_set_free(files_to_add); - free(dir_path); - return res; -} - -/** - * Move all SFV header lines (i.e. all lines starting with a semicolon) - * from the end of updated file to its head. - * - * @param file the hash file requiring fixing of its SFV header - */ -static int fix_sfv_header(file_t* file) -{ - FILE* in; - FILE* out; - char line[2048]; - file_t new_file; - int err = 0; - - if ( !(in = file_fopen(file, FOpenRead))) { - log_file_t_error(file); - return -1; - } - - /* open a temporary file for writing */ - file_path_append(&new_file, file, ".new"); - if ( !(out = file_fopen(&new_file, FOpenWrite) )) { - log_file_t_error(&new_file); - file_cleanup(&new_file); - fclose(in); - return -1; - } - - /* The first, output all commented lines to the file header */ - while (fgets(line, 2048, in)) { - if (*line == ';') { - if (fputs(line, out) < 0) break; - } - } - if (!ferror(out) && !ferror(in)) { - fseek(in, 0, SEEK_SET); - /* The second, output non-commented lines */ - while (fgets(line, 2048, in)) { - if (*line != ';') { - if (fputs(line, out) < 0) break; - } - } - } - if (ferror(in)) { - log_file_t_error(file); - err = 1; - } - if (ferror(out)) { - log_file_t_error(&new_file); - err = 1; - } - - fclose(in); - fclose(out); - - /* overwrite the hash file with a new one */ - if (!err && file_rename(&new_file, file) < 0) { - log_error(_("can't move %s to %s: %s\n"), - new_file.path, file->path, strerror(errno)); - } - file_cleanup(&new_file); - return (err ? -1 : 0); -} +/* hash_update.c - functions to update a crc file */ + +#include +#include +#include +#include +#ifndef _WIN32 +# include +#endif + +#include "calc_sums.h" +#include "common_func.h" +#include "file.h" +#include "file_set.h" +#include "file_mask.h" +#include "hash_print.h" +#include "hash_update.h" +#include "output.h" +#include "parse_cmdline.h" +#include "rhash_main.h" +#include "win_utils.h" + +/* first define some internal functions, implemented later in this file */ +static int add_new_crc_entries(file_t* file, file_set *crc_entries); +static int file_set_load_from_crc_file(file_set *set, file_t* file); +static int fix_sfv_header(file_t* file); + +/** + * Update given crc file, by adding to it hashes of files from the same + * directory, but which the crc file doesn't contain yet. + * + * @param file the file containing hash sums + * @return 0 on success, -1 on fail + */ +int update_hash_file(file_t* file) +{ + file_set* crc_entries; + timedelta_t timer; + int res; + + if (opt.flags & OPT_VERBOSE) { + log_msg(_("Updating: %s\n"), file->path); + } + + crc_entries = file_set_new(); + res = file_set_load_from_crc_file(crc_entries, file); + + if (opt.flags & OPT_SPEED) rsh_timer_start(&timer); + rhash_data.total_size = 0; + rhash_data.processed = 0; + + if (res == 0) { + /* add the crc file itself to the set of excluded from re-calculation files */ + file_set_add_name(crc_entries, get_basename(file->path)); + file_set_sort(crc_entries); + + /* update crc file with sums of files not present in the crc_entries */ + res = add_new_crc_entries(file, crc_entries); + } + file_set_free(crc_entries); + + if (opt.flags & OPT_SPEED && rhash_data.processed > 0) { + double time = rsh_timer_stop(&timer); + print_time_stats(time, rhash_data.total_size, 1); + } + + return res; +} + +/** + * Load a set of files from given crc file. + * + * @param set the file set to store loaded files + * @param file the file containing hash sums to load + * @return 0 on success, -1 on fail with error code in errno + */ +static int file_set_load_from_crc_file(file_set *set, file_t* file) +{ + FILE *fd; + int line_num; + char buf[2048]; + hash_check hc; + + if ( !(fd = file_fopen(file, FOpenRead | FOpenBin) )) { + /* if file not exist, it will be created */ + return (errno == ENOENT ? 0 : -1); + } + for (line_num = 0; fgets(buf, 2048, fd); line_num++) { + char* line = buf; + + /* 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(_("skipping binary file %s\n"), file->path); + fclose(fd); + return -1; + } + + if (IS_COMMENT(*line) || *line == '\r' || *line == '\n') continue; + + /* parse a hash file line */ + if (hash_check_parse_line(line, &hc, !feof(fd))) { + /* store file info to the file set */ + if (hc.file_path) file_set_add_name(set, hc.file_path); + } + } + fclose(fd); + return 0; +} + +/** + * Add hash sums of files from given file-set to a specified hash-file. + * A specified directory path will be prepended to the path of added files, + * if it is not a current directory. + * + * @param file the hash file to add the hash sums to + * @param dir_path the directory path to prepend + * @param files_to_add the set of files to hash and add + * @return 0 on success, -1 on error + */ +static int add_sums_to_file(file_t* file, char* dir_path, file_set *files_to_add) +{ + FILE* fd; + unsigned i; + int ch; + + /* SFV banner will be printed only in SFV mode and only for empty crc files */ + int print_banner = (opt.fmt == FMT_SFV); + + file->size = 0; + if (file_stat(file, 0) == 0) { + if (print_banner && file->size > 0) print_banner = 0; + } + + /* open the hash file for writing */ + if ( !(fd = file_fopen(file, FOpenRead | FOpenWrite) )) { + log_file_t_error(file); + return -1; + } + rhash_data.upd_fd = fd; + + if (file->size > 0) { + /* read the last character of the file to check if it is EOL */ + if (fseek(fd, -1, SEEK_END) != 0) { + log_file_t_error(file); + return -1; + } + ch = fgetc(fd); + + /* somehow writing doesn't work without seeking */ + if (fseek(fd, 0, SEEK_END) != 0) { + log_file_t_error(file); + return -1; + } + + /* write EOL if it wasn't present */ + if (ch != '\n' && ch != '\r') { + /* fputc('\n', fd); */ + rsh_fprintf(fd, "\n"); + } + } + + /* append hash sums to the updated crc file */ + for (i = 0; i < files_to_add->size; i++, rhash_data.processed++) { + file_t file; + char *print_path = file_set_get(files_to_add, i)->filepath; + memset(&file, 0, sizeof(file)); + + if (dir_path[0] != '.' || dir_path[1] != 0) { + /* prepend the file path by directory path */ + file_init(&file, make_path(dir_path, print_path), 0); + } else { + file_init(&file, print_path, FILE_OPT_DONT_FREE_PATH); + } + + if (opt.fmt == FMT_SFV) { + if (print_banner) { + print_sfv_banner(fd); + print_banner = 0; + } + } + file_stat(&file, 0); + + /* print hash sums to the crc file */ + calculate_and_print_sums(fd, &file, print_path); + + file_cleanup(&file); + + if (rhash_data.interrupted) { + fclose(fd); + return 0; + } + } + fclose(fd); + log_msg(_("Updated: %s\n"), file->path); + return 0; +} + +/** + * Read a directory and load files not present in the crc_entries file-set + * into the files_to_add file-set. + * + * @param dir_path the path of the directory to load files from + * @param crc_entries file-set of files which should be skipped + * @param files_to_add file-set to load the list of files into + * @return 0 on success, -1 on error (and errno is set) + */ +static int load_filtered_dir(const char* dir_path, file_set *crc_entries, file_set *files_to_add) +{ + DIR *dp; + struct dirent *de; + + /* read directory */ + dp = opendir(dir_path); + if (!dp) return -1; + + while ((de = readdir(dp)) != NULL) { + char *path; + unsigned is_regular; + + /* skip "." and ".." directories */ + if (de->d_name[0] == '.' && (de->d_name[1] == 0 || + (de->d_name[1] == '.' && de->d_name[2] == 0))) { + continue; + } + + /* check if the file is a regular one */ + path = make_path(dir_path, de->d_name); + is_regular = is_regular_file(path); + free(path); + + /* skip non-regular files (directories, device files, e.t.c.), + * as well as files not accepted by current file filter + * and files already present in the crc_entries file set */ + if (!is_regular || !file_mask_match(opt.files_accept, de->d_name) || + (opt.files_exclude && file_mask_match(opt.files_exclude, de->d_name)) || + file_set_exist(crc_entries, de->d_name)) + { + continue; + } + + file_set_add_name(files_to_add, de->d_name); + } + return 0; +} + +/** + * Calculate and add to the given hash-file the hash-sums for all files + * from the same directory as the hash-file, but absent from given + * crc_entries file-set. + * + *

If SFV format was specified by a command line switch, the after adding + * hash sums SFV header of the file is fixed by moving all lines starting + * with a semicolon before other lines. So an SFV-formatted hash-file + * will remain correct. + * + * @param file the hash-file to add sums into + * @param crc_entries file-set of files to omit from adding + * @return 0 on success, -1 on error + */ +static int add_new_crc_entries(file_t* file, file_set *crc_entries) +{ + file_set* files_to_add; + char* dir_path; + int res = 0; + + dir_path = get_dirname(file->path); + files_to_add = file_set_new(); + + /* load into files_to_add files from directory not present in the crc_entries */ + load_filtered_dir(dir_path, crc_entries, files_to_add); + + if (files_to_add->size > 0) { + /* sort files by path */ + file_set_sort_by_path(files_to_add); + + /* calculate and write crc sums to the file */ + res = add_sums_to_file(file, dir_path, files_to_add); + + if (res == 0 && opt.fmt == FMT_SFV && !rhash_data.interrupted) { + /* move SFV header from the end of updated file to its head */ + res = fix_sfv_header(file); + } + } + + file_set_free(files_to_add); + free(dir_path); + return res; +} + +/** + * Move all SFV header lines (i.e. all lines starting with a semicolon) + * from the end of updated file to its head. + * + * @param file the hash file requiring fixing of its SFV header + */ +static int fix_sfv_header(file_t* file) +{ + FILE* in; + FILE* out; + char line[2048]; + file_t new_file; + int err = 0; + + if ( !(in = file_fopen(file, FOpenRead))) { + log_file_t_error(file); + return -1; + } + + /* open a temporary file for writing */ + file_path_append(&new_file, file, ".new"); + if ( !(out = file_fopen(&new_file, FOpenWrite) )) { + log_file_t_error(&new_file); + file_cleanup(&new_file); + fclose(in); + return -1; + } + + /* The first, output all commented lines to the file header */ + while (fgets(line, 2048, in)) { + if (*line == ';') { + if (fputs(line, out) < 0) break; + } + } + if (!ferror(out) && !ferror(in)) { + fseek(in, 0, SEEK_SET); + /* The second, output non-commented lines */ + while (fgets(line, 2048, in)) { + if (*line != ';') { + if (fputs(line, out) < 0) break; + } + } + } + if (ferror(in)) { + log_file_t_error(file); + err = 1; + } + if (ferror(out)) { + log_file_t_error(&new_file); + err = 1; + } + + fclose(in); + fclose(out); + + /* overwrite the hash file with a new one */ + if (!err && file_rename(&new_file, file) < 0) { + log_error(_("can't move %s to %s: %s\n"), + new_file.path, file->path, strerror(errno)); + } + file_cleanup(&new_file); + return (err ? -1 : 0); +} diff --git a/hash_update.h b/hash_update.h index 82081394..8cf6fe95 100644 --- a/hash_update.h +++ b/hash_update.h @@ -1,15 +1,15 @@ -/* hash_update.h - functions to update a crc file */ -#ifndef HASH_UPDATE_H -#define HASH_UPDATE_H - -#ifdef __cplusplus -extern "C" { -#endif - -int update_hash_file(file_t* file); - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ - -#endif /* HASH_UPDATE_H */ +/* hash_update.h - functions to update a crc file */ +#ifndef HASH_UPDATE_H +#define HASH_UPDATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +int update_hash_file(file_t* file); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* HASH_UPDATE_H */ diff --git a/librhash/Doxyfile b/librhash/Doxyfile index 67dc24d7..19c08861 100644 --- a/librhash/Doxyfile +++ b/librhash/Doxyfile @@ -1,2428 +1,2428 @@ -# Doxyfile 1.8.11 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. -# -# All text after a double hash (##) is considered a comment and is placed in -# front of the TAG it is preceding. -# -# All text after a single hash (#) is considered a comment and will be ignored. -# The format is: -# TAG = value [value, ...] -# For lists, items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (\" \"). - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. -# The default value is: UTF-8. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by -# double-quotes, unless you are using Doxywizard) that should identify the -# project for which the documentation is generated. This name is used in the -# title of most generated pages and in a few other places. -# The default value is: My Project. - -PROJECT_NAME = RHash - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. This -# could be handy for archiving the generated documentation or if some version -# control system is used. - -PROJECT_NUMBER = - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer a -# quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify a logo or an icon that is included -# in the documentation. The maximum height of the logo should not exceed 55 -# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy -# the logo to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path -# into which the generated documentation will be written. If a relative path is -# entered, it will be relative to the location where doxygen was started. If -# left blank the current directory will be used. - -OUTPUT_DIRECTORY = docs - -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this -# option can be useful when feeding doxygen a huge amount of source files, where -# putting all generated files in the same directory would otherwise causes -# performance problems for the file system. -# The default value is: NO. - -CREATE_SUBDIRS = NO - -# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII -# characters to appear in the names of generated files. If set to NO, non-ASCII -# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode -# U+3044. -# The default value is: NO. - -ALLOW_UNICODE_NAMES = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. -# The default value is: English. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member -# descriptions after the members that are listed in the file and class -# documentation (similar to Javadoc). Set to NO to disable this. -# The default value is: YES. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief -# description of a member or function before the detailed description -# -# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. -# The default value is: YES. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator that is -# used to form the text in various listings. Each string in this list, if found -# as the leading text of the brief description, will be stripped from the text -# and the result, after processing the whole list, is used as the annotated -# text. Otherwise, the brief description is used as-is. If left blank, the -# following values are used ($name is automatically replaced with the name of -# the entity):The $name class, The $name widget, The $name file, is, provides, -# specifies, contains, represents, a, an and the. - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# doxygen will generate a detailed section even if there is only a brief -# description. -# The default value is: NO. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. -# The default value is: NO. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path -# before files name in the file list and in the header files. If set to NO the -# shortest path that makes the file name unique will be used -# The default value is: YES. - -FULL_PATH_NAMES = YES - -# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. -# Stripping is only done if one of the specified strings matches the left-hand -# part of the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the path to -# strip. -# -# Note that you can specify absolute paths here, but also relative paths, which -# will be relative from the directory where doxygen is started. -# This tag requires that the tag FULL_PATH_NAMES is set to YES. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the -# path mentioned in the documentation of a class, which tells the reader which -# header file to include in order to use a class. If left blank only the name of -# the header file containing the class definition is used. Otherwise one should -# specify the list of include paths that are normally passed to the compiler -# using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but -# less readable) file names. This can be useful is your file systems doesn't -# support long names like on DOS, Mac, or CD-ROM. -# The default value is: NO. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the -# first line (until the first dot) of a Javadoc-style comment as the brief -# description. If set to NO, the Javadoc-style will behave just like regular Qt- -# style comments (thus requiring an explicit @brief command for a brief -# description.) -# The default value is: NO. - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first -# line (until the first dot) of a Qt-style comment as the brief description. If -# set to NO, the Qt-style will behave just like regular Qt-style comments (thus -# requiring an explicit \brief command for a brief description.) -# The default value is: NO. - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a -# multi-line C++ special comment block (i.e. a block of //! or /// comments) as -# a brief description. This used to be the default behavior. The new default is -# to treat a multi-line C++ comment block as a detailed description. Set this -# tag to YES if you prefer the old behavior instead. -# -# Note that setting this tag to YES also means that rational rose comments are -# not recognized any more. -# The default value is: NO. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the -# documentation from any documented member that it re-implements. -# The default value is: YES. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new -# page for each member. If set to NO, the documentation of a member will be part -# of the file/class/namespace that contains it. -# The default value is: NO. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen -# uses this value to replace tabs by spaces in code fragments. -# Minimum value: 1, maximum value: 16, default value: 4. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that act as commands in -# the documentation. An alias has the form: -# name=value -# For example adding -# "sideeffect=@par Side Effects:\n" -# will allow you to put the command \sideeffect (or @sideeffect) in the -# documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. - -ALIASES = - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources -# only. Doxygen will then generate output that is more tailored for C. For -# instance, some of the names that are used will be different. The list of all -# members will be omitted, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_FOR_C = YES - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or -# Python sources only. Doxygen will then generate output that is more tailored -# for that language. For instance, namespaces will be presented as packages, -# qualified scopes will look different, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources. Doxygen will then generate output that is tailored for Fortran. -# The default value is: NO. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for VHDL. -# The default value is: NO. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can override or extend it -# using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: -# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: -# Fortran. In the later case the parser tries to guess whether the code is fixed -# or free formatted code, this is the default for Fortran type files), VHDL. For -# instance to make doxygen treat .inc files as Fortran files (default is PHP), -# and .f files as C (default is Fortran), use: inc=Fortran f=C. -# -# Note: For files without extension you can use no_extension as a placeholder. -# -# Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments -# according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you can -# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in -# case of backward compatibilities issues. -# The default value is: YES. - -MARKDOWN_SUPPORT = YES - -# When enabled doxygen tries to link words that correspond to documented -# classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by putting a % sign in front of the word or -# globally by setting AUTOLINK_SUPPORT to NO. -# The default value is: YES. - -AUTOLINK_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should set this -# tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. -# The default value is: NO. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. -# The default value is: NO. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. -# The default value is: NO. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate -# getter and setter methods for a property. Setting this option to YES will make -# doxygen to replace the get and set methods by a property in the documentation. -# This will only work if the methods are indeed getting or setting a simple -# type. If this is not the case, or you want to show the methods anyway, you -# should set this option to NO. -# The default value is: YES. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. -# The default value is: NO. - -DISTRIBUTE_GROUP_DOC = NO - -# If one adds a struct or class to a group and this option is enabled, then also -# any nested class or struct is added to the same group. By default this option -# is disabled and one has to add nested compounds explicitly via \ingroup. -# The default value is: NO. - -GROUP_NESTED_COMPOUNDS = NO - -# Set the SUBGROUPING tag to YES to allow class member groups of the same type -# (for instance a group of public functions) to be put as a subgroup of that -# type (e.g. under the Public Functions section). Set it to NO to prevent -# subgrouping. Alternatively, this can be done per class using the -# \nosubgrouping command. -# The default value is: YES. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions -# are shown inside the group in which they are included (e.g. using \ingroup) -# instead of on a separate page (for HTML and Man pages) or section (for LaTeX -# and RTF). -# -# Note that this feature does not work in combination with -# SEPARATE_MEMBER_PAGES. -# The default value is: NO. - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions -# with only public data fields or simple typedef fields will be shown inline in -# the documentation of the scope in which they are defined (i.e. file, -# namespace, or group documentation), provided this scope is documented. If set -# to NO, structs, classes, and unions are shown on a separate page (for HTML and -# Man pages) or section (for LaTeX and RTF). -# The default value is: NO. - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or -# enum is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically be -# useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. -# The default value is: NO. - -TYPEDEF_HIDES_STRUCT = NO - -# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This -# cache is used to resolve symbols given their name and scope. Since this can be -# an expensive process and often the same symbol appears multiple times in the -# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small -# doxygen will become slower. If the cache is too large, memory is wasted. The -# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range -# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 -# symbols. At the end of a run doxygen will report the cache usage and suggest -# the optimal cache size from a speed point of view. -# Minimum value: 0, maximum value: 9, default value: 0. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in -# documentation are documented, even if no documentation was available. Private -# class members and static file members will be hidden unless the -# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. -# Note: This will also disable the warnings about undocumented members that are -# normally produced when WARNINGS is set to YES. -# The default value is: NO. - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will -# be included in the documentation. -# The default value is: NO. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal -# scope will be included in the documentation. -# The default value is: NO. - -EXTRACT_PACKAGE = NO - -# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be -# included in the documentation. -# The default value is: NO. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO, -# only classes defined in header files are included. Does not have any effect -# for Java sources. -# The default value is: YES. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. If set to YES, local methods, -# which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO, only methods in the interface are -# included. -# The default value is: NO. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base name of -# the file that contains the anonymous namespace. By default anonymous namespace -# are hidden. -# The default value is: NO. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all -# undocumented members inside documented classes or files. If set to NO these -# members will be included in the various overviews, but no documentation -# section is generated. This option has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. If set -# to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO, these declarations will be -# included in the documentation. -# The default value is: NO. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO, these -# blocks will be appended to the function's detailed documentation block. -# The default value is: NO. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation that is typed after a -# \internal command is included. If the tag is set to NO then the documentation -# will be excluded. Set it to YES to include the internal documentation. -# The default value is: NO. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES, upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. -# The default value is: system dependent. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES, the -# scope will be hidden. -# The default value is: NO. - -HIDE_SCOPE_NAMES = NO - -# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will -# append additional text to a page's title, such as Class Reference. If set to -# YES the compound reference will be hidden. -# The default value is: NO. - -HIDE_COMPOUND_REFERENCE= NO - -# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of -# the files that are included by a file in the documentation of that file. -# The default value is: YES. - -SHOW_INCLUDE_FILES = YES - -# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each -# grouped member an include statement to the documentation, telling the reader -# which file to include in order to use the member. -# The default value is: NO. - -SHOW_GROUPED_MEMB_INC = NO - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include -# files with double quotes in the documentation rather than with sharp brackets. -# The default value is: NO. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the -# documentation for inline members. -# The default value is: YES. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the -# (detailed) documentation of file and class members alphabetically by member -# name. If set to NO, the members will appear in declaration order. -# The default value is: YES. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief -# descriptions of file, namespace and class members alphabetically by member -# name. If set to NO, the members will appear in declaration order. Note that -# this will also influence the order of the classes in the class list. -# The default value is: NO. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the -# (brief and detailed) documentation of class members so that constructors and -# destructors are listed first. If set to NO the constructors will appear in the -# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. -# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief -# member documentation. -# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting -# detailed member documentation. -# The default value is: NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy -# of group names into alphabetical order. If set to NO the group names will -# appear in their defined order. -# The default value is: NO. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by -# fully-qualified names, including namespaces. If set to NO, the class list will -# be sorted only by class name, not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the alphabetical -# list. -# The default value is: NO. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper -# type resolution of all parameters of a function it will reject a match between -# the prototype and the implementation of a member function even if there is -# only one candidate or it is obvious which candidate to choose by doing a -# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still -# accept a match between prototype and implementation in such cases. -# The default value is: NO. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo -# list. This list is created by putting \todo commands in the documentation. -# The default value is: YES. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test -# list. This list is created by putting \test commands in the documentation. -# The default value is: YES. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug -# list. This list is created by putting \bug commands in the documentation. -# The default value is: YES. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) -# the deprecated list. This list is created by putting \deprecated commands in -# the documentation. -# The default value is: YES. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional documentation -# sections, marked by \if ... \endif and \cond -# ... \endcond blocks. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the -# initial value of a variable or macro / define can have for it to appear in the -# documentation. If the initializer consists of more lines than specified here -# it will be hidden. Use a value of 0 to hide initializers completely. The -# appearance of the value of individual variables and macros / defines can be -# controlled using \showinitializer or \hideinitializer command in the -# documentation regardless of this setting. -# Minimum value: 0, maximum value: 10000, default value: 30. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES, the -# list will mention the files that were used to generate the documentation. -# The default value is: YES. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This -# will remove the Files entry from the Quick Index and from the Folder Tree View -# (if specified). -# The default value is: YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces -# page. This will remove the Namespaces entry from the Quick Index and from the -# Folder Tree View (if specified). -# The default value is: YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command command input-file, where command is the value of the -# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided -# by doxygen. Whatever the program writes to standard output is used as the file -# version. For an example see the documentation. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. You can -# optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. -# -# Note that if you run doxygen from a directory containing a file called -# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE -# tag is left empty. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files containing -# the reference definitions. This must be a list of .bib files. The .bib -# extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. -# For LaTeX the style of the bibliography can be controlled using -# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. See also \cite for info how to create references. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# Configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated to -# standard output by doxygen. If QUIET is set to YES this implies that the -# messages are off. -# The default value is: NO. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES -# this implies that the warnings are on. -# -# Tip: Turn warnings on while writing the documentation. -# The default value is: YES. - -WARNINGS = YES - -# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate -# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag -# will automatically be disabled. -# The default value is: YES. - -WARN_IF_UNDOCUMENTED = YES - -# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. -# The default value is: YES. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that -# are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. -# The default value is: NO. - -WARN_NO_PARAMDOC = NO - -# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. -# The default value is: NO. - -WARN_AS_ERROR = NO - -# The WARN_FORMAT tag determines the format of the warning messages that doxygen -# can produce. The string should contain the $file, $line, and $text tags, which -# will be replaced by the file and line number from which the warning originated -# and the warning text. Optionally the format may contain $version, which will -# be replaced by the version of the file (if it could be obtained via -# FILE_VERSION_FILTER) -# The default value is: $file:$line: $text. - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning and error -# messages should be written. If left blank the output is written to standard -# error (stderr). - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# Configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag is used to specify the files and/or directories that contain -# documented source files. You may enter file names like myfile.cpp or -# directories like /usr/src/myproject. Separate the files or directories with -# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING -# Note: If this tag is empty the current directory is searched. - -INPUT = rhash.h \ - rhash_torrent.h - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses -# libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of -# possible encodings. -# The default value is: UTF-8. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# read by doxygen. -# -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl, -# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js. - -FILE_PATTERNS = - -# The RECURSIVE tag can be used to specify whether or not subdirectories should -# be searched for input files as well. -# The default value is: NO. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. -# The default value is: NO. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or directories -# that contain example code fragments that are included (see the \include -# command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank all -# files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude commands -# irrespective of the value of the RECURSIVE tag. -# The default value is: NO. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or directories -# that contain images that are to be included in the documentation (see the -# \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command: -# -# -# -# where is the value of the INPUT_FILTER tag, and is the -# name of an input file. Doxygen will then use the output that the filter -# program writes to standard output. If FILTER_PATTERNS is specified, this tag -# will be ignored. -# -# Note that the filter must not add or remove lines; it is applied before the -# code is scanned, but not when the output code is generated. If lines are added -# or removed, the anchors will not be placed correctly. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# properly processed by doxygen. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: pattern=filter -# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how -# filters are used. If the FILTER_PATTERNS tag is empty or if none of the -# patterns match the file name, INPUT_FILTER is applied. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# properly processed by doxygen. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will also be used to filter the input files that are used for -# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). -# The default value is: NO. - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and -# it is also possible to disable source filtering for a specific pattern using -# *.ext= (so without naming a filter). -# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. - -FILTER_SOURCE_PATTERNS = - -# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that -# is part of the input, its contents will be placed on the main page -# (index.html). This can be useful if you have a project on for instance GitHub -# and want to reuse the introduction page also for the doxygen output. - -USE_MDFILE_AS_MAINPAGE = - -#--------------------------------------------------------------------------- -# Configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will be -# generated. Documented entities will be cross-referenced with these sources. -# -# Note: To get rid of all source code in the generated output, make sure that -# also VERBATIM_HEADERS is set to NO. -# The default value is: NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. -# The default value is: NO. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any -# special comment blocks from generated source code fragments. Normal C, C++ and -# Fortran comments will always remain visible. -# The default value is: YES. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. -# The default value is: NO. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES then for each documented function -# all documented entities called/used by that function will be listed. -# The default value is: NO. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES then the hyperlinks from functions in REFERENCES_RELATION and -# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will -# link to the documentation. -# The default value is: YES. - -REFERENCES_LINK_SOURCE = YES - -# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the -# source code will show a tooltip with additional information such as prototype, -# brief description and links to the definition and documentation. Since this -# will make the HTML file larger and loading of large files a bit slower, you -# can opt to disable this feature. -# The default value is: YES. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -SOURCE_TOOLTIPS = YES - -# If the USE_HTAGS tag is set to YES then the references to source code will -# point to the HTML generated by the htags(1) tool instead of doxygen built-in -# source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version -# 4.8.6 or higher. -# -# To use it do the following: -# - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file -# - Make sure the INPUT points to the root of the source tree -# - Run doxygen as normal -# -# Doxygen will invoke htags (and that will in turn invoke gtags), so these -# tools must be available from the command line (i.e. in the search path). -# -# The result: instead of the source browser generated by doxygen, the links to -# source code will now point to the output of htags. -# The default value is: NO. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a -# verbatim copy of the header file for each class for which an include is -# specified. Set to NO to disable this. -# See also: Section \class. -# The default value is: YES. - -VERBATIM_HEADERS = YES - -# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the -# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the -# cost of reduced performance. This can be particularly helpful with template -# rich C++ code for which doxygen's built-in parser lacks the necessary type -# information. -# Note: The availability of this option depends on whether or not doxygen was -# generated with the -Duse-libclang=ON option for CMake. -# The default value is: NO. - -CLANG_ASSISTED_PARSING = NO - -# If clang assisted parsing is enabled you can provide the compiler with command -# line options that you would normally use when invoking the compiler. Note that -# the include paths will already be set by doxygen for the files and directories -# specified with INPUT and INCLUDE_PATH. -# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. - -CLANG_OPTIONS = - -#--------------------------------------------------------------------------- -# Configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all -# compounds will be generated. Enable this if the project contains a lot of -# classes, structs, unions or interfaces. -# The default value is: YES. - -ALPHABETICAL_INDEX = NO - -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output -# The default value is: YES. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a -# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of -# it. -# The default directory is: html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each -# generated HTML page (for example: .htm, .php, .asp). -# The default value is: .html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a user-defined HTML header file for -# each generated HTML page. If the tag is left blank doxygen will generate a -# standard header. -# -# To get valid HTML the header file that includes any scripts and style sheets -# that doxygen needs, which is dependent on the configuration options used (e.g. -# the setting GENERATE_TREEVIEW). It is highly recommended to start with a -# default header using -# doxygen -w html new_header.html new_footer.html new_stylesheet.css -# YourConfigFile -# and then modify the file new_header.html. See also section "Doxygen usage" -# for information on how to generate the default header that doxygen normally -# uses. -# Note: The header is subject to change so you typically have to regenerate the -# default header when upgrading to a newer version of doxygen. For a description -# of the possible markers and block names see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each -# generated HTML page. If the tag is left blank doxygen will generate a standard -# footer. See HTML_HEADER for more information on how to generate a default -# footer and what special commands can be used inside the footer. See also -# section "Doxygen usage" for information on how to generate the default footer -# that doxygen normally uses. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style -# sheet that is used by each HTML page. It can be used to fine-tune the look of -# the HTML output. If left blank doxygen will generate a default style sheet. -# See also section "Doxygen usage" for information on how to generate the style -# sheet that doxygen normally uses. -# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as -# it is more robust and this tag (HTML_STYLESHEET) will in the future become -# obsolete. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_STYLESHEET = - -# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined -# cascading style sheets that are included after the standard style sheets -# created by doxygen. Using this option one can overrule certain style aspects. -# This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefore more robust against future updates. -# Doxygen will copy the style sheet files to the output directory. -# Note: The order of the extra style sheet files is of importance (e.g. the last -# style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_STYLESHEET = - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that the -# files will be copied as-is; there are no commands or markers available. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value -# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 -# purple, and 360 is red again. -# Minimum value: 0, maximum value: 359, default value: 220. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A -# value of 255 will produce the most vivid colors. -# Minimum value: 0, maximum value: 255, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the -# luminance component of the colors in the HTML output. Values below 100 -# gradually make the output lighter, whereas values above 100 make the output -# darker. The value divided by 100 is the actual gamma applied, so 80 represents -# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not -# change the gamma. -# Minimum value: 40, maximum value: 240, default value: 80. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_DYNAMIC_SECTIONS = NO - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries -# shown in the various tree structured indices initially; the user can expand -# and collapse entries dynamically later on. Doxygen will expand the tree to -# such a level that at most the specified number of entries are visible (unless -# a fully collapsed tree already exceeds this amount). So setting the number of -# entries 1 will produce a full collapsed tree by default. 0 is a special value -# representing an infinite number of entries and will result in a full expanded -# tree by default. -# Minimum value: 0, maximum value: 9999, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files will be -# generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_DOCSET = NO - -# This tag determines the name of the docset feed. A documentation feed provides -# an umbrella under which multiple documentation sets from a single provider -# (such as a company or product suite) can be grouped. -# The default value is: Doxygen generated docs. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# This tag specifies a string that should uniquely identify the documentation -# set bundle. This should be a reverse domain-name style string, e.g. -# com.mycompany.MyDocSet. Doxygen will append .docset to the name. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. -# The default value is: org.doxygen.Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. -# The default value is: Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three -# additional HTML index files: index.hhp, index.hhc, and index.hhk. The -# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. -# -# The HTML Help Workshop contains a compiler that can convert all HTML output -# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML -# files are now used as the Windows 98 help format, and will replace the old -# Windows help format (.hlp) on all Windows platforms in the future. Compressed -# HTML files also contain an index, a table of contents, and you can search for -# words in the documentation. The HTML workshop also contains a viewer for -# compressed HTML files. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_HTMLHELP = NO - -# The CHM_FILE tag can be used to specify the file name of the resulting .chm -# file. You can add a path in front of the file if the result should not be -# written to the html output directory. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_FILE = - -# The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler (hhc.exe). If non-empty, -# doxygen will try to run the HTML help compiler on the generated index.hhp. -# The file has to be specified with full path. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -HHC_LOCATION = - -# The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the master .chm file (NO). -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -GENERATE_CHI = NO - -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) -# and project file content. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_INDEX_ENCODING = - -# The BINARY_TOC flag controls whether a binary table of contents is generated -# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it -# enables the Previous and Next buttons. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members to -# the table of contents of the HTML help documentation and to the tree view. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that -# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help -# (.qch) of the generated HTML documentation. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify -# the file name of the resulting .qch file. The path specified is relative to -# the HTML output folder. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help -# Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt -# Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). -# The default value is: doc. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_VIRTUAL_FOLDER = doc - -# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom -# filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_SECT_FILTER_ATTRS = - -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be -# generated, together with the HTML files, they form an Eclipse help plugin. To -# install this plugin and make it available under the help contents menu in -# Eclipse, the contents of the directory containing the HTML and XML files needs -# to be copied into the plugins directory of eclipse. The name of the directory -# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. -# After copying Eclipse needs to be restarted before the help appears. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the Eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have this -# name. Each documentation set should have its own identifier. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# If you want full control over the layout of the generated HTML pages it might -# be necessary to disable the index and replace it with your own. The -# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top -# of each HTML page. A value of NO enables the index and the value YES disables -# it. Since the tabs in the index contain the same information as the navigation -# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. If the tag -# value is set to YES, a side panel will be generated containing a tree-like -# index structure (just like the one that is generated for HTML Help). For this -# to work a browser that supports JavaScript, DHTML, CSS and frames is required -# (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_TREEVIEW = NO - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that -# doxygen will group on one line in the generated HTML documentation. -# -# Note that a value of 0 will completely suppress the enum values from appearing -# in the overview section. -# Minimum value: 0, maximum value: 20, default value: 4. -# This tag requires that the tag GENERATE_HTML is set to YES. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used -# to set the initial width (in pixels) of the frame in which the tree is shown. -# Minimum value: 0, maximum value: 1500, default value: 250. -# This tag requires that the tag GENERATE_HTML is set to YES. - -TREEVIEW_WIDTH = 250 - -# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to -# external symbols imported via tag files in a separate window. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of LaTeX formulas included as images in -# the HTML documentation. When you change the font size after a successful -# doxygen run you need to manually remove any form_*.png images from the HTML -# output directory to force them to be regenerated. -# Minimum value: 8, maximum value: 50, default value: 10. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX -# installed or if you want to formulas look prettier in the HTML output. When -# enabled you may also need to install MathJax separately and configure the path -# to it using the MATHJAX_RELPATH option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -USE_MATHJAX = NO - -# When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. -# Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. -# The default value is: HTML-CSS. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_FORMAT = HTML-CSS - -# When MathJax is enabled you need to specify the location relative to the HTML -# output directory using the MATHJAX_RELPATH option. The destination directory -# should contain the MathJax.js script. For instance, if the mathjax directory -# is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax -# Content Delivery Network so you can quickly see the result without installing -# MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest - -# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax -# extension names that should be enabled during MathJax rendering. For example -# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_EXTENSIONS = - -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces -# of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an -# example see the documentation. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_CODEFILE = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for -# the HTML output. The underlying search engine uses javascript and DHTML and -# should work on any modern browser. Note that when using HTML help -# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) -# there is already a search function so this one should typically be disabled. -# For large projects the javascript based search engine can be slow, then -# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to -# search using the keyboard; to jump to the search box use + S -# (what the is depends on the OS and browser, but it is typically -# , /