pax_global_header00006660000000000000000000000064142521672510014517gustar00rootroot0000000000000052 comment=a1ba419a295e2925cce55c80794873a92a838d44 RHash-1.4.3/000077500000000000000000000000001425216725100125315ustar00rootroot00000000000000RHash-1.4.3/.github/000077500000000000000000000000001425216725100140715ustar00rootroot00000000000000RHash-1.4.3/.github/FUNDING.yml000066400000000000000000000000271425216725100157050ustar00rootroot00000000000000open_collective: rhash RHash-1.4.3/.gitignore000066400000000000000000000003271425216725100145230ustar00rootroot00000000000000/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 RHash-1.4.3/COPYING000066400000000000000000000013401425216725100135620ustar00rootroot00000000000000 BSD Zero Clause License Copyright (c) 2005, Aleksey Kravchenko Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. RHash-1.4.3/ChangeLog000066400000000000000000000613071425216725100143120ustar00rootroot00000000000000Tue 14 Jun 2022 Aleksey Kravchenko * === Version 1.4.3 === Tue 14 Jun 2022 Michael Hudson-Doyle * Support runtime loading of OpenSSL 3.0 Sun 12 Jun 2022 Aleksey Kravchenko * Bugfix: Show total speed in the update mode Sat 19 Feb 2022 Aleksey Kravchenko * LibRHash: add rhash_import() and rhash_export() functions Mon 03 Jan 2022 Aleksey Kravchenko * Bugfix: fix building of the LibRHash static library on Solaris * Honor hash file extension in --update mode Sun 19 Dec 2021 Aleksey Kravchenko * Support --ignore-missing option, to ignore missing files in --check mode Sun 12 Dec 2021 Aleksey Kravchenko * Support --brief option to show verification report without header and footer * Bugfix: hash options were sometimes ignored in the --check mode * Allow simultaneous usage of --update and --check options Fri 05 Nov 2021 Aleksey Kravchenko * Honor --lowercase option while --embed-crc is in action Mon 01 Nov 2021 And Sch * Improve ripemd160 performance Mon 01 Nov 2021 Aleksey Kravchenko * Add --bt-transmission option to create Transmission compatible torrent files Sun 26 Sep 2021 Aleksey Kravchenko * Bugfix: star character at the start of filepath must be ignored Wed 14 Jul 2021 Aleksey * === Version 1.4.2 === * print 'Nothing to verify' when verifying a hash file without a message digest Wed 14 Jul 2021 Zak Kemble * significantly improve file reading performance on Linux/Unix Sun 11 Jul 2021 Aleksey * Bugfix: fix verification of some hash files containing spaces in file paths * count unparsed lines of a hash file as errors * print line numbers of unparsed lines of a hash file Thu 07 Jan 2021 Aleksey * === Version 1.4.1 === Wed 06 Jan 2021 Aleksey * look for config file at $HOME/.config/rhash/rhashrc Mon 04 Jan 2021 Aleksey * supported --blake2s, --blake2b options for the BLAKE2 hash functions Sun 03 Jan 2021 Aleksey * Bugfix: fix computing of EDON-R 512 by big data chunks Thu 24 Dec 2020 Aleksey * support --no-detect-by-ext option * speed up verification by detecting hash type from file extension Sun 06 Dec 2020 Aleksey * Bugfix: correctly print long paths on Windows Sun 22 Nov 2020 Aleksey * Bugfix: print correct '%{mtime}' when --file-list is specified Sat 29 Aug 2020 Theodore Ts'o * Bugfix: only follow symbolic links when --follow is specified Wed 22 Jul 2020 Aleksey * Bugfix: fix buffer overflow in GOST12 Tue 14 Jul 2020 Aleksey * === Version 1.4.0 === Sat 11 Jul 2020 Aleksey * librhash: supported rhash_get_version() - get library version Mon 29 Jun 2020 Aleksey * Bugfix: fix broken output on Win 7 Sun 19 Apr 2020 Alexey Dokuchaev, Aleksey * Bugfix: fix broken 'configure --localedir=' option Fri 14 Feb 2020 Fabrice Fontaine * Bugfix: fix broken makefile install-so-link target Tue 07 Jan 2020 Aleksey * Bugfix: restore behavior of 'rhash -rc' to be the same as in v1.3.8 * Bugfix: fix a segfault and memory errors Sat 14 Dec 2019 Aleksey * === Version 1.3.9 === Sun 08 Dec 2019 Aleksey * add uk translations Thu 28 Nov 2019 Aleksey * change project license to BSD Zero Clause License Mon 18 Nov 2019 Aleksey * new printf-format modifier '%u' to print url-encoded filename, path or hash Fri 15 Nov 2019 Aleksey * Bugfix: btih in magnet links shall be hex-encoded Tue 12 Nov 2019 Aleksey * correctly align UTF8 file paths, while printing verification results * respect UTF8 BOM when updating or verifying a hash file Thu 17 Oct 2019 Aleksey * print a new-line after ed2k link, when --ed2k-link option is passed Mon 14 Oct 2019 Aleksey * exit on output errors with exit_code = 2 * change option --update= to update the specified file Sun 29 Sep 2019 Aleksey * make short option '-P' to be an alias for --percents Tue 02 Jul 2019 Aleksey * change %{mtime} format to 'YYYY-MM-DD hh:mm:ss' Wed 26 Jun 2019 Aleksey * Bugfix: --sysconfdir was ignored while searching for config on Linux Tue 25 Jun 2019 Aleksey * support verification of base64-formated hash sums * add formatting options: --hex, --base32, -b/--base64 Mon 17 Jun 2019 Aleksey * Bugfix: properly handle symlinks on the command line 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 RHash-1.4.3/INSTALL.md000066400000000000000000000026551425216725100141710ustar00rootroot00000000000000 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 ``` RHash-1.4.3/Makefile000066400000000000000000000303641425216725100141770ustar00rootroot00000000000000 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/blake2b.c librhash/blake2b.h \ librhash/blake2s.c librhash/blake2s.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/torrent.h librhash/torrent.c librhash/tth.c librhash/tth.h \ librhash/whirlpool.c librhash/whirlpool.h librhash/whirlpool_sbox.c \ librhash/test_lib.c librhash/test_lib.h librhash/ustd.h \ librhash/util.c 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 po/uk.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) 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_TARGZ = $(PACKAGE_NAME)-src.tar.gz ARCHIVE_TARGZ_CORE = $(RHASH_NAME)-core-$(VERSION)-src.tar.gz ARCHIVE_TARGZ_BINDINGS = $(RHASH_NAME)-bindings-$(VERSION)-src.tar.gz ARCHIVE_TARGZ_DEB = $(RHASH_NAME)_$(VERSION).orig.tar.gz ARCHIVE_XZ = $(PACKAGE_NAME)-src.tar.xz ARCHIVE_ZIP = $(PACKAGE_NAME)-$(WIN_SUFFIX).zip WIN_ZIP_DIR = RHash-$(VERSION)-$(WIN_SUFFIX) dist: tgz win-dist: zip zip: $(ARCHIVE_ZIP) dgz: check $(ARCHIVE_TARGZ_DEB) 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) /bin/sh tests/test_rhash.sh $(TEST_OPTIONS) ./$(RHASH_STATIC) test-shared: $(RHASH_SHARED) /bin/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 file.h \ hash_check.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 platform.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 file.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 file.h \ hash_check.h output.h parse_cmdline.h win_utils.h librhash/rhash.h $(CC) -c $(CFLAGS) $< -o $@ hash_update.o: hash_update.c calc_sums.h common_func.h file.h \ hash_check.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 calc_sums.h common_func.h file.h \ hash_check.h output.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.h \ file_mask.h find_file.h hash_print.h output.h rhash_main.h win_utils.h \ librhash/rhash.h $(CC) -c $(CFLAGS) $(CONFCFLAGS) $< -o $@ rhash_main.o: rhash_main.c rhash_main.h calc_sums.h common_func.h file.h \ hash_check.h file_mask.h find_file.h hash_print.h hash_update.h \ parse_cmdline.h output.h win_utils.h librhash/rhash.h $(CC) -c $(CFLAGS) $(LOCALECFLAGS) $< -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 -rman --version 2>/dev/null && (rman -fHTML -roff dist/rhash.1 | sed -e '/ $@) dist/rhash.1.txt: dist/rhash.1 -groff --version 2>/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)/ tgz-core: check +$(MAKE) copy-dist PACKAGE_NAME=$(PACKAGE_NAME)-core tar czf $(ARCHIVE_TARGZ_CORE) --owner=root --group=root $(PACKAGE_NAME)-core/ rm -rf $(PACKAGE_NAME)-core tgz-bindings: +cd bindings && $(MAKE) gzip ARCHIVE_GZIP=../$(ARCHIVE_TARGZ_BINDINGS) tgz: check clean-bindings +$(MAKE) copy-dist +cd bindings && $(MAKE) copy-dist COPYDIR=../$(PACKAGE_NAME)/bindings tar czf $(ARCHIVE_TARGZ) --owner=root:0 --group=root:0 $(PACKAGE_NAME)/ rm -rf $(PACKAGE_NAME) xz: check clean-bindings +$(MAKE) copy-dist +cd bindings && $(MAKE) copy-dist COPYDIR=../$(PACKAGE_NAME)/bindings tar cJf $(ARCHIVE_XZ) --owner=root:0 --group=root:0 $(PACKAGE_NAME)/ rm -rf $(PACKAGE_NAME) win-dir: $(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 $(ARCHIVE_ZIP): $(WIN_DIST_FILES) dist/rhash.1.win.html +$(MAKE) win-dir zip -9r $(ARCHIVE_ZIP) $(WIN_ZIP_DIR) rm -rf $(WIN_ZIP_DIR) $(ARCHIVE_TARGZ_DEB) : $(ALL_FILES) +$(MAKE) tgz mv -f $(ARCHIVE_TARGZ) $(ARCHIVE_TARGZ_DEB) # rpm packaging $(SPECFILE): $(SPECFILE).in config.mak sed -e 's/@VERSION@/$(VERSION)/' $(SPECFILE).in > $(SPECFILE) rpm: tgz -for i in $(RPMDIRS); do mkdir -p $(RPMTOP)/$$i; done cp -f $(ARCHIVE_TARGZ) $(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~ po/compile-gmo.tag 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 po/compile-gmo.tag: $(I18N_FILES) for f in $(I18N_FILES); do \ g=`basename $$f .po`; \ msgfmt -o po/$$g.gmo $$f; \ done touch $@ compile-gmo: po/compile-gmo.tag 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 \ dgz dist tgz tgz-bindings tgz-core rpm win-dist win-dir xz zip RHash-1.4.3/README.md000066400000000000000000000033501425216725100140110ustar00rootroot00000000000000# RHash RHash (Recursive Hasher) is a console utility for calculation and verification of magnet links and various message digests, 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. Message digests 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 message digests of files missing in the hash file). * Calculates several message digests 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. ## License The code is distributed under [BSD Zero Clause License](COPYING). [INSTALL.md]: INSTALL.md [The LibRHash Library]: docs/LIBRHASH.md [ChangeLog]: ChangeLog RHash-1.4.3/bindings/000077500000000000000000000000001425216725100143265ustar00rootroot00000000000000RHash-1.4.3/bindings/COPYING000066400000000000000000000013341425216725100153620ustar00rootroot00000000000000 BSD Zero Clause License Copyright (c) 2011, Aleksey Kravchenko and Sergey Basalaev Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. RHash-1.4.3/bindings/ChangeLog000066400000000000000000000013661425216725100161060ustar00rootroot00000000000000Fri 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 RHash-1.4.3/bindings/Makefile000066400000000000000000000073041425216725100157720ustar00rootroot00000000000000VERSION := $(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 ?= python3 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: cd python && $(PYTHON) -m build 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: cd python && PYTHONPATH=. $(PYTHON) tests/rhash_test.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 | uniq` for f in `sed 's/ .*//' perl/MANIFEST`; do cp perl/$$f $(PERL_PKG)/$$f; done cp ../docs/CONTRIBUTING.md ../COPYING $(PERL_PKG)/ cp ../librhash/*.[hc] ../version.h $(PERL_PKG)/librhash/ ( echo CONTRIBUTING.md; echo COPYING ) >> $(PERL_PKG)/MANIFEST 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 -rf python/dist/ python/rhash_Rhash.egg-info/ python/tests/__pycache__/ RHash-1.4.3/bindings/java/000077500000000000000000000000001425216725100152475ustar00rootroot00000000000000RHash-1.4.3/bindings/java/.gitignore000066400000000000000000000000361425216725100172360ustar00rootroot00000000000000classes/* dist/* *.so *.class RHash-1.4.3/bindings/java/Makefile000066400000000000000000000060201425216725100167050ustar00rootroot00000000000000#!/usr/bin/make -f # This file is a part of Java Bindings for Librhash # # Copyright (c) 2011, Sergey Basalaev # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. 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 RHash-1.4.3/bindings/java/native/000077500000000000000000000000001425216725100165355ustar00rootroot00000000000000RHash-1.4.3/bindings/java/native/Makefile000066400000000000000000000032151425216725100201760ustar00rootroot00000000000000#!/usr/bin/make -f # This file is a part of Java Bindings for Librhash # # Copyright (c) 2011, Sergey Basalaev # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. CC ?= gcc JAVAC ?= javac CFLAGS ?= -g -O2 LDFLAGS ?= LIBRHASH_INC ?= LIBRHASH_LD ?= ALLLDFLAGS = $(LDFLAGS) -lrhash $(LIBRHASH_LD) ALLCFLAGS = $(CFLAGS) $(LIBRHASH_INC) -fPIC #Platform dependent JAVAC_PATH = $(shell readlink -f $(shell command -v $(JAVAC))) JDK_HOME ?=$(realpath $(dir $(JAVAC_PATH))/..) JNI_CFLAGS1 = $(shell test -d "$(JDK_HOME)/include" && echo -I$(JDK_HOME)/include) JNI_CFLAGS2 = $(shell test -d "$(JDK_HOME)/include/linux" && echo -I$(JDK_HOME)/include/linux) JNI_CFLAGS ?= $(JNI_CFLAGS1) $(JNI_CFLAGS2) 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) RHash-1.4.3/bindings/java/native/bindings.c000066400000000000000000000145411425216725100205030ustar00rootroot00000000000000/* * This file is a part of Java Bindings for Librhash * * Copyright (c) 2011, Sergey Basalaev * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #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)); } RHash-1.4.3/bindings/java/native/bindings.h000066400000000000000000000064621425216725100205130ustar00rootroot00000000000000/* 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 RHash-1.4.3/bindings/java/native/digest.c000066400000000000000000000025751425216725100201710ustar00rootroot00000000000000/* * This file is a part of Java Bindings for Librhash * * Copyright (c) 2011, Sergey Basalaev * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #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); } RHash-1.4.3/bindings/java/native/digest.h000066400000000000000000000026741425216725100201760ustar00rootroot00000000000000/* * This file is a part of Java Bindings for Librhash * * Copyright (c) 2011, Sergey Basalaev * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* 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 */ RHash-1.4.3/bindings/java/src/000077500000000000000000000000001425216725100160365ustar00rootroot00000000000000RHash-1.4.3/bindings/java/src/org/000077500000000000000000000000001425216725100166255ustar00rootroot00000000000000RHash-1.4.3/bindings/java/src/org/sf/000077500000000000000000000000001425216725100172355ustar00rootroot00000000000000RHash-1.4.3/bindings/java/src/org/sf/rhash/000077500000000000000000000000001425216725100203425ustar00rootroot00000000000000RHash-1.4.3/bindings/java/src/org/sf/rhash/Bindings.java000066400000000000000000000104131425216725100227410ustar00rootroot00000000000000/* * This file is a part of Java Bindings for Librhash * * Copyright (c) 2011, Sergey Basalaev * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ 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(); } } RHash-1.4.3/bindings/java/src/org/sf/rhash/Digest.java000066400000000000000000000077421425216725100224360ustar00rootroot00000000000000/* * This file is a part of Java Bindings for Librhash * * Copyright (c) 2011, Sergey Basalaev * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ 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); } } RHash-1.4.3/bindings/java/src/org/sf/rhash/HashType.java000066400000000000000000000066061425216725100227420ustar00rootroot00000000000000/* * This file is a part of Java Bindings for Librhash * * Copyright (c) 2011, Sergey Basalaev * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ package org.sf.rhash; /** * Type of hashing algorithm. Supported algorithms are CRC32, CRC32C, * MD4, MD5, SHA1/SHA2/SHA3, Tiger, DC++ TTH, BitTorrent BTIH, AICH, * EDonkey 2000 hash, GOST R 34.11-94, GOST R 34.11-2012, RIPEMD-160, * HAS-160, BLAKE2s/BLAKE2b, 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), /** BLAKE2s hash. */ BLAKE2S(1 << 29), /** BLAKE2b hash. */ BLAKE2B(1 << 30); /** 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() { return Bindings.rhash_get_digest_size(hashId); } } RHash-1.4.3/bindings/java/src/org/sf/rhash/RHash.java000066400000000000000000000341511425216725100222160ustar00rootroot00000000000000/* * This file is a part of Java Bindings for Librhash * * Copyright (c) 2011, Sergey Basalaev * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ 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 using specified hash functions. * * @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 using specified hash functions. * * @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 message digests 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 filename * and message digests for the specified hash functions. * Message digests only for computed hash functions are included into the link. * * @param filename file name to include into the magnet link, can 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 that includes filename * and all computed message digests. * * @param filename file name to include into the magnet link, can 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); } } RHash-1.4.3/bindings/java/src/org/sf/rhash/package-info.java000066400000000000000000000053001425216725100235270ustar00rootroot00000000000000/* * This file is a part of Java Bindings for LibRHash * * Copyright (c) 2011, Sergey Basalaev * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /** * Java bindings for LibRHash. * LibRHash is a library for computing message digests and magnet links * for various hash functions. 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; RHash-1.4.3/bindings/java/test/000077500000000000000000000000001425216725100162265ustar00rootroot00000000000000RHash-1.4.3/bindings/java/test/RHashTest.java000066400000000000000000000113651425216725100207440ustar00rootroot00000000000000import 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()); assertEquals("4a0d129873403037c2cd9b9048203687f6233fb6738956e0349bd4320fec3e90", r.getDigest(BLAKE2S).toString()); assertEquals("333fcb4ee1aa7c115355ec66ceac917c8bfd815bf7587d325aec1864edd24e34d5abe2c6b1b5ee3face62fed78dbef802f2a85cb91d455a8f5249d330853cb3c", r.getDigest(BLAKE2B).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); } } RHash-1.4.3/bindings/mono/000077500000000000000000000000001425216725100152765ustar00rootroot00000000000000RHash-1.4.3/bindings/mono/.gitignore000066400000000000000000000001211425216725100172600ustar00rootroot00000000000000bin RHash.dll RHash.dll.mdb RHash.pidb RHash.tree RHash.userprefs RHash.zip html RHash-1.4.3/bindings/mono/AssemblyInfo.cs000066400000000000000000000034221425216725100202210ustar00rootroot00000000000000/* * This file is a part of Mono Bindings for Librhash * * Copyright (c) 2011, Sergey Basalaev * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ 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")] RHash-1.4.3/bindings/mono/Bindings.cs000066400000000000000000000036431425216725100173700ustar00rootroot00000000000000/* * This file is a part of Mono Bindings for Librhash * * Copyright (c) 2011, Sergey Basalaev * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ 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); } } RHash-1.4.3/bindings/mono/HashType.cs000066400000000000000000000045171425216725100173610ustar00rootroot00000000000000/* * This file is a part of Java Bindings for Librhash * * Copyright (c) 2011, Sergey Basalaev * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ 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, /* BLAKE2s hash. */ BLAKE2S = 1 << 29, /* BLAKE2b hash. */ BLAKE2B = 1 << 30 } } RHash-1.4.3/bindings/mono/Hasher.cs000066400000000000000000000123251425216725100170420ustar00rootroot00000000000000/* * This file is a part of Java Bindings for Librhash * * Copyright (c) 2011, Sergey Basalaev * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ using System; using System.IO; using System.Text; namespace RHash { public sealed class Hasher { private const int DEFAULT = 0x0; /* output binary message digest */ private const int RAW = 0x1; /* print message digest as a hexadecimal string */ private const int HEX = 0x2; /* print message digest as a base32-encoded string */ private const int BASE32 = 0x3; /* print message digest as a base64-encoded string */ private const int BASE64 = 0x4; /* Print message digest as an uppercase string. */ private const int UPPERCASE = 0x8; /* Reverse bytes order for hexadecimal message digest. */ 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("Hash functions bit-mask must be non-zero", "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 has not computed message digest for id: "+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 has not computed message digest for id: "+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 has not computed message digest for id: "+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 has not computed message digest for id: "+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 has not computed message digest for id: "+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); } } } RHash-1.4.3/bindings/mono/Makefile000066400000000000000000000025471425216725100167460ustar00rootroot00000000000000#!/usr/bin/make -f # This file is a part of Mono Bindings for Librhash # # Copyright (c) 2011, Sergey Basalaev # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. 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 RHash-1.4.3/bindings/mono/RHash.csproj000066400000000000000000000034141425216725100175270ustar00rootroot00000000000000 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 RHash-1.4.3/bindings/mono/RHash.dll.config000066400000000000000000000002651425216725100202470ustar00rootroot00000000000000 RHash-1.4.3/bindings/mono/RHash.sln000066400000000000000000000022271425216725100170240ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RHash", "RHash.csproj", "{2EC1635A-308E-46E4-B016-017C2AF3CDD9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2EC1635A-308E-46E4-B016-017C2AF3CDD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2EC1635A-308E-46E4-B016-017C2AF3CDD9}.Debug|Any CPU.Build.0 = Debug|Any CPU {2EC1635A-308E-46E4-B016-017C2AF3CDD9}.Release|Any CPU.ActiveCfg = Release|Any CPU {2EC1635A-308E-46E4-B016-017C2AF3CDD9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = RHash.csproj Policies = $0 $0.DotNetNamingPolicy = $1 $1.DirectoryNamespaceAssociation = None $1.ResourceNamePolicy = FileFormatDefault $0.StandardHeader = $2 $2.Text = $2.IncludeInNewFiles = True description = .NET/Mono bindings for librhash version = 1.0 EndGlobalSection EndGlobal RHash-1.4.3/bindings/mono/RHash.snk000066400000000000000000000011241425216725100170160ustar00rootroot00000000000000$RSA2/o#&٢*slҺ@Ȉ_Υ|N=:QEʧ|PD`*/vlMaQOFDR%52Kְś9Hn3T! G_ RD]#*8YT}`o 3S5FC\l髪j@*#ūn,3>~?#iE%yr dwn~ttj7{E ;>4f|U>;ve}9 Xb";oT{*edk&z++87֍N- Z6^cݥC[OC8g: 4:1> RHash 1.0.1.1 System.Enum Type of hashing algorithm. Supported algorithms are CRC32, CRC32C, MD4, MD5, SHA1/SHA2/SHA3, AICH, ED2K, Tiger, DC++ TTH, GOST R 34.11-94, GOST R 34.11-2012, BitTorrent BTIH, RIPEMD-160, HAS-160, BLAKE2s/BLAKE2b, 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 BLAKE2b hash. Field 1.0.1.1 RHash.HashType BLAKE2s hash. 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 CRC32C 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-2012, 256 bit. Field 1.0.1.1 RHash.HashType GOST R 34.11-2012, 512 bit. 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.4.3/bindings/mono/doc/RHash/Hasher.xml000066400000000000000000000454201425216725100210110ustar00rootroot00000000000000 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 message digests. Processes any buffered data and finishes computation of message digests. Method 1.0.1.1 System.String File to compute message digest for. Type of message digest 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 message digest for. Type of message digest 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 message digests 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 message digests. Magnet link. Only message digests 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 link for specified file with given message digests. Magnet link. Returned magnet link includes file name and all computed message digests. 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 message digests are lost and the 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 message digest 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 message digest 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 message digest 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 message digest 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 message digest 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 message digest 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 the array to process. 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.4.3/bindings/mono/doc/index.xml000066400000000000000000000037531425216725100177040ustar00rootroot00000000000000 [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 RHash-1.4.3/bindings/mono/doc/ns-RHash.xml000066400000000000000000000024101425216725100202050ustar00rootroot00000000000000 .NET/Mono bindings to librhash. Librhash is a library for computing hash functions. It 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 the 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. RHash-1.4.3/bindings/mono/test/000077500000000000000000000000001425216725100162555ustar00rootroot00000000000000RHash-1.4.3/bindings/mono/test/12345.txt000066400000000000000000000000061425216725100174700ustar00rootroot0000000000000012345 RHash-1.4.3/bindings/mono/test/Makefile000066400000000000000000000016621425216725100177220ustar00rootroot00000000000000#!/usr/bin/make -f # This file is a part of Mono Bindings for Librhash # # Copyright (c) 2011, Sergey Basalaev # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. 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 RHash-1.4.3/bindings/mono/test/Test.cs000066400000000000000000000137571425216725100175400ustar00rootroot00000000000000/* * This file is a part of Mono Bindings for Librhash * * Copyright (c) 2011, Sergey Basalaev * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ 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"); hashes.Add(HashType.BLAKE2S, "709dcba6d2db68cdc6d4d3674cf8382755b6f6d673c68ad2d8132d5eac0a54cc"); hashes.Add(HashType.BLAKE2B, "bfc877bc2a258facff21279383039ca6c5e4f98ee78b5cafa209bd3598633443908f9e533676cb38952cd8132241f19735b4929bc249937ec79349132dceac5a"); 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; } } RHash-1.4.3/bindings/perl/000077500000000000000000000000001425216725100152705ustar00rootroot00000000000000RHash-1.4.3/bindings/perl/.gitignore000066400000000000000000000000641425216725100172600ustar00rootroot00000000000000blib/ Makefile Rhash.c Rhash.bs pm_to_blib MYMETA.* RHash-1.4.3/bindings/perl/MANIFEST000066400000000000000000000004611425216725100164220ustar00rootroot00000000000000Makefile.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) RHash-1.4.3/bindings/perl/META.json000066400000000000000000000022341425216725100167120ustar00rootroot00000000000000{ "abstract" : "Library for computing message digests and magnet links", "author" : [ "Aleksey Kravchenko" ], "dynamic_config" : 0, "generated_by" : "ExtUtils::MakeMaker version 6.84, CPAN::Meta::Converter version 2.133380", "license" : [ "open_source" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Crypt-Rhash", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : {} } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/rhash/RHash/issues" }, "homepage" : "http://rhash.sf.net/", "license" : [ "https://github.com/rhash/RHash/blob/master/COPYING" ], "repository" : { "url" : "https://github.com/rhash/RHash" } }, "version" : "1.00" } RHash-1.4.3/bindings/perl/META.yml000066400000000000000000000012701425216725100165410ustar00rootroot00000000000000--- abstract: 'Library for computing message digests and magnet links' author: - 'Aleksey Kravchenko' build_requires: ExtUtils::MakeMaker: 0 configure_requires: ExtUtils::MakeMaker: 0 dynamic_config: 0 generated_by: 'ExtUtils::MakeMaker version 6.84, CPAN::Meta::Converter version 2.133380' license: open_source meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Crypt-Rhash no_index: directory: - t - inc requires: {} resources: bugtracker: https://github.com/rhash/RHash/issues homepage: http://rhash.sf.net/ license: https://github.com/rhash/RHash/blob/master/COPYING repository: https://github.com/rhash/RHash version: 1.00 RHash-1.4.3/bindings/perl/Makefile.PL000066400000000000000000000072701425216725100172500ustar00rootroot00000000000000use strict; use warnings; use Cwd; use ExtUtils::MakeMaker; use File::Copy; my $libs = ''; my $def = ''; 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; } sub read_librhash_version($) { my $path = $_[0] . "/version.h"; open my $fh, "<", $path or die "could not open $path: $!"; chomp(my @lines = <$fh>); close $fh; foreach (@lines) { if (/^#define VERSION "(\d+)\.(\d+)\.(\d+)"/) { return sprintf("0x%02x%02x%02x%02x", $1, $2, $3, 0); } } return '0'; } # 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 $librhash_version = read_librhash_version($rh_builtin_dir); my @c_files = copy_c_files($rh_builtin_dir); $clean = join(' ', @c_files); $obj = join(' ', map { s/\.c$/\$(OBJ_EXT)/; $_ } @c_files) . ' '; $def = '-DRHASH_XVERSION=' . $librhash_version; } # 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 message digests and magnet links', AUTHOR => 'Aleksey Kravchenko', VERSION_FROM => 'Rhash.pm', # finds $VERSION OPTIONAL( '6.31', LICENSE => 'open_source', ), 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 => $def, INC => $inc, OBJECT => $obj . 'Rhash$(OBJ_EXT)', clean => { FILES => $clean, }, ); RHash-1.4.3/bindings/perl/README000066400000000000000000000023671425216725100161600ustar00rootroot00000000000000 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 ------- BSD Zero Clause License Copyright (c) 2011, Aleksey Kravchenko Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. RHash-1.4.3/bindings/perl/Rhash.pm000066400000000000000000000324131425216725100166760ustar00rootroot00000000000000package 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_BLAKE2S RHASH_BLAKE2B RHASH_EDONR256 RHASH_EDONR512 RHASH_HAS160 RHASH_SNEFRU128 RHASH_SNEFRU256 RHASH_ALL)] ); Exporter::export_tags( ); Exporter::export_ok_tags( qw(Functions Constants) ); our $VERSION = '1.00'; 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_BLAKE2S => 0x20000000; use constant RHASH_BLAKE2B => 0x40000000; use constant RHASH_ALL => 0x7FFFFFFF; ############################################################################## # Rhash class methods # Rhash object constructor sub new($$@) { my $hash_id = 0; shift; scalar(@_) > 0 or die "hash_id not specified"; for my $id (@_) { $hash_id |= scalar($id); if(!scalar($id) || (scalar($id) & RHASH_ALL) != $id) { die "bad hash_id = " . scalar($id); } } my $context = rhash_init($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}); } ############################################################################## # Message digest 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 a binary message digest 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 message digests and magnet links =head1 SYNOPSIS use Crypt::Rhash; my $msg = "a message text"; print "MD5 = " . Crypt::Rhash::msg(RHASH_MD5, $msg) . "\n"; or use Crypt::Rhash; my $filepath = "/tmp/file.txt"; # Calculate two hash functions simultaneously my $r = Crypt::Rhash->new(RHASH_SHA1, RHASH_SHA512); $res = $r->update_file($filepath); defined($res) or die "failed to read $filepath: $!"; print "SHA1 = " . $r->hash(RHASH_SHA1) . "\n"; print "SHA512 = " . $r->hash(RHASH_SHA512) . "\n"; =head1 DESCRIPTION Crypt::Rhash module is an object-oriented interface to LibRHash library, allowing simultaneous calculation of several hash functions for a file or a text message. Calculated message digest can be obtained in hexadecimal, BASE32, BASE64, raw binary format or as a magnet link. =head1 SUPPORTED ALGORITHMS The module supports the following hash functions: 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, BLAKE2s/BLAKE2b, EDON-R 256/512, Whirlpool and Snefru-128/256. =head1 CONSTRUCTOR Creates and returns new Crypt::Rhash object. my $r = Crypt::Rhash->new($hash_id1, $hash_id2, ...); my $p = new Crypt::Rhash($hash_id1, ...); # alternative way to call the constructor Constructor accepts the following constants as arguments: 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, RHASH_BLAKE2S, RHASH_BLAKE2B, RHASH_ALL The RHASH_ALL bit mask is bitwise union of all listed above bit-flags. An object created as Crypt::Rhash->new(RHASH_ALL) calculates all supported hash functions for the same data. =head1 COMPUTING MESSAGE DIGESTS =over =item $rhash->update( $msg ) Calculates message digests 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 message digest 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 process. If $start is undefined, then the file is read from the start. If $size is undefined, then the file is read till the end. 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 the 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 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 message digest 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 MESSAGE DIGEST Computed message digest 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 message digest 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 message digest for the algorithm contained in $rhash with the lowest identifier. =item $rhash->hash_hex( $hash_id ) Returns the specified message digest 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 message digest in the hexadecimal format with reversed order of bytes. Some programs prefer to output the GOST R 34.11-94 message digest in this format. =item $rhash->hash_base32( $hash_id ) Returns the specified message digest in the base32 format. =item $rhash->hash_base64( $hash_id ) Returns the specified message digest in the base64 format. =item $rhash->magnet_link( $filename, $hash_mask ) Returns the magnet link containing the computed message digests, 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 message digests to put into the link. =back =head1 STATIC METHODS =over =item Crypt::Rhash::count() Returns the number of supported hash functions =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 message digest of the specified hash function. =item Crypt::Rhash::get_hash_length($hash_id) Returns the length of a message digest in default output format for the specified hash function. =item Crypt::Rhash::get_name($hash_id) Returns the name of the specified hash function. =item Crypt::Rhash::librhash_version_string() Returns the version of LibRHash as string. =back =head1 ALTERNATIVE WAY TO COMPUTE A MESSAGE DIGEST =over =item Crypt::Rhash::msg($hash_id, $message) Computes and returns a single message digest (in its default format) of the $message by the selected hash function. use Crypt::Rhash; print "SHA1( 'abc' ) = " . Crypt::Rhash::msg(RHASH_SHA1, "abc") . "\n"; =back =head1 LICENSE BSD Zero Clause License Copyright (c) 2011, Aleksey Kravchenko Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. =cut RHash-1.4.3/bindings/perl/Rhash.xs000066400000000000000000000160131425216725100167120ustar00rootroot00000000000000#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 struct rhash_context * rhash_init(hash_id) unsigned hash_id PROTOTYPE: $ int rhash_update(ctx, message) struct 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) struct rhash_context * ctx PROTOTYPE: $ CODE: RETVAL = rhash_final(ctx, 0); OUTPUT: RETVAL void rhash_reset(ctx) struct rhash_context * ctx PROTOTYPE: $ void rhash_free(ctx) struct rhash_context * ctx PROTOTYPE: $ SV * rhash_print(ctx, hash_id, flags = 0) struct 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) struct 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) struct rhash_context * ctx PROTOTYPE: $ CODE: RETVAL = ctx->hash_id; OUTPUT: RETVAL ulonglong rhash_get_hashed_length(ctx) struct rhash_context * ctx PROTOTYPE: $ CODE: RETVAL = ctx->msg_size; OUTPUT: RETVAL ############################################################################## # Information functions int count() CODE: RETVAL = rhash_count(); OUTPUT: RETVAL SV * librhash_version_string() PREINIT: unsigned version; CODE: version = rhash_get_version(); RETVAL = allocate_string_buffer(20); sprintf(SvPVX(RETVAL), "%u.%u.%u", (version >> 24) & 255, (version >> 16) & 255, (version >> 8) & 255); SvCUR_set(RETVAL, strlen(SvPVX(RETVAL))); OUTPUT: RETVAL int librhash_version() CODE: RETVAL = rhash_get_version(); 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) struct 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) struct rhash_context * ctx unsigned piece_length PROTOTYPE: $$ CODE: rhash_torrent_set_piece_length(ctx, piece_length); void rhash_bt_set_private(ctx) struct rhash_context * ctx PROTOTYPE: $ CODE: rhash_torrent_set_options(ctx, RHASH_TORRENT_OPT_PRIVATE); SV * rhash_bt_get_torrent_text(ctx) struct 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 RHash-1.4.3/bindings/perl/t/000077500000000000000000000000001425216725100155335ustar00rootroot00000000000000RHash-1.4.3/bindings/perl/t/1test_hash_calculation.t000066400000000000000000000043661425216725100223520ustar00rootroot00000000000000use 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__ RHash-1.4.3/bindings/perl/t/2test_static_functions.t000066400000000000000000000014261425216725100224230ustar00rootroot00000000000000use Test::More tests => 12; 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"); like(&Crypt::Rhash::librhash_version_string(), qr/^\d+\.\d+\.\d+$/); # 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"); RHash-1.4.3/bindings/perl/t/3test_all_hash_functions.t000066400000000000000000000061621425216725100227120ustar00rootroot00000000000000use Test::More tests => 31; 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"); is( $r->hash(RHASH_BLAKE2S), "4a0d129873403037c2cd9b9048203687f6233fb6738956e0349bd4320fec3e90"); is( $r->hash(RHASH_BLAKE2B), "333fcb4ee1aa7c115355ec66ceac917c8bfd815bf7587d325aec1864edd24e34d5abe2c6b1b5ee3face62fed78dbef802f2a85cb91d455a8f5249d330853cb3c"); __END__ RHash-1.4.3/bindings/perl/typemap000066400000000000000000000001421425216725100166670ustar00rootroot00000000000000struct rhash_context * T_PTROBJ rhash_uptr_t T_NV ulonglong T_NV const char * T_PV RHash-1.4.3/bindings/php/000077500000000000000000000000001425216725100151155ustar00rootroot00000000000000RHash-1.4.3/bindings/php/config.m4000066400000000000000000000024101425216725100166210ustar00rootroot00000000000000dnl 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 RHash-1.4.3/bindings/php/php_compatibility.h000066400000000000000000000035071425216725100210130ustar00rootroot00000000000000/* * This file is a part of PHP Bindings for Librhash * * Copyright (c) 2012, Aleksey Kravchenko * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #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 */ RHash-1.4.3/bindings/php/php_rhash.c000066400000000000000000000471621425216725100172470ustar00rootroot00000000000000/* * This file is a part of PHP Bindings for Librhash * * Copyright (c) 2012, Aleksey Kravchenko * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #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_BLAKE2S); REGISTER_RHASH_CONSTANT(RHASH_BLAKE2B); 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 message digests 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 message digests 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 message digests 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); } /* }}} */ RHash-1.4.3/bindings/php/php_rhash.h000066400000000000000000000030721425216725100172440ustar00rootroot00000000000000/* * This file is a part of PHP Bindings for Librhash * * Copyright (c) 2012, Aleksey Kravchenko * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #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 */ RHash-1.4.3/bindings/php/tests/000077500000000000000000000000001425216725100162575ustar00rootroot00000000000000RHash-1.4.3/bindings/php/tests/001.phpt000066400000000000000000000006131425216725100174540ustar00rootroot00000000000000--TEST-- test RHash global functions --FILE-- = 31) . "\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 RHash-1.4.3/bindings/php/tests/002.phpt000066400000000000000000000072771425216725100174720ustar00rootroot00000000000000--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_BLAKE2S) . "\n"; echo $r->hash(RHASH_BLAKE2B) . "\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 4a0d129873403037c2cd9b9048203687f6233fb6738956e0349bd4320fec3e90 333fcb4ee1aa7c115355ec66ceac917c8bfd815bf7587d325aec1864edd24e34d5abe2c6b1b5ee3face62fed78dbef802f2a85cb91d455a8f5249d330853cb3c 943aa9225a2cf154ec2e4dd81237720ba538ca8df2fd83c0b893c5d265f353a0 b59ec44f7beef8a04ceed38a973d77c65e22e9458d5f67b497948da34986c093b5efc5483fbee55f2f740fcad31f18d80db44bb6b8843e7fd599188e7c07233b 7]ܹ7vg 16614b1f68c5c25eaf6136286c9c12932f4f73e87e90a273 q336in72uwt7zyk5dxolt2xk5i3xmz5y hvfkN/qlp/zhXR3cuerq6jd2Z7g= magnet:?xl=1&dn=file.txt&xt=urn:aich:q336in72uwt7zyk5dxolt2xk5i3xmz5y&xt=urn:crc32:e8b7be43 Done RHash-1.4.3/bindings/php/tests/003.phpt000066400000000000000000000017121425216725100174570ustar00rootroot00000000000000--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 RHash-1.4.3/bindings/python/000077500000000000000000000000001425216725100156475ustar00rootroot00000000000000RHash-1.4.3/bindings/python/.gitignore000066400000000000000000000000351425216725100176350ustar00rootroot00000000000000__pycache__ *.egg-info *.pyc RHash-1.4.3/bindings/python/LICENSE000066400000000000000000000014331425216725100166550ustar00rootroot00000000000000 BSD Zero Clause License Copyright (c) 2011, Sergey Basalaev , Aleksey Kravchenko Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. RHash-1.4.3/bindings/python/README.md000066400000000000000000000046101425216725100171270ustar00rootroot00000000000000# RHash RHash is a Python library for computing various message digests, including CRC32, CRC32C, MD4, MD5, SHA1, SHA2, SHA3, AICH, ED2K, DC++ TTH, Tiger, BitTorrent BTIH, GOST R 34.11-94, GOST R 34.11-2012, RIPEMD-160, HAS-160, EDON-R, and Whirlpool. ## Installation RHash requires LibRHash library. The LibRHash sources or Windows binaries can be downloaded from: * http://rhash.sf.net/ Linux and BSD users should install LibRHash from the official repository. To build LibRHash from sources use commands $ ./configure $ make lib-shared install-lib-shared In order to be loaded by RHash Python module, the LibRHash library should be placed in the appropriate directory or you can change required environment variable. To install the RHash Python module use the package manager [pip] $ pip install rhash-Rhash You can also build the module from source $ python setup.py build ## Usage Hashing a file or a text message can be done using RHash hi-level interface >>> import rhash >>> rhash.hash_file("input-file.txt", rhash.SHA3_256) 'a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a' >>> rhash.make_magnet("input-file.txt", rhash.CRC32, rhash.TTH) 'magnet:?xl=0&dn=input-file.txt&xt=urn:crc32:00000000&xt=urn:tree:tiger:lwpnacqdbzryxw3vhjvcj64qbznghohhhzwclnq' >>> message_digest = rhash.hash_msg("abc", rhash.SHA1) >>> print("SHA1 (\"abc\") = {}".format(message_digest)) SHA1 ("abc") = a9993e364706816aba3e25717850c26c9cd0d89d The Low-level interface allows to calculate several message digests at once and output them in different formats >>> import rhash >>> h = rhash.RHash(rhash.MD5, rhash.SHA1, rhash.BLAKE2S) >>> h.update("abc") >>> h.finish() >>> h.hex(rhash.MD5) '900150983cd24fb0d6963f7d28e17f72' >>> h.HEX(rhash.MD5) '900150983CD24FB0D6963F7D28E17F72' >>> h.base32(rhash.SHA1) 'vgmt4nsha2awvor6evyxqugcnsonbwe5' >>> h.base64(rhash.BLAKE2S) 'UIxejDJ8FOLhpyujTutFLzdFiyCe1jopTZmbTIZnWYI=' ## Contribution To contribute to the project, please read the [Contribution guidelines] document. ## License The code is distributed under the [BSD Zero Clause License](LICENSE). [pip]: https://pip.pypa.io/en/stable/ [Contribution guidelines]: https://github.com/rhash/RHash/blob/master/docs/CONTRIBUTING.md RHash-1.4.3/bindings/python/pyproject.toml000066400000000000000000000001501425216725100205570ustar00rootroot00000000000000[build-system] requires = [ "setuptools>=42", "wheel" ] build-backend = "setuptools.build_meta" RHash-1.4.3/bindings/python/rhash/000077500000000000000000000000001425216725100167545ustar00rootroot00000000000000RHash-1.4.3/bindings/python/rhash/__init__.py000066400000000000000000000041101425216725100210610ustar00rootroot00000000000000# Copyright (c) 2021, Aleksey Kravchenko # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. """Python rhash module.""" from .rhash import ( ALL, CRC32, CRC32C, MD4, MD5, SHA1, TIGER, TTH, BTIH, ED2K, AICH, WHIRLPOOL, RIPEMD160, GOST94, GOST94_CRYPTOPRO, GOST12_256, GOST12_512, HAS160, SHA2_224, SHA2_256, SHA2_384, SHA2_512, EDONR256, EDONR512, SHA3_224, SHA3_256, SHA3_384, SHA3_512, BLAKE2S, BLAKE2B, SNEFRU128, SNEFRU256, RHash, hash_msg, hash_file, make_magnet, get_librhash_version, ) # Import deprecated constants and functions from .rhash import SHA224, SHA256, SHA384, SHA512 from .rhash import hash_for_msg, hash_for_file, magnet_for_file __all__ = [ "ALL", "CRC32", "CRC32C", "MD4", "MD5", "SHA1", "TIGER", "TTH", "BTIH", "ED2K", "AICH", "WHIRLPOOL", "RIPEMD160", "GOST94", "GOST94_CRYPTOPRO", "GOST12_256", "GOST12_512", "HAS160", "SHA2_224", "SHA2_256", "SHA2_384", "SHA2_512", "EDONR256", "EDONR512", "SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512", "BLAKE2S", "BLAKE2B", "SNEFRU128", "SNEFRU256", "RHash", "hash_msg", "hash_file", "make_magnet", "get_librhash_version", "SHA224", "SHA256", "SHA384", "SHA512", "hash_for_msg", "hash_for_file", "magnet_for_file", ] RHash-1.4.3/bindings/python/rhash/rhash.py000066400000000000000000000253631425216725100204440ustar00rootroot00000000000000# Copyright (c) 2011, Sergey Basalaev , # Aleksey Kravchenko # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. """Python bindings for LibRHash. Librhash is a library for computing message digests and magnet links for various hash functions. The simplest way to calculate a message digest of a string or file is by using one of the functions: hash_msg(message, hash_id) hash_file(filepath, hash_id) make_magnet(filepath, 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, SHA2_224, SHA2_256, SHA2_384, SHA2_512, SHA3_224, SHA3_256, SHA3_384, SHA3_512, BLAKE2S, BLAKE2B, 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 make_magnet('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 message digests 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(filepath). 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, hash_id can be omitted if the instance of RHash was created to compute message digest of a single hash function. Method magnet(filepath) will generate magnet link containing message digests computed by the RHash object. """ import sys import warnings 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 SHA2_224 = 0x10000 SHA2_256 = 0x20000 SHA2_384 = 0x40000 SHA2_512 = 0x80000 EDONR256 = 0x100000 EDONR512 = 0x200000 SHA3_224 = 0x0400000 SHA3_256 = 0x0800000 SHA3_384 = 0x1000000 SHA3_512 = 0x2000000 CRC32C = 0x4000000 SNEFRU128 = 0x08000000 SNEFRU256 = 0x10000000 BLAKE2S = 0x20000000 BLAKE2B = 0x40000000 ALL = 0x7FFFFFFF # four deprecated constants SHA224 = 0x10000 SHA256 = 0x20000 SHA384 = 0x40000 SHA512 = 0x80000 # 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 RMSG_SET_AUTOFINAL = 5 RMSG_GET_LIBRHASH_VERSION = 20 class RHash(object): """Class to compute message digests and magnet links.""" def __init__(self, *hash_ids): """Construct RHash object.""" hash_mask = 0 for hash_id in hash_ids: hash_mask = hash_mask | hash_id if hash_mask == 0: self._ctx = None raise ValueError("Invalid argument") self._ctx = _LIBRHASH.rhash_init(hash_mask) # switching off the auto-final feature _LIBRHASH.rhash_transmit(RMSG_SET_AUTOFINAL, self._ctx, 0, 0) def __del__(self): """Cleanup allocated resources.""" if self._ctx is not 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): """Update this object with new data chunk.""" return self.update(message) def update_file(self, filepath): """Update this object with data from the given file.""" file = open(filepath, "rb") buf = file.read(8192) while len(buf) > 0: self.update(buf) buf = file.read(8192) file.close() return self def finish(self): """Flush buffered data and calculate message digests.""" _LIBRHASH.rhash_final(self._ctx, None) return self def _print(self, hash_id, flags): """Retrieve the message digest in the specified 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] return buf[0:size].decode() def raw(self, hash_id=0): """Return the message digest as raw binary data.""" return self._print(hash_id, RHPR_RAW) def hex(self, hash_id=0): """Return the message digest as a hexadecimal lower-case string.""" return self._print(hash_id, RHPR_HEX) def base32(self, hash_id=0): """Return the message digest as a Base32 lower-case string.""" return self._print(hash_id, RHPR_BASE32) def base64(self, hash_id=0): """Return the message digest as a Base64 string.""" return self._print(hash_id, RHPR_BASE64) # pylint: disable=invalid-name def HEX(self, hash_id=0): """Return the message digest as a hexadecimal upper-case string.""" return self._print(hash_id, RHPR_HEX | RHPR_UPPERCASE) def BASE32(self, hash_id=0): """Return the message digest as a Base32 upper-case string.""" return self._print(hash_id, RHPR_BASE32 | RHPR_UPPERCASE) # pylint: enable=invalid-name def magnet(self, filepath): """Return magnet link with all message digests 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): """Return the message digest for the given hash function in its default format.""" return self._print(hash_id, 0) def __str__(self): """Return the message digest.""" return self._print(0, 0) # simplified interface functions def hash_msg(message, hash_id): """Compute and return the message digest (in its default format) of the message.""" handle = RHash(hash_id) handle.update(message).finish() return str(handle) def hash_file(filepath, hash_id): """Compute and return the message digest (in its default format) of the file content.""" handle = RHash(hash_id) handle.update_file(filepath).finish() return str(handle) def make_magnet(filepath, *hash_ids): """Compute and return the magnet link for the file.""" handle = RHash(*hash_ids) handle.update_file(filepath).finish() return handle.magnet(filepath) def get_librhash_version(): """Return the version of the loaded LibRHash library.""" ver = _LIBRHASH.rhash_transmit(RMSG_GET_LIBRHASH_VERSION, None, 0, 0) return "{}.{}.{}".format(ver >> 24, (ver >> 16) & 255, (ver >> 8) & 255) # deprecated functions def _deprecation(message): warnings.warn(message, category=DeprecationWarning, stacklevel=2) def hash_for_msg(message, hash_id): """Deprecated function to compute a hash of a message.""" _deprecation("Call to deprecated function hash_for_msg(), should use hash_msg().") return hash_msg(message, hash_id) def hash_for_file(filepath, hash_id): """Deprecated function to compute a hash of a file.""" _deprecation("Call to deprecated function hash_for_file(), should use hash_file().") return hash_file(filepath, hash_id) def magnet_for_file(filepath, hash_mask): """Deprecated function to compute a magnet link for a file.""" _deprecation( "Call to deprecated function magnet_for_file(), should use make_magnet()." ) return make_magnet(filepath, hash_mask) RHash-1.4.3/bindings/python/setup.cfg000066400000000000000000000011401425216725100174640ustar00rootroot00000000000000[metadata] name = rhash-Rhash version = 1.0 author = Aleksey Kravchenko author_email = rhash.admin@gmail.com description = Python interface for librhash long_description = file: README.md long_description_content_type = text/markdown url = https://github.com/rhash/RHash project_urls = Source = https://github.com/rhash/RHash Bug Tracker = https://github.com/rhash/RHash/issues license = BSD Zero Clause License classifiers = Programming Language :: Python :: 3 License :: OSI Approved :: BSD License Operating System :: OS Independent [options] packages = rhash python_requires = >=3.4 RHash-1.4.3/bindings/python/tests/000077500000000000000000000000001425216725100170115ustar00rootroot00000000000000RHash-1.4.3/bindings/python/tests/__init__.py000066400000000000000000000000001425216725100211100ustar00rootroot00000000000000RHash-1.4.3/bindings/python/tests/rhash_test.py000066400000000000000000000202541425216725100215320ustar00rootroot00000000000000# Copyright (c) 2011, Aleksey Kravchenko # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. """Unit-tests for the rhash module.""" import os import unittest import rhash # 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.SHA2_224), ) self.assertEqual( "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", ctx.hash(rhash.SHA2_256), ) self.assertEqual( "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", ctx.hash(rhash.SHA2_384), ) self.assertEqual( "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", ctx.hash(rhash.SHA2_512), ) 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), ) self.assertEqual( "4a0d129873403037c2cd9b9048203687f6233fb6738956e0349bd4320fec3e90", ctx.hash(rhash.BLAKE2S), ) self.assertEqual( "333fcb4ee1aa7c115355ec66ceac917c8bfd815bf7587d325aec1864edd24e34d5abe2c6b1b5ee3face62fed78dbef802f2a85cb91d455a8f5249d330853cb3c", ctx.hash(rhash.BLAKE2B), ) # test reset ctx.reset().finish() self.assertEqual( "d41d8cd98f00b204e9800998ecf8427e", ctx.hash(rhash.MD5) ) # MD5( '' ) def test_update(self): """Test sequential updates.""" 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_msg(self): """Test hash_msg() function.""" self.assertEqual( "900150983cd24fb0d6963f7d28e17f72", rhash.hash_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 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_file(path, rhash.SHA1), ) self.assertEqual( "magnet:?xl=4&dn=python_test_input_123.txt&xt=urn:crc32:f2653eb7&xt=urn:tree:tiger:c6docz63fpef5pdfpz35z7mw2iozshxlpr4erza", rhash.make_magnet(path, rhash.CRC32, rhash.TTH), ) os.remove(path) def test_librhash_version(self): """Test get_librhash_version() function.""" version = rhash.get_librhash_version() self.assertTrue(isinstance(version, str)) self.assertRegex(version, r"^[1-9]\d*\.\d+\.\d+$") if __name__ == "__main__": unittest.main() RHash-1.4.3/bindings/ruby/000077500000000000000000000000001425216725100153075ustar00rootroot00000000000000RHash-1.4.3/bindings/ruby/.gitignore000066400000000000000000000000331425216725100172730ustar00rootroot00000000000000mkmf.log rhash.so Makefile RHash-1.4.3/bindings/ruby/extconf.rb000066400000000000000000000003651425216725100173060ustar00rootroot00000000000000require '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') RHash-1.4.3/bindings/ruby/rhash.c000066400000000000000000000267431425216725100165740ustar00rootroot00000000000000/* * Ruby Bindings for Librhash * * Copyright (c) 2011, Sergey Basalaev and * Aleksey Kravchenko * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #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 message digests. */ 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) { int len; char buf[130]; rhash ctx; Data_Get_Struct(self, struct rhash_context, ctx); 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 message digests 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 message digests for given algorithms. * Parameters should be constants defined in this class. */ VALUE rh_new(int argc, VALUE* argv, VALUE clz) { rhash ctx; VALUE newobj; 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)); /** BLAKE2s hash. */ rb_define_const(cRHash, "BLAKE2S", INT2FIX(RHASH_BLAKE2S)); /** BLAKE2b hash. */ rb_define_const(cRHash, "BLAKE2B", INT2FIX(RHASH_BLAKE2B)); /** Compute message digests for all available algorithms. */ rb_define_const(cRHash, "ALL", INT2FIX(RHASH_ALL_HASHES)); } RHash-1.4.3/bindings/ruby/test_rhash.rb000066400000000000000000000110451425216725100200010ustar00rootroot00000000000000#!/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("4a0d129873403037c2cd9b9048203687f6233fb6738956e0349bd4320fec3e90", r.to_s(RHash::BLAKE2S)) assert_equal("333fcb4ee1aa7c115355ec66ceac917c8bfd815bf7587d325aec1864edd24e34d5abe2c6b1b5ee3face62fed78dbef802f2a85cb91d455a8f5249d330853cb3c", r.to_s(RHash::BLAKE2B)) 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 RHash-1.4.3/bindings/version.properties000066400000000000000000000000161425216725100201260ustar00rootroot00000000000000version=1.4.2 RHash-1.4.3/build/000077500000000000000000000000001425216725100136305ustar00rootroot00000000000000RHash-1.4.3/build/vc-2010/000077500000000000000000000000001425216725100146205ustar00rootroot00000000000000RHash-1.4.3/build/vc-2010/rhash.vcxproj000066400000000000000000000436531425216725100173550ustar00rootroot00000000000000 Debug Win32 Debug x64 Release Win32 Release x64 {F478B068-6719-4C50-83F5-F74A6EE22A4D} rhash Win32Proj Application Unicode true Application Unicode true Application Application Application Application Application Unicode Application Unicode <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)$(Configuration)\ $(SolutionDir)$(Configuration)-x64\ $(Configuration)\ $(Configuration)-x64\ true true $(SolutionDir)$(Configuration)\ $(SolutionDir)$(Configuration)-x64\ $(Configuration)\ $(Configuration)-x64\ false false AllRules.ruleset AllRules.ruleset AllRules.ruleset AllRules.ruleset Disabled ..\..\librhash;%(AdditionalIncludeDirectories) _CONSOLE;_CRT_SECURE_NO_DEPRECATE;_DEBUG;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue true Console false MachineX86 kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) Disabled ..\..\librhash;%(AdditionalIncludeDirectories) _CONSOLE;_CRT_SECURE_NO_DEPRECATE;_DEBUG;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Level3 ProgramDatabase false true StreamingSIMDExtensions2 true Console false kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) Full ..\..\librhash;%(AdditionalIncludeDirectories) _CONSOLE;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) MultiThreadedDLL false true NoListing Level3 ProgramDatabase Speed true true Console true true false MachineX86 kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) $(OutDir)$(TargetName).bsc Full ..\..\librhash;%(AdditionalIncludeDirectories) _CONSOLE;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) MultiThreadedDLL false true AssemblyAndSourceCode Level3 ProgramDatabase Speed true StreamingSIMDExtensions2 true Console true true false kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) true true true true RHash-1.4.3/calc_sums.c000066400000000000000000000365101425216725100146530ustar00rootroot00000000000000/* calc_sums.c - message digests calculating and printing functions */ #include "calc_sums.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" #include #include #include #include /* free() */ #include #ifdef _WIN32 # include /* _O_BINARY */ # include #endif /** * 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); if (opt.flags & (OPT_BT_PRIVATE | OPT_BT_TRANSMISSION)) { unsigned options = (opt.flags & OPT_BT_PRIVATE ? RHASH_TORRENT_OPT_PRIVATE : 0) | (opt.flags & OPT_BT_TRANSMISSION ? RHASH_TORRENT_OPT_TRANSMISSION : 0); rhash_torrent_set_options(info->rctx, options); } rhash_torrent_add_file(info->rctx, file_get_print_path(info->file, FPathUtf8 | FPathNotNull), info->size); rhash_torrent_set_program_name(info->rctx, get_bt_program_name()); 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 message digests. * * @param info the file data */ static void re_init_rhash_context(struct file_info* info) { if (rhash_data.rctx != 0) { if (IS_MODE(MODE_CHECK | MODE_CHECK_EMBEDDED)) { /* a set of hash algorithms 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_get_print_path(info->file, FPathUtf8 | FPathNotNull), 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 message digests simultaneously, according to the info->sums_flags. * Calculated message digests are stored in info->rctx. * * @param info file data * @return 0 on success, -1 on fail with error code stored in errno */ 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 (IS_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 unreadble files */ 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, (size_t)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; } /* functions to calculate and print file sums */ /** * Search for a crc32 checksum in the given file name. * * @param file the file, which filename is checked * @param crc32 pointer to integer to receive parsed checksum * @return non zero if crc32 was found, zero otherwise */ int find_embedded_crc32(file_t* file, unsigned* crc32) { const char* filepath = file_get_print_path(file, FPathUtf8 | FPathNotNull); 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 the given file by 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 stored in errno */ int rename_file_by_embeding_crc32(struct file_info* info) { int res = -1; unsigned crc32; file_t new_file; char suffix[12]; char* suffix_start = suffix; if (FILE_ISSPECIAL(info->file)) return 0; /* do nothing on stdin or a command-line message */ assert((info->rctx->hash_id & RHASH_CRC32) != 0); rhash_print(suffix + 2, info->rctx, RHASH_CRC32, (opt.flags & OPT_LOWERCASE ? 0 : RHPR_UPPERCASE)); /* check if filename already contains a CRC32 sum */ if (find_embedded_crc32(info->file, &crc32)) { /* compare with calculated CRC32 */ if (crc32 == get_crc32(info->rctx)) return 0; /* TRANSLATORS: sample filename with embedded CRC32: file_[A1B2C3D4].mkv */ log_warning(_("wrong embedded CRC32, should be %s\n"), suffix + 2); } suffix[1] = '['; suffix[10] = ']'; suffix[11] = 0; if (opt.embed_crc_delimiter && *opt.embed_crc_delimiter) suffix[0] = *opt.embed_crc_delimiter; else suffix_start++; memset(&new_file, 0, sizeof(new_file)); if (file_modify_path(&new_file, info->file, suffix_start, FModifyInsertBeforeExtension) < 0 && file_modify_path(&new_file, info->file, suffix_start, FModifyAppendSuffix) < 0) { /* impossible situation: AppendSuffix can't fail, so not translating this error */ log_error_msg_file_t("impossible: failed to rename file: %s\n", info->file); } else if (file_rename(info->file, &new_file) < 0) { log_error(_("can't move %s to %s: %s\n"), file_get_print_path(info->file, FPathPrimaryEncoding | FPathNotNull), file_get_print_path(&new_file, FPathPrimaryEncoding | FPathNotNull), strerror(errno)); } else { /* store the new path */ file_swap(info->file, &new_file); res = 0; } file_cleanup(&new_file); return res; } /** * Save torrent file to the given path. * In a case of fail, the error will be logged. * * @param torrent_file the path to save torrent file to * @param rctx the context containing torrent data * @return 0 on success, -1 on fail */ int save_torrent_to(file_t* torrent_file, struct rhash_context* rctx) { FILE* fd; int res = 0; const rhash_str* text = rhash_torrent_generate_content(rctx); if (!text) { errno = ENOMEM; log_error_file_t(torrent_file); return -1; } /* make backup copy of the existing torrent file, ignore errors */ 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) == 0) { /* TRANSLATORS: printed when a torrent file is saved */ log_msg_file_t(_("%s saved\n"), torrent_file); } else { log_error_file_t(torrent_file); res = -1; } if (fd) fclose(fd); return res; } /** * Save torrent file. * In a case of fail, the error will be logged. * * @param info information about the hashed file * @return 0 on success, -1 on fail */ static int save_torrent(struct file_info* info) { int res; /* append .torrent extension to the file path */ file_t torrent_file; file_modify_path(&torrent_file, info->file, ".torrent", FModifyAppendSuffix); res = file_modify_path(&torrent_file, info->file, ".torrent", FModifyAppendSuffix); if (res >= 0) res = save_torrent_to(&torrent_file, info->rctx); file_cleanup(&torrent_file); return res; } /** * Calculate and print file message digests using printf format. * In a case of fail, the error will be logged. * * @param out the output stream to print results to * @param out the name of the output stream * @param file the file to calculate sums for * @param print_path the path to print * @return 0 on success, -1 on input error, -2 on results output error */ int calculate_and_print_sums(FILE* out, file_t* out_file, file_t* file) { struct file_info info; timedelta_t timer; int res = 0; /* skip directories */ if (FILE_ISDIR(file)) return 0; memset(&info, 0, sizeof(info)); info.file = file; info.size = file->size; /* total size, in bytes */ info.sums_flags = opt.sum_flags; /* initialize percents output */ if (init_percents(&info) < 0) { log_error_file_t(&rhash_data.out_file); return -2; } rsh_timer_start(&timer); if (info.sums_flags) { /* calculate sums */ if (calc_sums(&info) < 0) { /* print i/o error */ log_error_file_t(file); res = -1; } if (rhash_data.stop_flags) { report_interrupted(); return 0; } } info.time = rsh_timer_stop(&timer); finish_percents(&info, res); if ((opt.flags & OPT_EMBED_CRC) && res == 0) { /* rename the file */ rename_file_by_embeding_crc32(&info); } if (IS_MODE(MODE_TORRENT) && !opt.bt_batch_file && res == 0) { if (save_torrent(&info) < 0) res = -2; } if (IS_MODE(MODE_UPDATE) && rhash_data.is_sfv && res == 0) { /* updating SFV file: print SFV header line */ if (print_sfv_header_line(out, out_file->mode, file) < 0) { log_error_file_t(out_file); res = -2; } if (opt.flags & OPT_VERBOSE) { print_sfv_header_line(rhash_data.log, rhash_data.log_file.mode, file); fflush(rhash_data.log); } } if (rhash_data.print_list && res == 0) { if (!opt.bt_batch_file) { if (print_line(out, out_file->mode, rhash_data.print_list, &info) < 0) { log_error_file_t(out_file); res = -2; } /* print the calculated line to stderr/log-file if verbose */ else if (IS_MODE(MODE_UPDATE) && (opt.flags & OPT_VERBOSE)) { print_line(rhash_data.log, rhash_data.log_file.mode, rhash_data.print_list, &info); } } if ((opt.flags & OPT_SPEED) && info.sums_flags) { print_file_time_stats(&info); } } return res; } /*========================================================================= * 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.stop_flags; 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; uint64_t 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 hash functions */ for (i = 0; i < (int)sizeof(message); i++) message[i] = i & 0xff; for (j = 0; j < rounds && !rhash_data.stop_flags; 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.stop_flags) { rsh_fprintf(rhash_data.out, "%s %u MiB calculated in %.3f sec, %.3f MBps\n", hash_name, (unsigned)sz_mb, (time / 1000.0), (double)sz_mb * 1000.0 / time); fflush(rhash_data.out); } } #if defined(HAVE_TSC) /* measure the CPU "clocks per byte" speed */ if ((flags & BENCHMARK_CPB) != 0 && !rhash_data.stop_flags) { 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.stop_flags) { 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 / 1000.0, (double)(sz_mb * rounds) * 1000.0 / 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 / 1000.0, (double)(sz_mb * rounds) * 1000.0 / 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"); } } RHash-1.4.3/calc_sums.h000066400000000000000000000031121425216725100146500ustar00rootroot00000000000000/* calc_sums.h */ #ifndef CALC_SUMS_H #define CALC_SUMS_H #include "common_func.h" #include "file.h" #include "hash_check.h" #ifdef __cplusplus extern "C" { #endif /** * Information about a file to calculate/verify message digests for. */ struct file_info { uint64_t size; /* the size of the hashed file */ uint64_t msg_offset; /* rctx->msg_size before hashing this file */ uint64_t time; /* file processing time in milliseconds */ file_t* file; /* the file being processed */ struct rhash_context* rctx; /* state of hash algorithms */ struct hash_parser* hp; /* parsed line of a hash file */ unsigned sums_flags; /* mask of ids of calculated hash functions */ int processing_result; /* -1/-2 for i/o error, 0 on success, 1 on a hash mismatch */ }; int calc_sums(struct file_info* info); int calculate_and_print_sums(FILE* out, file_t* out_file, file_t* file); int find_embedded_crc32(file_t* file, unsigned* crc32); int rename_file_by_embeding_crc32(struct file_info* info); int save_torrent_to(file_t* torrent_file, struct rhash_context* rctx); /* 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 */ RHash-1.4.3/common_func.c000066400000000000000000000431071425216725100152050ustar00rootroot00000000000000/* common_func.c - functions used almost everywhere */ #include "common_func.h" #include "parse_cmdline.h" #include "version.h" #include "win_utils.h" #include #include #include #include #include #include #include #if defined( _WIN32) || defined(__CYGWIN__) # include #endif /*========================================================================= * 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 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; } #ifdef _WIN32 /** * Return wide-string obtained from the given source string by replacing its part with another string. * * @param src source wide-string * @param start_pos starting position of the replacement * @param end_pos ending position of the replacement * @param replacement the replacement ASCII string (nullable), NULL is interpreted as empty string * @return result of replacement, the resulting string is always allocated by malloc(), * and must be freed by caller */ wchar_t* wcs_replace_n(const wchar_t* src, size_t start_pos, size_t end_pos, const char* replacement) { const size_t len1 = wcslen(src); const size_t len2 = (replacement ? strlen(replacement) : 0); size_t result_len; size_t i; wchar_t* result; if (start_pos > len1) start_pos = end_pos = len1; else if (end_pos > len1) end_pos = len1; else if (start_pos > end_pos) end_pos = start_pos; result_len = len1 + len2 - (end_pos - start_pos); result = (wchar_t*)rsh_malloc((result_len + 1) * sizeof(wchar_t)); memcpy(result, src, start_pos * sizeof(wchar_t)); for (i = 0; i < len2; i++) result[start_pos + i] = (wchar_t)replacement[i]; if (end_pos < len1) memcpy(result + start_pos + len2, src + end_pos, (len1 - end_pos) * sizeof(wchar_t)); result[result_len] = 0; return result; } #endif /** * Return string obtained from the given source string by replacing its part with another string. * * @param src source string * @param start_pos starting position of the replacement * @param end_pos ending position of the replacement * @param replacement the replacement string (nullable), NULL is interpreted as empty string * @return result of replacement, the resulting string is always allocated by malloc(), * and must be freed by caller */ char* str_replace_n(const char* src, size_t start_pos, size_t end_pos, const char* replacement) { const size_t len1 = strlen(src); const size_t len2 = (replacement ? strlen(replacement) : 0); size_t result_len; char* result; if (start_pos > len1) start_pos = end_pos = len1; else if (end_pos > len1) end_pos = len1; else if (start_pos > end_pos) end_pos = start_pos; result_len = len1 + len2 - (end_pos - start_pos); result = (char*)rsh_malloc(result_len + 1); memcpy(result, src, start_pos); if (len2 > 0) memcpy(result + start_pos, replacement, len2); if (end_pos < len1) memcpy(result + start_pos + len2, src + end_pos, len1 - end_pos); result[result_len] = 0; return result; } /** * 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 count_utf8_symbols(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 *=========================================================================*/ #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); } uint64_t rsh_timer_stop(timedelta_t* timer) { timedelta_t end; #if defined( _WIN32) || defined(__CYGWIN__) LARGE_INTEGER frequency; get_timedelta(&end); *timer = end - *timer; QueryPerformanceFrequency(&frequency); return (uint64_t)((LONGLONG)(*timer) * 1000 / frequency.QuadPart); #else get_timedelta(&end); 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; return ((uint64_t)(timer->tv_sec) * 1000 + timer->tv_usec / 1000); #endif } 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. * * @param code the program exit code */ void rsh_call_exit_handlers(void) { while (rhash_exit_handlers.handlers_count > 0) rhash_exit_handlers.handlers[--rhash_exit_handlers.handlers_count](); } /** * Call all installed exit handlers and exit the program. * * @param code the program exit code */ void rsh_exit(int code) { rsh_call_exit_handlers(); 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; i < vect->size; 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*)rsh_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)); } RHash-1.4.3/common_func.h000066400000000000000000000160461425216725100152140ustar00rootroot00000000000000/* 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 /* for wchar_t */ #include #include #include /* for time_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); size_t count_utf8_symbols(const char* str); 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_replace_n(const char* src, size_t start_pos, size_t end_pos, const char* replace); #ifdef _WIN32 wchar_t* wcs_replace_n(const wchar_t* src, size_t start_pos, size_t end_pos, const char* replace); #endif /* _WIN32 */ /* check if character starts a commentary in the program config file */ #define IS_COMMENT(c) ((c) == ';' || (c) == '#') /* test line for UTF8 mark: 0xEF, 0xBB, 0xBF */ #define STARTS_WITH_UTF8_BOM(line) ((line)[0] == '\357' && (line)[1] == '\273' && (line)[2] == '\277') #ifdef _WIN32 typedef wchar_t rsh_tchar; # define RSH_T(str) L##str #else typedef char rsh_tchar; # define RSH_T(str) str #endif /* _WIN32 */ typedef rsh_tchar* tstr_t; typedef const rsh_tchar* ctstr_t; #ifdef _WIN32 # define IF_WINDOWS(code) code #else /* non _WIN32 part */ # define IF_WINDOWS(code) #endif /* _WIN32 */ /* version information */ const char* get_version_string(void); const char* get_bt_program_name(void); /* printf functions */ #ifdef _WIN32 # define rsh_fprintf win_fprintf # define rsh_fprintf_targ win_fprintf_warg # define rsh_vfprintf win_vfprintf # define rsh_fwrite win_fwrite #else # define rsh_fprintf fprintf # define rsh_fprintf_targ fprintf # define rsh_vfprintf vfprintf # define rsh_fwrite fwrite #endif #define PRINTF_RES(res) ((res) < 0 ? res : 0) /* time delta and timer 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 timer value in milliseconds */ uint64_t 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_call_exit_handlers(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__) #define rsh_tstrdup(str) rsh_wcsdup(str) wchar_t* rhash_wcsdup(const wchar_t* str, const char* srcfile, int srcline); #else #define rsh_tstrdup(str) rsh_strdup(str) #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 */ RHash-1.4.3/configure000077500000000000000000000704341425216725100144500ustar00rootroot00000000000000#!/bin/sh # set default values OPT_OPENSSL=auto OPT_OPENSSL_RUNTIME=auto OPT_GETTEXT=auto OPT_CC= 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 has160-hash gost12-256-hash gost12-512-hash edonr256-hash edonr512-hash tiger-hash tth-hash whirlpool-hash ed2k-link magnet-link" INSTALL_LIB_STATIC=auto INSTALL_LIB_SHARED=auto INSTALL_PKGCONFIGDIR="$PKG_INSTALLDIR" SHARED_LIB_MODE=${SHARED_LIB_MODE:-755} # detect and prepare tmp directory for DETECT_TMP in "$TMPDIR" "$TEMPDIR" "/tmp"; do test -d "$DETECT_TMP" && break done RANDNUM=$RANDOM test -z "$RANDNUM" && jot -r 1 2>/dev/null >dev/null && RANDNUM=$(jot -r 1 1 32767) || RANDNUM=0 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 # 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[=runtime] enable OpenSSL (optimized hash functions) support. If runtime specified, then load OpenSSL at runtime if the library is found [autodetect] --enable-debug enable debug information --enable-static statically link libraries into 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 } check_set_contains() { VALUE="$1" shift for VALID_VALUE do if test "$VALUE" = "$VALID_VALUE"; then return 0 fi shift done return 1 } 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 ;; --enable-openssl=*) OPT_OPENSSL=$(get_opt_value $OPT) check_set_contains "$OPT_OPENSSL" "runtime" || die "Unexpected option value: $OPT" ;; --disable-openssl) OPT_OPENSSL=no ;; --enable-openssl-runtime) OPT_OPENSSL=runtime # legacy option echo "warning: use --enable-openssl=runtime instead of $OPT" >> "$TMPLOG" ;; --disable-openssl-runtime) OPT_OPENSSL=yes # legacy option echo "warning: use --enable-openssl instead of $OPT" >> "$TMPLOG" ;; --target=*) BUILD_TARGET=$(get_opt_value $OPT) ;; --cc=*) CC=$(get_opt_value $OPT) OPT_CC=1 ;; --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="$BUILD_EXTRA_CFLAGS $(get_opt_value $OPT)" ;; --extra-ldflags=*) BUILD_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" join_params() { printf '%s ' $@ | sed -e 's/ $//' } run_cmd() { echo "Run: $@" >> "$TMPLOG" $@ >> "$TMPLOG" 2>&1 TMPRES="$?" echo "Run result: $TMPRES" >> "$TMPLOG" echo >> "$TMPLOG" return "$TMPRES" } yn_nonempty() { test -n "$1" && echo yes || echo no; } log_start() { echo "============ Checking for $1 ============" >> "$TMPLOG" } log_finish() { echo "=============================================" >> "$TMPLOG" echo "" >> "$TMPLOG" } # Use this before starting a check start_check() { log_start "$1" printf '%s' "Checking for $1 ... " res_comment="" } # Use this to echo the results of a check finish_check() { if test -n "$res_comment"; then res_comment="($res_comment)" fi echo "Result is: $1 $res_comment" >> "$TMPLOG" log_finish 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|uclinux) 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 ;; cygwin*) TARGET_OS=CYGWIN ;; 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.*|20*) cc_version="$cc_version, ok" ;; *) cc_version="$cc_version, bad" cc_fail=yes ;; esac finish_check "$cc_version" else CC_TMP="$CC" test -n "$OPT_CC" && OTHER_CC= || OTHER_CC="gcc cc" for CC in "$CC_TMP" $OTHER_CC; do cc_name_tmp= if run_cmd "$CC -v"; then cc_name_tmp=$($CC -v 2>&1 | tail -n 1 | cut -d ' ' -f 1) elif run_cmd "$CC --version"; then cc_name_tmp=$($CC --version 2>&1 | head -n 1 | cut -d ' ' -f 1) fi if echo "$cc_name_tmp" | grep -q "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 elif $CC --version 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 else 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" log_start "compiler working with default options" if ! cc_check_cflag; then die "compiler doesn't work" fi log_finish 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 $BUILD_DEBUG; do case "$OPT" in -O[0-3]|-O) return 0 ;; esac done return 1 } has_optimization && OPTLEVEL= || OPTLEVEL="-O2" test -n "$BUILD_DEBUG" && OPTNDEBUG= || OPTNDEBUG="-DNDEBUG" OPTFLAGS="-pipe -ffunction-sections -fdata-sections" check_set_contains "-fno-omit-frame-pointer" $BUILD_EXTRA_CFLAGS $BUILD_DEBUG \ || OPTFLAGS="$OPTFLAGS -fomit-frame-pointer" OPTFLAGS=$(join_params $BUILD_DEBUG $OPTLEVEL $OPTNDEBUG $OPTFLAGS) # test that compiler works with options specified by command line log_start "compiler working with provided options" if ! cc_check_cflag; then die "wrong compiler options provided" fi log_finish # 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" && ! 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 LIBDL_LDFLAGS= if win32; then ALLOW_RUNTIME_LINKING=yes elif test "$BUILD_STATIC" = "yes"; then ALLOW_RUNTIME_LINKING=no elif test "$OPT_OPENSSL" = "auto" || test "$OPT_OPENSSL" = "runtime"; 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" 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" && die "dlopen() is required for OpenSSL runtime loading" 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" || ( test "$ALLOW_RUNTIME_LINKING" = "yes" && test "$OPT_OPENSSL" = "auto" ); 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" != "auto" && test "$OPENSSL_FOUND" = "no" && die "OpenSSL library not found" fi # building of static/shared binary and 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= RHASH_XVERSION= 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]*\.[0-9]' ; } if test "$HAS_RHASH" = "yes" || test "$HAS_LIBRHASH" = "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" _v1=$(echo $RHASH_VERSION | cut -d '.' -f 1) _v2=$(echo $RHASH_VERSION | cut -d '.' -f 2) _v3=$(echo $RHASH_VERSION | cut -d '.' -f 3) RHASH_XVERSION=$(printf "0x%02x%02x%02x%02x" "$_v1" "$_v2" "$_v3" 0) 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 CONFCFLAGS = -DSYSCONFDIR=\\"$INSTALL_SYSCONFDIR\\" LOCALECFLAGS = -DLOCALEDIR=\\"$INSTALL_LOCALEDIR\\" 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 SHARED_LIB_MODE = $SHARED_LIB_MODE 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) VERSION_CFLAGS = -DRHASH_XVERSION=$RHASH_XVERSION 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 RHash-1.4.3/dist/000077500000000000000000000000001425216725100134745ustar00rootroot00000000000000RHash-1.4.3/dist/MD5.bat000066400000000000000000000001051425216725100145450ustar00rootroot00000000000000@REM generate md5 file @rhash.exe --md5 %1 %2 %3 %4 %5 %6 %7 %8 %9 RHash-1.4.3/dist/magnet.bat000066400000000000000000000001141425216725100154330ustar00rootroot00000000000000@REM generate magnet links @rhash.exe --magnet %1 %2 %3 %4 %5 %6 %7 %8 %9 RHash-1.4.3/dist/rhash.1000066400000000000000000000314401425216725100146650ustar00rootroot00000000000000.TH RHASH 1 "APR 2010" Linux "User Manuals" .SH NAME rhash \- calculate/check CRC32, MD5, SHA1, GOST, TTH, BTIH or other message digests. .SH SYNOPSIS .B rhash [ .I option .B ]... [ .I file .B ]... .SH DESCRIPTION .B RHash (Recursive Hasher) computes and verifies various message digests and checksums of files. Supported hash algorithms include CRC32, CRC32C, MD4, MD5, SHA1, SHA256, SHA512, SHA3, Tiger, DC++ TTH, BTIH, AICH, ED2K, GOST R 34.11\-*, RIPEMD\-160, HAS\-160, BLAKE2s/BLAKE2b, 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 the standard input stream (stdin). By default .B rhash prints sums in SFV format with CRC32 checksum only. The format can be changed by options \-\-bsd, \-\-magnet, \-\-simple, \-\-printf, \-\-template. To output all sums use the `\-a' option. .SH PROGRAM MODE OPTIONS The default mode is to print checksums for all files and directory trees specified by command line. The mode can be changed by the following options. .IP "\-c, \-\-check" Check hash files specified by command line. RHash can verify hash files in SFV and BSD formats, MD5 and SHA1 files format and text files containing magnet or ed2k links (one link per line). Empty lines and lines starting with `;' or `#' are ignored. RHash can verify hash files generated without \-\-printf and \-\-template formatting options. If the hash algorithm is not specified by command line options then RHash tries to detect algorithm from the extension of the hash file. If detection fails, then all hash function of the same hash length are calculated, and that significally slows down files verification. To speed up verification, in such case, explicitly specify the hash algorithm in the command line. .IP "\-u, \-\-update=" Update the hash file specified by the option. Message digests will be calculated for all files specified by the command line and not present in this hash file. The calculated Message digests will be appended to the updated hash file in the format specified by formatting options. The \-\-update option can be combined with \-\-recursive to update a hash file for whole directory trees. Also \-\-update option can be used with \-\-check to verify the hash file before updating 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 the selected hash algorithm(s). .SH HASH ALGORITHMS OPTIONS .IP "\-C, \-\-crc32" CRC32: Select CRC32 checksum algorithm. .IP "\-\-crc32c" CRC32C: Select CRC32C checksum algorithm. .IP "\-\-md4" MD4: Select MD4 hash function. .IP "\-M, \-\-md5" MD5: Select MD5 hash function. .IP "\-H, \-\-sha1" SHA1: Select SHA1 hash function. .IP "\-\-sha224, \-\-sha256, \-\-sha384, \-\-sha512" Select specified SHA2 hash function. .IP "\-\-sha3-224, \-\-sha3-256, \-\-sha3-384, \-\-sha3-512" Select specified SHA3 hash function. .IP "\-\-tiger" Tiger: Select Tiger hash function. .IP "\-T, \-\-tth" TTH: Select DC++ TTH hash function. .IP "\-\-btih" BTIH: Select BitTorrent Info Hash. .IP "\-A, \-\-aich" AICH: Select AICH hash function. .IP "\-E, \-\-ed2k" ED2K: Select eDonkey 2000 hash function. .IP "\-L, \-\-ed2k\-link" eDonkey link: calculate and print eDonkey link. .IP "\-W, \-\-whirlpool" Whirlpool: Select Whirlpool hash function. .IP "\-G, \-\-gost12-256" GOST\-2012: Select 256-bit GOST R 34.11\-2012, the Russian GOST standard hash function. .IP "\-\-gost12-512" GOST\-2012: Select 512-bit GOST R 34.11\-2012, the Russian GOST standard hash function. .IP "\-\-gost94" GOST\-94: Select GOST R 34.11\-94, the deprecated Russian hash function. .IP "\-\-gost94\-cryptopro" GOST\-94\-CRYPTOPRO: Select the CryptoPro version of the deprecated Russian GOST R 34.11\-94 hash function. .IP "\-\-ripemd160" RIPEMD\-160: Select RIPEMD\-160 hash function. .IP "\-\-has160" HAS\-160: Select HAS\-160 hash function. .IP "\-\-snefru128, \-\-snefru256" SNEFRU: Select SNEFRU\-128/256 hash function. .IP "\-\-edonr256, \-\-edonr512" EDON\-R: Select EDON\-R 256/512 hash function. .IP "\-\-blake2b, \-\-blake2s" BLAKE2: Select BLAKE2b/BLAKE2s hash function. .IP "\-a, \-\-all" Calculate all supported hash functions. .IP "\-\-list\-hashes" List names of all supported hash functions, one per line. .SH MISCELLANEOUS OPTIONS .IP "\-r, \-\-recursive" Recursively process directories, specified by command line. .IP "\-\-follow" Follow symbolic links when processing files or directories recursively. .IP "\-m, \-\-message=" Calculate message digests of the given text message. .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 "\-v, \-\-verbose" Be verbose. .IP "\-\-brief" Print brief form of verification report (without a header and footer), when verifying a hash file. .IP "\-P, \-\-percents" Show percents, while calculating or checking sums .IP "\-\-skip\-ok" Don't print OK messages for successfully verified files. .IP "\-i, \-\-ignore\-missing" Ignore missing files, while verifying a hash file. .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 message digests or 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 function names, but only those supported by openssl are allowed: md4, md5, sha1, sha2*, ripemd160 and whirlpool. .IP "\-\-gost\-reverse" Reverse bytes in hexadecimal output of a GOST hash functions. The most significant byte of the message digest will be printed first. Default order is the least significant byte 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 torrent file or BTIH for a private BitTorrent tracker. .IP "\-\-bt\-transmission" Generate torrent file or BTIH compatible with Transmission torrent client. .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 message digest. .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 "\-\-no\-detect\-by\-ext" Do not detect hash function by an extension of hash file, in the \-\-check mode. .IP "\-\-no\-path\-escaping" Turn off escape characters in file paths. The option can be specified in the default, check or update modes. .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 message digests in the SFV (Simple File Verification) output format (default). But unlike common SFV file, not only CRC32, but any message digests specified by options can be printed. .IP "\-g, \-\-magnet" Print message digests formatted as magnet links. .IP "\-\-bsd" Use BSD output format. Each message digest is printed on a separate line after hash function name and file's path, enclosed in parentheses. .IP "\-\-simple" Use simple output format. Each line will consist of filename and message digests specified by options. .IP "\-\-hex" Print message digests in hexadecimal format. .IP "\-\-base32" Print message digests in Base32 format. .IP "\-b, \-\-base64" Print message digests in Base64 format. .IP "\-\-uppercase" Print message digests in upper case. .IP "\-\-lowercase" Print message digests 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 or %U" Prefix used to print a filename, file path or base64/raw message digest as an URL\(hyencoded string. For example: `%uf', `%up', `%uBm', `%u@h'. Use %u for lowercase and %U for uppercase characters. .IP %s File's size in bytes. .IP %{mtime} File's last modification time. .IP "%a or %A" AICH message digest. .IP "%c or %C" CRC32 checksum. Use %c for lowercase and %C for uppercase characters. .IP "%g or %G" GOST R 34.11\-2012 256-bit message digest. .IP "%h or %H" SHA1 message digest. .IP "%e or %E" ED2K message digest. .IP "%l or %L" EDonkey ed2k://... link. .IP "%m or %M" MD5 message digest. .IP "%r or %R" RIPEMD-160 message digest. .IP "%t or %T" TTH message digest. .IP "%w or %W" Whirlpool message digest. .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}, %{blake2s}, %{blake2b},\ %{snefru128}, %{snefru256}" Print the specified message digest. It is printed in uppercase, if the hash function name starts with a capital letter, e.g. %{TTH}, %{Sha-512}. .IP "%x, %b, %B, %@" Use one of these prefixes to output a message digest in hexadecimal, base32, base64 or raw (binary) format respectively, e.g. %b{md4}, %BH or %xT. .RE The default output format can also be changed by renaming the program or placing a hardlink/symlink to it with a filename containing strings `crc32', `crc32c', `md4', `md5', `sha1', `sha224' `sha256', `sha384' `sha512', `sha3\-256', `sha3\-512', `sha3\-224', `sha3\-384', `tiger', `tth', `btih', `aich', `ed2k', `ed2k\-link', `gost12\-256', `gost12\-512', `gost94', `gost94\-cryptopro', `rmd160', `has160', `whirlpool', `edonr256', `edonr512', `blake2s', `blake2b', `snefru128', `snefru256', `sfv' , `bsd' or `magnet'. .SH CONFIG FILE RHash looks for a config file at $XDG_CONFIG_HOME/rhash/rhashrc, $HOME/.config/rhash/rhashrc, $XDG_CONFIG_DIRS/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! Post them to the GitHub issues page .I https://github.com/rhash/RHash/issues RHash-1.4.3/dist/rhash.1.win.sed000066400000000000000000000006151425216725100162330ustar00rootroot00000000000000#!/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 } RHash-1.4.3/dist/rhash.spec.in000066400000000000000000000072271425216725100160720ustar00rootroot00000000000000# 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: 0BSD %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 RHash-1.4.3/dist/rhashrc.sample000066400000000000000000000010441425216725100163300ustar00rootroot00000000000000; The RHash config file config ; crc32 is the default hash sum #crc32=on #md5=on #sha1=on ; use windows code page (useful only under windows) #ansi=on ; ignore case in filenames, when verifying crc files #ignore-case=on ; directories are not scanned recursively by default #recursive=on ; OK messages are printed by default #skip-ok=on ; accept only *.sfv files while recursively checking directories #crc-accept=.sfv #crc-accept=.sfv,.md5,.sha1,.tiger,.tth,.aich ; percents are switched off by default #percents=on RHash-1.4.3/docs/000077500000000000000000000000001425216725100134615ustar00rootroot00000000000000RHash-1.4.3/docs/CONTRIBUTING.md000066400000000000000000000033541425216725100157170ustar00rootroot00000000000000# Contribution guidelines for the RHash project There are many ways of contributing to the project. * Sponsor the project * Translating to other languages * Hunting bugs * Packaging RHash to a new distribution * Contributing by writing code ## Sponsor the project Sponsor RHash  Support the project by money. ## 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 the [po files](../po/) and create a [Pull Request] or 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 print-info ``` File new bugs at the [issues] page. ## Bug fixing Investigate one of the bugs listed at [issues] page, fix it and make a pull request. ## 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. [donating]: http://sourceforge.net/donate/index.php?group_id=205103 [Launchpad]: https://launchpad.net/ [RHash translations]: https://translations.launchpad.net/rhash/ [Pull Request]: https://github.com/rhash/RHash/pulls [repository]: https://github.com/rhash/RHash/ [issues]: https://github.com/rhash/RHash/issues RHash-1.4.3/docs/LIBRHASH.md000066400000000000000000000062171425216725100152050ustar00rootroot00000000000000LibRHash Library ================ **LibRHash** is a professional, portable, thread-safe *C* library for computing a wide variety of hash functions. ### 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 [BSD Zero Clause License]. 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 message digests calculation */ /* output message digest as a hexadecimal 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 message digest 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, "message digest 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 message digest 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/ [BSD Zero Clause License]: ../COPYING RHash-1.4.3/file.c000066400000000000000000000772621425216725100136320ustar00rootroot00000000000000/* 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 "file.h" #include "common_func.h" #include "parse_cmdline.h" #include "platform.h" #include "win_utils.h" #include #include #include #include #include #include /* _O_RDONLY, _O_BINARY, posix_fadvise */ #if defined(_WIN32) || defined(__CYGWIN__) # include #if !defined(__CYGWIN__) # include /* for _SH_DENYWR */ #endif # include #endif #define IS_ANY_SLASH(c) ((c) == '/' || (c) == '\\') #define IS_ANY_TSLASH(c) ((c) == RSH_T('/') || (c) == RSH_T('\\')) #define IS_DOT_STR(s) ((s)[0] == '.' && (s)[1] == 0) #define IS_DOT_TSTR(s) ((s)[0] == '.' && (s)[1] == 0) #ifdef _WIN32 /* auxiliary function */ static int str_is_ascii(const char* str) { for (; *str; str++) if ((unsigned char)*str >= 0x80) return 0; return 1; } #endif /*========================================================================= * Path functions *=========================================================================*/ /** * Return file name without path. * * @param path file path * @return file name */ static const char* get_basename(const char* path) { const char* p; if (!path) return NULL; for (p = path + strlen(path); p > path && !IS_PATH_SEPARATOR(*(p - 1)); p--); return p; } /** * Return filepath, obtained by concatinating a directory path and a sub-path. * * @param dir_path (nullable) directory path * @param sub_path the filepath to append to the directory * @param user_path_separator flag, 1 to use user-defined path separator, * 0 to use system path separator * @return concatinated file path */ char* make_path(const char* dir_path, const char* sub_path, int user_path_separator) { char* buf; size_t dir_len; assert(sub_path); if (sub_path[0] == '.' && IS_ANY_SLASH(sub_path[1])) sub_path += 2; if (!dir_path) return rsh_strdup(sub_path); /* remove leading path delimiters from sub_path */ for (; IS_ANY_SLASH(*sub_path); sub_path++); if (dir_path[0] == 0 || IS_DOT_STR(dir_path)) { /* do not extend sub_path for dir_path="." */ return rsh_strdup(sub_path); } /* remove trailing path delimiters from the directory path */ for (dir_len = strlen(dir_path); dir_len > 0 && IS_ANY_SLASH(dir_path[dir_len - 1]); dir_len--); /* copy directory path */ buf = (char*)rsh_malloc(dir_len + strlen(sub_path) + 2); memcpy(buf, dir_path, dir_len); /* insert path separator */ buf[dir_len++] = (user_path_separator && opt.path_separator ? opt.path_separator : SYS_PATH_SEPARATOR); strcpy(buf + dir_len, sub_path); /* append sub_path */ return buf; } #ifdef _WIN32 /** * Return wide-string filepath, obtained by concatinating a directory path and a sub-path. * * @param dir_path (nullable) directory path * @param dir_len length of directory path in characters * @param sub_path the filepath to append to the directory * @return concatinated file path */ tpath_t make_wpath(ctpath_t dir_path, size_t dir_len, ctpath_t sub_path) { wchar_t* result; size_t len; if (dir_path == 0 || IS_DOT_TSTR(dir_path)) dir_len = 0; else { if (IS_UNC_PREFIX(sub_path)) sub_path += UNC_PREFIX_SIZE; if (sub_path[0] == L'.' && IS_PATH_SEPARATOR_W(sub_path[1])) sub_path += 2; /* remove leading path separators from sub_path */ for (; IS_PATH_SEPARATOR_W(*sub_path); sub_path++); if (dir_len == (size_t)-1) dir_len = wcslen(dir_path); } len = wcslen(sub_path); result = (wchar_t*)rsh_malloc((dir_len + len + 2) * sizeof(wchar_t)); if (dir_len > 0) { memcpy(result, dir_path, dir_len * sizeof(wchar_t)); if (result[dir_len - 1] != L'\\' && sub_path[0]) { /* append path separator to the directory */ result[dir_len++] = L'\\'; } } /* append sub_path */ memcpy(result + dir_len, sub_path, (len + 1) * sizeof(wchar_t)); return result; } /** * Return wide-string filepath, obtained by concatinating a directory path and a sub-path. * Windows UNC path is returned if the resulting path is too long. * * @param dir_path (nullable) directory path * @param sub_path the filepath to append to the directory * @return concatinated file path */ static tpath_t make_wpath_unc(ctpath_t dir_path, wchar_t* sub_path) { wchar_t* path = make_wpath(dir_path, (size_t)-1, sub_path); wchar_t* long_path = get_long_path_if_needed(path); if (!long_path) return path; free(path); return long_path; } #endif /* _WIN32 */ /** * Compare paths. * * @param path the first path * @param file the second path * @return 1 if paths a equal, 0 otherwise */ int are_paths_equal(ctpath_t path, file_t* file) { ctpath_t fpath; if (!path || !file || !file->real_path) return 0; fpath = file->real_path; if (path[0] == RSH_T('.') && IS_ANY_TSLASH(path[1])) path += 2; if (fpath[0] == RSH_T('.') && IS_ANY_TSLASH(fpath[1])) fpath += 2; for (; *path; ++path, ++fpath) { if (*path != *fpath && (!IS_ANY_TSLASH(*path) || !IS_ANY_TSLASH(*fpath))) { /* paths are different */ return 0; } } /* check if both paths terminated */ return (*path == *fpath); } #ifndef _WIN32 /** * Convert a windows file path to a UNIX one, replacing '\\' by '/'. * * @param path the path to convert * @return converted path */ static void convert_backslashes_to_unix(char* path) { for (; *path; path++) { if (*path == '\\') *path = '/'; } } #endif /* _WIN32 */ /** * 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_by_print_path(&file, NULL, path, FileInitReusePath); if (file_stat(&file, 0) >= 0) { is_regular = FILE_ISREG(&file); } file_cleanup(&file); return is_regular; } /*========================================================================= * file_t functions *=========================================================================*/ enum FileMemoryModeBits { FileDontFreeRealPath = 0x1000, FileDontFreePrintPath = 0x2000, FileDontFreeNativePath = 0x4000, FileMemoryModeMask = (FileDontFreeRealPath | FileDontFreePrintPath | FileDontFreeNativePath), FileIsAsciiPrintPath = 0x10000, FileDontUsePrintPath = 0x20000, FileDontUseNativePath = 0x40000, FileConversionMask = (FileIsAsciiPrintPath | FileDontUsePrintPath | FileDontUseNativePath) }; /** * 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 */ int file_init(file_t* file, ctpath_t path, unsigned init_flags) { #ifdef _WIN32 tpath_t long_path = get_long_path_if_needed(path); #endif memset(file, 0, sizeof(*file)); if (path[0] == RSH_T('.') && IS_ANY_TSLASH(path[1])) path += 2; file->real_path = (tpath_t)path; file->mode = (init_flags & FileMaskModeBits) | FileDontFreeRealPath; if (((init_flags & FileMaskUpdatePrintPath) && opt.path_separator) IF_WINDOWS( || long_path)) { /* initialize print_path using the path argument */ if (!file_get_print_path(file, FPathUtf8 | (init_flags & FileMaskUpdatePrintPath))) { IF_WINDOWS(free(long_path)); return -1; } } #ifdef _WIN32 if (long_path) { file->real_path = long_path; file->mode = init_flags & FileMaskModeBits; } else #endif { if ((init_flags & FileInitReusePath) == 0) { file->mode = init_flags & FileMaskModeBits; file->real_path = rsh_tstrdup(path); #ifndef _WIN32 if ((init_flags & FileInitUseRealPathAsIs) == 0) convert_backslashes_to_unix(file->real_path); #endif } } if ((init_flags & (FileInitRunFstat | FileInitRunLstat)) && file_stat(file, (init_flags & FileInitRunLstat)) < 0) return -1; return 0; } #ifdef _WIN32 static int file_statw(file_t* file); /** * Detect path encoding, by trying file_statw() the file in available encodings. * The order of encodings is detected by init_flags bit mask. * On success detection file->real_path is allocated. * * @param file the file to store * @param dir_path (nullable) directory path to prepend to printable path * @param print_path printable path, which encoding shall be detected * @param init_flags bit flags, helping to detect the encoding * @return encoding on success, -1 on fail with error code stored in errno */ static int detect_path_encoding(file_t* file, wchar_t* dir_path, const char* print_path, unsigned init_flags) { static unsigned encoding_flags[4] = { ConvertUtf8ToWcs | ConvertExact, ConvertNativeToWcs | ConvertExact, ConvertUtf8ToWcs, ConvertNativeToWcs }; wchar_t* last_path = NULL; unsigned convert_path = (dir_path ? 0 : ConvertPath); int ascii = str_is_ascii(print_path); int primary_path_index = ((opt.flags & OPT_UTF8) || (init_flags & FileInitUtf8PrintPath) || ascii ? 0 : 1); int step = ((init_flags & FileInitUtf8PrintPath) || ascii ? 2 : 1); int i; assert(file && !file->real_path); file->mode &= ~FileMaskStatBits; if (ascii) file->mode |= FileIsAsciiPrintPath; /* detect encoding in two or four steps */ for (i = 0; i < 4; i += step) { int path_index = i ^ primary_path_index; wchar_t* path = convert_str_to_wcs(print_path, encoding_flags[path_index] | convert_path); if (!path) { if (!last_path) continue; file->real_path = last_path; return primary_path_index; } if (dir_path) { file->real_path = make_wpath_unc(dir_path, path); free(path); } else file->real_path = path; if (i < 2) { if (file_statw(file) == 0 || errno == EACCES) { free(last_path); return (path_index & 1); } if (i == 0) { if (step == 2) return primary_path_index; last_path = file->real_path; continue; } free(file->real_path); file->real_path = last_path; if(file->real_path) return primary_path_index; } else if (file->real_path) { return (path_index & 1); } assert(last_path == NULL); } errno = EILSEQ; return -1; } #endif /** * Initialize file_t structure from a printable file path. * * @param file the file_t structure to initialize * @param prepend_dir the directory to prepend to the print_path, to construct the file path, can be NULL * @param print_path the printable representation of the file path * @param init_flags initialization flags * @return 0 on success, -1 on fail with error code stored in errno */ int file_init_by_print_path(file_t* file, file_t* prepend_dir, const char* print_path, unsigned init_flags) { assert(print_path); assert(!prepend_dir || prepend_dir->real_path); memset(file, 0, sizeof(file_t)); file->mode = (init_flags & FileMaskModeBits); if (init_flags & (FileIsStdStream | FileIsData)) { file->print_path = print_path; file->mode |= FileDontFreePrintPath | FileIsAsciiPrintPath; return 0; } if (print_path[0] == '.' && IS_PATH_SEPARATOR(print_path[1])) print_path += 2; #ifdef _WIN32 { const char** primary_path; wchar_t* dir_path = (prepend_dir && !IS_DOT_TSTR(prepend_dir->real_path) ? prepend_dir->real_path : NULL); int encoding = detect_path_encoding(file, dir_path, print_path, init_flags); if (encoding < 0) return -1; if (encoding == 0) { primary_path = &file->print_path; } else { primary_path = &file->native_path; } if ((init_flags & (FileInitReusePath | FileMaskUpdatePrintPath)) == FileInitReusePath) { *primary_path = print_path; file->mode |= (encoding == 0 ? FileDontFreePrintPath : FileDontFreeNativePath); } else { *primary_path = rsh_strdup(print_path); } } #else if (!prepend_dir || IS_DOT_STR(prepend_dir->real_path)) { file_init(file, print_path, init_flags & (FileInitReusePath | FileMaskModeBits)); } else { file->real_path = make_path(prepend_dir->real_path, print_path, 0); file->mode = init_flags & FileMaskModeBits; } assert(file->print_path == NULL); if ((init_flags & (FileInitReusePath | FileMaskUpdatePrintPath)) == FileInitReusePath) { file->print_path = print_path; file->mode |= FileDontFreePrintPath; } else { file->print_path = rsh_strdup(print_path); } #endif /* note: FileMaskUpdatePrintPath flags are used only with file_init() */ assert((init_flags & FileMaskUpdatePrintPath) == 0); if ((init_flags & (FileInitRunFstat | FileInitRunLstat)) && file_stat(file, (init_flags & FileInitRunLstat)) < 0) return -1; return 0; } /** * Transform the given file path, according to passed flags. * * @param path the file path to transform * @param flags bitmask containing FPathBaseName, FPathNotNull and FileMaskUpdatePrintPath bit flags * @return transformed path */ static const char* handle_rest_of_path_flags(const char* path, unsigned flags) { if (path == NULL) return ((flags & FPathNotNull) ? (errno == EINVAL ? "(null)" : "(encoding error)") : NULL); if ((flags & FileMaskUpdatePrintPath) != 0 && opt.path_separator) { char* p = (char*)path - 1 + strlen(path); for (; p >= path; p--) { if (IS_ANY_SLASH(*p)) { *p = opt.path_separator; if ((flags & FileInitUpdatePrintPathLastSlash) != 0) break; } } } return (flags & FPathBaseName ? get_basename(path) : path); } /** * Get the print path of the file in utf8 or in a native encoding. * Transformations specified by flags are applied. * Encoding conversion on Windows can be lossy. * * @param file the file to get the path * @param flags bitmask containing FPathUtf8, FPathNative, FPathBaseName, FPathNotNull * and FileMaskUpdatePrintPath bit flags * @return transformed print path of the file. If FPathNotNull flag is not specified, * then NULL is returned on function fail with error code stored in errno. * If FPathNotNull flag is set, then error code is transformed to returned string. */ const char* file_get_print_path(file_t* file, unsigned flags) { #ifdef _WIN32 unsigned convert_to; unsigned dont_use_bit; int is_utf8 = (opt.flags & OPT_UTF8 ? !(flags & FPathNative) : flags & FPathUtf8); const char* secondary_path; const char** primary_path = (is_utf8 || (file->mode & FileIsAsciiPrintPath) ? &file->print_path : &file->native_path); if (*primary_path) return handle_rest_of_path_flags(*primary_path, flags); if (is_utf8) { convert_to = ConvertToUtf8; dont_use_bit = FileDontUsePrintPath; secondary_path = file->native_path; } else { convert_to = ConvertToNative; dont_use_bit = FileDontUseNativePath; secondary_path = file->print_path; } if (secondary_path) { if ((file->mode & dont_use_bit) == 0) { *primary_path = convert_str_encoding(secondary_path, convert_to); if (!*primary_path) file->mode |= dont_use_bit; } else errno = EILSEQ; return handle_rest_of_path_flags(*primary_path, flags); } if (!file->real_path) { errno = EINVAL; return handle_rest_of_path_flags(NULL, flags); } *primary_path = convert_wcs_to_str(file->real_path, convert_to | ConvertPath); if (!*primary_path) return handle_rest_of_path_flags(NULL, flags); if (str_is_ascii(*primary_path)) { file->mode |= FileIsAsciiPrintPath; if (primary_path != &file->print_path) { file->print_path = *primary_path; file->native_path = NULL; primary_path = &file->print_path; } } return handle_rest_of_path_flags(*primary_path, flags); #else if (!file->print_path && !file->real_path) errno = EINVAL; if (!file->print_path && (flags & FileMaskUpdatePrintPath)) file->print_path = rsh_strdup(file->real_path); return handle_rest_of_path_flags((file->print_path ? file->print_path : file->real_path), flags); #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 & FileDontFreeRealPath)) free(file->real_path); file->real_path = NULL; if (!(file->mode & FileDontFreePrintPath)) free((char*)file->print_path); file->print_path = NULL; #ifdef _WIN32 if ((file->mode & FileDontFreeNativePath) == 0) free((char*)file->native_path); file->native_path = NULL; #endif /* _WIN32 */ free(file->data); file->data = NULL; file->mtime = 0; file->size = 0; file->mode = 0; } /** * Clone existing file_t structure to another. * * @param file the file_t structure to clone to * @param orig_file the file to clone */ void file_clone(file_t* file, const file_t* orig_file) { memset(file, 0, sizeof(*file)); file->mode = orig_file->mode & FileMaskModeBits; if (orig_file->real_path) file->real_path = rsh_tstrdup(orig_file->real_path); if (orig_file->print_path) file->print_path = rsh_strdup(orig_file->print_path); #ifdef _WIN32 if (orig_file->native_path) file->native_path = rsh_strdup(orig_file->native_path); #endif } /** * Swap members of two file_t structures. * * @param first the first file * @param second the second file */ void file_swap(file_t* first, file_t* second) { file_t tmp; memcpy(&tmp, first, sizeof(file_t)); memcpy(first, second, sizeof(file_t)); memcpy(second, &tmp, sizeof(file_t)); } /** * Get a modified file path. * * @param path the file path to modify * @param str the string to insert into/append to the source file path * @param operation the operation determinating how to modify the file path, can be one of the values * FModifyAppendSuffix, FModifyInsertBeforeExtension, FModifyRemoveExtension, FModifyGetParentDir * @return allocated and modified file path on success, NULL on fail */ static char* get_modified_path(const char* path, const char* str, int operation) { size_t start_pos = (size_t)-1; size_t end_pos = (size_t)-1; if (!path) return NULL; if (operation != FModifyAppendSuffix) { if (operation == FModifyGetParentDir) { end_pos = strlen(path); start_pos = (end_pos > 0 ? end_pos - 1 : 0); for (; start_pos > 0 && !IS_ANY_SLASH(path[start_pos]); start_pos--); if (start_pos == 0 && !IS_ANY_SLASH(path[start_pos])) return rsh_strdup("."); for (; start_pos > 0 && IS_ANY_SLASH(path[start_pos]); start_pos--); start_pos++; } else { char* point = strrchr(path, '.'); if (!point) return NULL; start_pos = point - path; if (operation == FModifyInsertBeforeExtension) end_pos = start_pos; } } return str_replace_n(path, start_pos, end_pos, str); } #ifdef _WIN32 /** * Get a modified file path. * * @param path the file path to modify * @param str the string to insert into/append to the source file path * @param operation the operation determinating how to modify the file path, can be one of the values * FModifyAppendSuffix, FModifyInsertBeforeExtension, FModifyRemoveExtension, FModifyGetParentDir * @return allocated and modified file path on success, NULL on fail */ static tpath_t get_modified_tpath(ctpath_t path, const char* str, int operation) { size_t start_pos = (size_t)-1; size_t end_pos = (size_t)-1; if (!path) return NULL; if (operation != FModifyAppendSuffix) { if (operation == FModifyGetParentDir) { end_pos = wcslen(path); start_pos = (end_pos > 0 ? end_pos - 1 : 0); for (; start_pos > 0 && !IS_ANY_TSLASH(path[start_pos]); start_pos--); if (start_pos == 0 && !IS_ANY_TSLASH(path[start_pos])) return rsh_wcsdup(L"."); for (; start_pos > 0 && IS_ANY_TSLASH(path[start_pos]); start_pos--); start_pos++; } else { rsh_tchar* point = wcsrchr(path, L'.'); if (!point) return NULL; start_pos = point - path; if (operation == FModifyInsertBeforeExtension) end_pos = start_pos; } } return wcs_replace_n(path, start_pos, end_pos, str); } #else # define get_modified_tpath get_modified_path #endif /** * Initialize a (destination) file by modifying the path of another (source) file. * * @param dst destination file * @param src source file * @param str the string to insert into/append to the source file path * @param operation the operation to do on src file, can be one of the values * FModifyAppendSuffix, FModifyInsertBeforeExtension, FModifyRemoveExtension, FModifyGetParentDir * @return 0 on success, -1 on fail with error code stored in errno */ int file_modify_path(file_t* dst, file_t* src, const char* str, int operation) { assert(operation == FModifyRemoveExtension || operation == FModifyGetParentDir || str); assert(operation == FModifyAppendSuffix || operation == FModifyInsertBeforeExtension || !str); memcpy(dst, src, sizeof(file_t)); dst->mode = 0; dst->print_path = NULL; IF_WINDOWS(dst->native_path = NULL); dst->print_path = get_modified_path(src->print_path, str, operation); if (!src->real_path) { if (!FILE_ISSPECIAL(src) || !dst->print_path) { errno = EINVAL; return -1; } #ifdef _WIN32 dst->real_path = convert_str_to_wcs(dst->print_path, ConvertUtf8ToWcs); #else dst->real_path = rsh_tstrdup(dst->print_path); #endif /* _WIN32 */ } else dst->real_path = get_modified_tpath(src->real_path, str, operation); IF_WINDOWS(dst->native_path = get_modified_path(src->native_path, str, operation)); return 0; } #ifdef _WIN32 /** * Retrieve file information (type, size, mtime) into file_t fields. * * @param file the file information * @return 0 on success, -1 on fail with error code stored in errno */ static int file_statw(file_t* file) { WIN32_FILE_ATTRIBUTE_DATA data; /* read file attributes */ if (GetFileAttributesExW(file->real_path, GetFileExInfoStandard, &data)) { uint64_t u; file->size = (((uint64_t)data.nFileSizeHigh) << 32) + data.nFileSizeLow; file->mode |= (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? FileIsDir : FileIsReg); if ((data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) file->mode |= FileIsLnk; /* the number of 100-nanosecond intervals since January 1, 1601 */ u = (((uint64_t)data.ftLastWriteTime.dwHighDateTime) << 32) + data.ftLastWriteTime.dwLowDateTime; /* convert to seconds and subtract the epoch difference */ file->mtime = u / 10000000 - 11644473600LL; return 0; } file->mode |= FileIsInaccessible; 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 fail with error code stored in errno */ int file_stat(file_t* file, int fstat_flags) { #ifdef _WIN32 (void)fstat_flags; /* ignore on windows */ #else struct stat st; #endif file->size = 0; file->mtime = 0; file->mode &= ~FileMaskStatBits; if (FILE_ISDATA(file) || FILE_ISSTDSTREAM(file)) return 0; else if (!file->real_path) { file->mode |= FileIsInaccessible; errno = EINVAL; return -1; } #ifdef _WIN32 return file_statw(file); #else if (stat(file->real_path, &st)) { file->mode |= FileIsInaccessible; return -1; } file->size = st.st_size; file->mtime = st.st_mtime; if (S_ISDIR(st.st_mode)) { file->mode |= FileIsDir; } else if (S_ISREG(st.st_mode)) { /* it's a regular file or a symlink pointing to a regular file */ file->mode |= FileIsReg; } if ((fstat_flags & FUseLstat) && lstat(file->real_path, &st) == 0) { if (S_ISLNK(st.st_mode)) file->mode |= FileIsLnk; /* it's a symlink */ } return 0; #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 fail with error code stored in errno */ 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, #ifdef _WIN32 RSH_T("rbS"), /* open with _O_SEQUENTIAL */ #else "rb", #endif RSH_T("wb"), RSH_T("r+b") }; const file_tchar* mode = possible_modes[fopen_flags & FOpenMask]; FILE* fd; assert((fopen_flags & FOpenRW) != 0); if (!file->real_path) { errno = EINVAL; return NULL; } #ifdef _WIN32 { fd = _wfsopen(file->real_path, mode, _SH_DENYNO); if (!fd && errno == EINVAL) errno = ENOENT; return fd; } #else fd = fopen(file->real_path, mode); # if _POSIX_C_SOURCE >= 200112L && !defined(__STRICT_ANSI__) if(fd) posix_fadvise(fileno(fd), 0, 0, POSIX_FADV_SEQUENTIAL); # endif /* _POSIX_C_SOURCE >= 200112L && !defined(__STRICT_ANSI__) */ return fd; #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 fail with error code stored in errno */ int file_rename(const file_t* from, const file_t* to) { #ifdef _WIN32 if (!from->real_path || !to->real_path) { errno = EINVAL; return -1; } /* Windows: file must be removed before overwriting it */ _wunlink(to->real_path); return _wrename(from->real_path, to->real_path); #else return rename(from->real_path, to->real_path); #endif } /** * Rename a given file to *.bak, if it exists. * * @param file the file to move * @return 0 on success, -1 on fail with error code stored in errno */ int file_move_to_bak(file_t* file) { if (FILE_ISSPECIAL(file)) return 0; else if (file_stat(file, 0) >= 0) { int res; int save_errno; file_t bak_file; file_modify_path(&bak_file, file, ".bak", FModifyAppendSuffix); 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 specified path points to a readable file. * * @param real_path file path * @param is_readable pointer to the result, it is set to 1, if the file is readable, to 0 otherwise * @return 1 if the file with such path exists, 0 otherwise */ static int real_path_is_readable(wchar_t* real_path, int* is_readable) { /* note: using _wsopen, since _waccess doesn't check permissions */ int fd = _wsopen(real_path, _O_RDONLY | _O_BINARY, _SH_DENYNO); *is_readable = (fd >= 0); if (fd >= 0) { _close(fd); return 1; } return (errno == EACCES); } #endif /** * Check if the given file can't be opened for reading. * * @param file the file * @return 1 if the file can be opened for reading, 0 otherwise */ int file_is_readable(file_t* file) { #ifdef _WIN32 if (file->real_path) { int is_readable; (void)real_path_is_readable(file->real_path, &is_readable); return is_readable; } return 0; #else return (access(file->real_path, R_OK) == 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 the file to open * @return 0 on success, -1 on fail with error code stored in errno */ int file_list_open(file_list_t* list, file_t* file) { memset(list, 0, sizeof(file_list_t)); if (FILE_ISSTDIN(file)) { list->fd = stdin; return 0; } list->fd = file_fopen(file, 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, FileListHasBom = FileInitUtf8PrintPath }; /** * 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 (STARTS_WITH_UTF8_BOM(buf)) { line += 3; if (!(list->state & NotFirstLine)) list->state |= FileListHasBom; } 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_by_print_path(&list->current_file, NULL, line, (list->state & FileInitUtf8PrintPath) | FileInitRunFstat); 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, NULL on fail with error code stored in errno */ WIN_DIR* win_opendir(const char* dir_path) { WIN_DIR* d; wchar_t* real_path; /* 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)); real_path = convert_str_to_wcs(path, (ConvertToPrimaryEncoding | ConvertExact | ConvertPath)); d->hFind = (real_path != NULL ? FindFirstFileW(real_path, &d->findFileData) : INVALID_HANDLE_VALUE); free(real_path); if (d->hFind == INVALID_HANDLE_VALUE && GetLastError() != ERROR_ACCESS_DENIED) { /* try the secondary codepage */ real_path = convert_str_to_wcs(path, (ConvertToSecondaryEncoding | ConvertExact | ConvertPath)); if (real_path) { d->hFind = FindFirstFileW(real_path, &d->findFileData); free(real_path); } } 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* real_path = make_wpath_unc(dir_path, L"*"); d = (WIN_DIR*)rsh_malloc(sizeof(WIN_DIR)); d->hFind = FindFirstFileW(real_path, &d->findFileData); free(real_path); 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; 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))) continue; /* simplified implementation, skips '.' and '..' names */ d->dir.d_name = filename = convert_wcs_to_str(d->findFileData.cFileName, (ConvertToPrimaryEncoding | ConvertExact)); if (filename) { d->dir.d_wname = d->findFileData.cFileName; d->dir.d_isdir = (0 != (d->findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); return &d->dir; } /* quietly skip the file and repeat the search, if filename conversion failed */ } } #endif /* _WIN32 */ RHash-1.4.3/file.h000066400000000000000000000121021425216725100136150ustar00rootroot00000000000000/* file.h - file abstraction layer */ #ifndef FILE_H #define FILE_H #include #include #include /* for wchar_t */ #ifdef __cplusplus extern "C" { #endif #ifdef _WIN32 typedef wchar_t file_tchar; # define SYS_PATH_SEPARATOR '\\' # define ALIEN_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 ALIEN_PATH_SEPARATOR '\\' # define IS_PATH_SEPARATOR(c) ((c) == '/') #endif /* _WIN32 */ typedef file_tchar* tpath_t; typedef const file_tchar* ctpath_t; /* Generic path functions */ char* make_path(const char* dir, const char* filename, int user_path_separator); #ifdef _WIN32 tpath_t make_wpath(ctpath_t dir_path, size_t dir_len, ctpath_t sub_path); # define make_tpath(dir_path, sub_path) make_wpath(dir_path, (size_t)-1, sub_path) #else # define make_tpath(dir_path, sub_path) make_path(dir_path, sub_path, 0) #endif /* _WIN32 */ int is_regular_file(const char* path); /* shall be deprecated */ /** * Portable file information. */ typedef struct file_t { tpath_t real_path; const char* print_path; #ifdef _WIN32 const char* native_path; /* print_path in native encoding */ #endif char* data; uint64_t size; uint64_t mtime; unsigned mode; } file_t; /* bit constants for the file_t.mode bit mask */ enum FileModeBits { FileIsDir = 0x01, FileIsLnk = 0x02, FileIsReg = 0x04, FileIsInaccessible = 0x08, FileIsRoot = 0x10, FileIsData = 0x20, FileIsList = 0x40, FileIsStdStream = 0x80, FileIsStdin = FileIsStdStream, FileContentIsUtf8 = 0x100, FileInitReusePath = 0x1000, FileInitUtf8PrintPath = 0x2000, FileInitRunFstat = 0x4000, FileInitRunLstat = 0x8000, FileInitUpdatePrintPathLastSlash = 0x10000, FileInitUpdatePrintPathSlashes = 0x20000, FileInitUseRealPathAsIs = 0x40000, FileMaskUpdatePrintPath = (FileInitUpdatePrintPathLastSlash | FileInitUpdatePrintPathSlashes), FileMaskStatBits = (FileIsDir | FileIsLnk | FileIsReg | FileIsInaccessible), FileMaskIsSpecial = (FileIsData | FileIsList | FileIsStdStream), FileMaskModeBits = (FileMaskStatBits | FileIsRoot | FileMaskIsSpecial | FileContentIsUtf8) }; #define FILE_ISDIR(file) ((file)->mode & FileIsDir) #define FILE_ISLNK(file) ((file)->mode & FileIsLnk) #define FILE_ISREG(file) ((file)->mode & FileIsReg) #define FILE_ISBAD(file) ((file)->mode & FileIsInaccessible) #define FILE_ISDATA(file) ((file)->mode & FileIsData) #define FILE_ISLIST(file) ((file)->mode & FileIsList) #define FILE_ISSTDIN(file) ((file)->mode & FileIsStdin) #define FILE_ISSTDSTREAM(file) ((file)->mode & FileIsStdStream) #define FILE_ISSPECIAL(file) ((file)->mode & (FileMaskIsSpecial)) #define FILE_IS_IN_UTF8(file) ((file)->mode & (FileContentIsUtf8)) /* file functions */ int file_init(file_t* file, ctpath_t path, unsigned init_flags); int file_init_by_print_path(file_t* file, file_t* prepend_dir, const char* print_path, unsigned init_flags); void file_cleanup(file_t* file); void file_clone(file_t* file, const file_t* orig_file); void file_swap(file_t* first, file_t* second); int are_paths_equal(ctpath_t path, struct file_t* file); enum FileGetPrintPathFlags { FPathPrimaryEncoding = 0, FPathUtf8 = 1, FPathNative = 2, FPathBaseName = 4, FPathNotNull = 8 }; const char* file_get_print_path(file_t* file, unsigned flags); enum FileModifyOperations { FModifyAppendSuffix, FModifyInsertBeforeExtension, FModifyRemoveExtension, FModifyGetParentDir }; int file_modify_path(file_t* dst, file_t* src, const char* str, int operation); enum FileStatModes { FNoMode = 0, FUseLstat = FileInitRunLstat }; 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); int file_rename(const file_t* from, const file_t* to); int file_move_to_bak(file_t* file); int file_is_readable(file_t* file); /** * A file list iterator. */ 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); int file_list_read(file_list_t* list); void file_list_close(file_list_t* list); #ifndef _WIN32 # define dirent_get_tname(d) ((d)->d_name) # define rsh_topendir(p) opendir(p) #else /* readdir structures and functions */ # define DIR WIN_DIR # define dirent win_dirent # define opendir win_opendir # define readdir win_readdir # define closedir win_closedir # define dirent_get_tname(d) ((d)->d_wname) # define rsh_topendir(p) win_wopendir(p) /* 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 */ RHash-1.4.3/file_mask.c000066400000000000000000000043751425216725100146400ustar00rootroot00000000000000/* file_mask.c - matching file against a list of file masks */ #include "file_mask.h" #include "file.h" #include #include #include #include /** * 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; char* cur; char* 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 file path 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 file the file path to match * @return 1 if matched, 0 otherwise */ int file_mask_match(file_mask_array* vect, struct file_t* file) { unsigned i; int res = 0; size_t len, namelen; char* buf; const char* name = file_get_print_path(file, FPathUtf8); if (!name) return 0; /* 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; } RHash-1.4.3/file_mask.h000066400000000000000000000012021425216725100146270ustar00rootroot00000000000000/* file_mask.h */ #ifndef FILE_MASK_H #define FILE_MASK_H #include "common_func.h" #ifdef __cplusplus extern "C" { #endif struct file_t; /* 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, struct file_t* file); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* FILE_MASK_H */ RHash-1.4.3/file_set.c000066400000000000000000000120241425216725100144660ustar00rootroot00000000000000/* file_set.c - functions to manipulate a set of files */ #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" #include #include /* isspace */ #include /* ptrdiff_t */ #include /* qsort */ #include /** * 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; } RHash-1.4.3/file_set.h000066400000000000000000000022211425216725100144710ustar00rootroot00000000000000/* file_set.h - functions to manipulate a set of files with its message digests */ #ifndef FILE_SET_H #define FILE_SET_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 */ RHash-1.4.3/find_file.c000066400000000000000000000307031425216725100146170ustar00rootroot00000000000000/* find_file.c - functions for recursive scan of directories. */ #include "find_file.h" #include "output.h" #include "parse_cmdline.h" #include "platform.h" #include "win_utils.h" #include #include #include #include #include #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 & FileIsStdin ? "(stdin)" : "(message)"); char* ext_data = 0; if (file_mode & FileIsData) { #ifdef _WIN32 ext_data = convert_wcs_to_str(str, ConvertToUtf8 | ConvertExact); /* we assume that this conversion always succeeds and the following condition is never met */ if (!ext_data) return; #else ext_data = rsh_strdup(str); #endif } file_init_by_print_path(&file, NULL, filename, file_mode); if (file_mode & FileIsData) { 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 &= (FileIsList | FileIsData); assert((file_mode & (file_mode - 1)) == 0); file_mode |= FileIsRoot; /* mark the file as obtained from the command line */ if ((file_mode & FileIsData) != 0) { file_search_add_special_file(data, file_mode, path); return; } if (IS_DASH_TSTR(path)) { file_search_add_special_file(data, (file_mode | FileIsStdin), 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 res; tpath_t filepath; if (IS_CURRENT_OR_PARENT_DIRW(d.cFileName)) continue; /* skip directories unless we are in recursive mode */ if (data->max_depth == 0 && (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) continue; filepath = make_wpath(parent, index + 1, d.cFileName); if (!filepath) continue; res = file_init(&file, filepath, file_mode | FileInitUpdatePrintPathSlashes | FileInitRunFstat); free(filepath); /* convert file name */ if (res == 0 && !(opt.flags & OPT_UTF8) && !file_get_print_path(&file, FPathPrimaryEncoding)) res = -1; /* quietly skip unconvertible file names and nonexistent files */ if (res < 0) { data->errors_count++; file_cleanup(&file); continue; } add_root_file(data, &file); } while (FindNextFileW(handle, &d)); FindClose(handle); } else { /* report error on the specified wildcard */ file_init(&file, path, FileInitReusePath); set_errno_from_last_file_error(); log_error_file_t(&file); file_cleanup(&file); data->errors_count++; } } else { if (file_init(&file, path, file_mode | FileInitRunFstat) < 0) { log_error_file_t(&file); file_cleanup(&file); data->errors_count++; return; } if (!(opt.flags & OPT_UTF8) && !file_get_print_path(&file, FPathPrimaryEncoding)) { log_error_msg_file_t(_("can't convert the file path to local encoding: %s\n"), &file); file_cleanup(&file); data->errors_count++; return; } /* mark the file as obtained from the command line */ add_root_file(data, &file); } #else /* init the file and test for its existence */ if (file_init(&file, path, file_mode | FileInitRunLstat) < 0) { log_error_file_t(&file); file_cleanup(&file); data->errors_count++; return; } 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 & FileIsRoot)); /* check if file is a directory */ if (FILE_ISLIST(file)) { file_list_t list; if (file_list_open(&list, file) < 0) { log_error_file_t(file); continue; } while (file_list_read(&list)) { data->callback(&list.current_file, data->callback_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_error_file_t(file); } } else { /* process a regular file or a dash '-' path */ data->callback(file, data->callback_data); } } } /** * An entry of a list containing content of a directory. */ typedef struct dir_entry { struct dir_entry* next; tstr_t 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, tstr_t filename, unsigned type) { dir_entry* e = (dir_entry*)malloc(sizeof(dir_entry)); if (!e) return NULL; if (filename) { e->filename = rsh_tstrdup(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, tstr_t 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; tpath_t 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_bit = (data->options & FIND_FOLLOW_SYMLINKS ? FileInitRunFstat : FileInitRunLstat); 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->callback(start_dir, data->callback_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; tpath_t dir_path; DIR* dp; struct dirent* de; /* go 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 == NULL); 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_tpath(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_tstrdup(start_dir->real_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, FileIsDir | fstat_bit); /* check if we should skip the directory */ if (res < 0 || !data->callback(&file, data->callback_data)) { if (res < 0 && (options & FIND_LOG_ERRORS)) { log_error_file_t(&file); data->errors_count++; } file_cleanup(&file); continue; } } file_cleanup(&file); /* step into directory */ dp = rsh_topendir(dir_path); if (!dp) continue; insert_at = &dirs_stack; while ((de = readdir(dp)) != NULL) { int res; tpath_t filepath; /* skip the "." and ".." directories */ if (IS_CURRENT_OR_PARENT_DIR(de->d_name)) continue; filepath = make_tpath(dir_path, dirent_get_tname(de)); if (!filepath) continue; res = file_init(&file, filepath, fstat_bit | FileInitUpdatePrintPathSlashes); free(filepath); 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->callback(&file, data->callback_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, dirent_get_tname(de), 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_error_file_t(&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); return 0; } RHash-1.4.3/find_file.h000066400000000000000000000016011425216725100146170ustar00rootroot00000000000000/* 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 (*callback)(file_t* file, int data); int callback_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 */ RHash-1.4.3/hash_check.c000066400000000000000000001361311425216725100147620ustar00rootroot00000000000000/* hash_check.c - functions to parse and verify a hash file contianing message digests */ #include "hash_check.h" #include "calc_sums.h" #include "common_func.h" #include "hash_print.h" #include "output.h" #include "parse_cmdline.h" #include "rhash_main.h" #include "librhash/rhash.h" #include #include /* isspace */ #include #include #include /* size of the buffer to receive a hash file line */ #define LINE_BUFFER_SIZE 4096 /* message digest conversion macros and functions */ #define HEX_TO_DIGIT(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(bits) (((bits) + 4) / 5) #define BASE64_LENGTH(bits) (((bits) + 5) / 6) #define BASE32_BIT_SIZE(length) (((length) * 5) & ~7) #define BASE64_BIT_SIZE(length) (((length) * 6) & ~7) /* pack a character sequence into a single unsigned integer */ #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)) /** * 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++) = HEX_TO_DIGIT(*(str++)); len--; } /* parse the rest - an even-sized hexadecimal string */ for (; len >= 2; len -= 2, str += 2) { *(bin++) = (HEX_TO_DIGIT(str[0]) << 4) | HEX_TO_DIGIT(str[1]); } } /** * Decode an URL-encoded string into the specified buffer. * * @param buffer buffer to decode string into * @param buffer_size buffer size * @param src URL-encoded string * @param src_length length of the string to decode * @return length of the decoded string */ static size_t urldecode(char* buffer, size_t buffer_size, const char* src, size_t src_length) { char* dst = buffer; char* dst_back = dst + buffer_size - 1; const char* src_end = src + src_length; assert(src_length < buffer_size); for (; src < src_end && dst < dst_back; dst++) { *dst = *(src++); /* copy non-escaped characters */ if (*dst == '%') { if (*src == '%') { src++; /* interpret '%%' as single '%' */ } else if (IS_HEX(*src)) { /* decode character from the % form */ int ch = HEX_TO_DIGIT(*src); src++; if (IS_HEX(*src)) { ch = (ch << 4) | HEX_TO_DIGIT(*src); src++; } *dst = (char)ch; } } } assert(dst <= dst_back); *dst = '\0'; /* terminate decoded string */ return (dst - buffer); } /** * Decode a string with escaped characters into the specified buffer. * * @param buffer buffer to decode string into * @param buffer_size buffer size * @param src string with escaped characters * @param src_length length of the source string * @return length of the decoded string */ static size_t unescape_characters(char* buffer, size_t buffer_size, const char* src, size_t src_length) { char* dst = buffer; char* dst_back = dst + buffer_size - 1; const char* src_end = src + src_length; assert(src_length < buffer_size); for (; src < src_end && dst < dst_back; dst++) { *dst = *(src++); /* copy non-escaped characters */ if (*dst == '\\') { if (*src == '\\') { src++; /* interpret '\\' as a single '\' */ } else if (*src == 'n') { *dst = '\n'; src++; } } } assert(dst <= dst_back); *dst = '\0'; /* terminate decoded string */ return (dst - buffer); } /* convert a hash function bit-flag to the index of the bit */ #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 a bit-mask of hash-ids by a length of message digest in bytes. * * @param digest_size length of a binary message digest in bytes * @return mask of hash-ids with given hash length, 0 on fail */ static unsigned hash_bitmask_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 hash_id; for (hash_id = 1; hash_id <= RHASH_ALL_HASHES; hash_id <<= 1) { code = code_digest_size(rhash_get_digest_size(hash_id)); assert(0 <= code && code <= 7); if (code >= 0) mask[code] |= hash_id; } mask[9] = 1; } code = code_digest_size(digest_size); return (code >= 0 ? mask[code] : 0); } /** * Bit flags corresponding to possible formats of a message digest. */ enum FmtBitFlags { FmtHex = 1, FmtBase32LoweCase = 2, FmtBase32UpperCase = 4, FmtBase64 = 8, FmtBase32 = (FmtBase32LoweCase | FmtBase32UpperCase), FmtAll = (FmtHex | FmtBase32 | FmtBase64) }; /** * Test if a character is a hexadecimal/base32 digit. * * @param c the character to test * @return a combination of Fmt* bits */ static int test_hash_char(char c) { static unsigned char char_bits[80] = { 8, 0, 0, 0, 8, 9, 9, 15, 15, 15, 15, 15, 15, 9, 9, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }; c -= '+'; return ((unsigned)c <= 80 ? char_bits[(unsigned)c] : 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 message digest * @return type of detected hash as combination of Fmt* flags */ static int detect_hash_type(char** ptr, char* end, int* p_len) { char* p = *ptr; size_t len = 0; size_t eq_num = 0; int char_type = 0; int next_type = FmtAll; if (p < end) { /* search forward (but no more then 129 symbols) */ if ((end - p) >= 129) end = p + 129; for (; p <= end && (next_type &= test_hash_char(*p)); len++, p++) char_type = next_type; if ((char_type & FmtBase64) && *p == '=') { char_type = FmtBase64; for (; *p == '=' && p <= end; eq_num++, p++); } } else { /* search backward (but no more then 129 symbols) */ if ((p - end) >= 129) end = p - 129; for (; p > end && p[-1] == '='; eq_num++, p--) char_type = FmtBase64; for (; p > end && (next_type &= test_hash_char(p[-1])); len++, p--) char_type = next_type; } if ((char_type & FmtBase64) != 0) { size_t hash_len = (len * 6) & ~7; if (eq_num > 3 || ((len + eq_num) & 3) || len != (hash_len + 5) / 6) char_type &= ~FmtBase64; } *ptr = p; *p_len = (int)len; return char_type; } /** * Check if a message digest of the specified bit length is supported by the program. * * @param length the bit length of a binary message digest value * @return 1 if a message digest of the specified bit length is supported, 0 otherwise */ static int is_acceptable_bit_length(int length) { if ((length & 31) == 0 && length <= 512) { int pow = get_ctz(length >> 5); int code = ((length >> (pow + 6)) << 3) | pow; return (code < 32 && ((1 << code) & 0x101061d)); } return 0; } /** * Test the given substring to be a hexadecimal or base32 * message digest of one of the supported hash functions. * * @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 message digest * @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 & FmtHex) && is_acceptable_bit_length(len * 4)) hash_type |= FmtHex; if ((char_type & FmtBase32) && is_acceptable_bit_length(BASE32_BIT_SIZE(len))) hash_type |= FmtBase32; if ((char_type & FmtBase64) && is_acceptable_bit_length(BASE64_BIT_SIZE(len))) hash_type |= FmtBase64; if (hash_type != 0) *p_len = len; return hash_type; } enum HashNameMatchModes { ExactMatch, PrefixMatch }; /** * Detect a hash-function id by its BSD name. * * @param name an uppercase string, a possible name of a hash-function * @param length length of the name string * @param match_mode whether the name parameter must match the name of a * known hash algorithm exactly, or trailing chars are * allowed. * @return id of hash function if found, zero otherwise */ static unsigned bsd_hash_name_to_id(const char* name, unsigned length, enum HashNameMatchModes match_mode) { #define code2mask_size (19 * 2) static unsigned code2mask[code2mask_size] = { FOURC2U('A', 'I', 'C', 'H'), RHASH_AICH, FOURC2U('B', 'L', 'A', 'K'), (RHASH_BLAKE2S | RHASH_BLAKE2B), FOURC2U('B', 'T', 'I', 'H'), RHASH_BTIH, FOURC2U('C', 'R', 'C', '3'), (RHASH_CRC32 | RHASH_CRC32C), FOURC2U('E', 'D', '2', 'K'), RHASH_ED2K, FOURC2U('E', 'D', 'O', 'N'), (RHASH_EDONR256 | RHASH_EDONR512), FOURC2U('G', 'O', 'S', 'T'), (RHASH_GOST12_256 | RHASH_GOST12_512 | RHASH_GOST94 | RHASH_GOST94_CRYPTOPRO), FOURC2U('H', 'A', 'S', '1'), RHASH_HAS160, FOURC2U('M', 'D', '4', 0), RHASH_MD4, FOURC2U('M', 'D', '5', 0), RHASH_MD5, FOURC2U('R', 'I', 'P', 'E'), RHASH_RIPEMD160, FOURC2U('S', 'H', 'A', '1'), RHASH_SHA1, FOURC2U('S', 'H', 'A', '2'), (RHASH_SHA224 | RHASH_SHA256), FOURC2U('S', 'H', 'A', '3'), (RHASH_SHA384 | RHASH_SHA3_224 | RHASH_SHA3_256 | RHASH_SHA3_384 | RHASH_SHA3_512), FOURC2U('S', 'H', 'A', '5'), RHASH_SHA512, FOURC2U('S', 'N', 'E', 'F'), (RHASH_SNEFRU128 | RHASH_SNEFRU256), FOURC2U('T', 'I', 'G', 'E'), RHASH_TIGER, FOURC2U('T', 'T', 'H', 0), RHASH_TTH, FOURC2U('W', 'H', 'I', 'R'), RHASH_WHIRLPOOL }; unsigned code, i, hash_mask, hash_id; char fourth_char; if (length < 3) return 0; fourth_char = (name[3] != '-' ? name[3] : name[4]); code = FOURC2U(name[0], name[1], name[2], fourth_char); /* quick fix to detect "RMD160" as RIPEMD160 */ if (code == FOURC2U('R', 'M', 'D', '1')) return (length == 6 && name[4] == '6' && name[5] == '0' ? RHASH_RIPEMD160 : 0); for (i = 0; code2mask[i] != code; i += 2) if (i >= (code2mask_size - 2)) return 0; hash_mask = code2mask[i + 1]; i = get_ctz(hash_mask); if (length <= 4) { assert((hash_mask & (hash_mask - 1)) == 0); return (length == strlen(hash_info_table[i].name) ? hash_mask : 0); } /* look for the hash_id in the hash_mask */ for (hash_id = 1 << i; hash_id && hash_id <= hash_mask; i++, hash_id <<= 1) { const char* a; const char* b; if ((hash_id & hash_mask) == 0) continue; assert(length > 4); assert(strlen(hash_info_table[i].name) >= 4); /* check the name tail, starting from &name[3] to detect names like "SHA-1" or "SHA256" */ for (a = hash_info_table[i].name + 3, b = name + 3; *a; a++, b++) { if (*a == *b) continue; else if (*a == '-') b--; else if (*b == '-') a--; else break; } if (!*a && (match_mode == PrefixMatch || !*b)) return hash_id; } return 0; } /** * Detect ASCII-7 white spaces (0x09=\t, 0x0a=\n, 0x0b=\v, 0x0c=\f, 0x0d=\r, 0x20=' '). * Note that standard C function isspace() is locale specific and * detects Unicode spaces, like U+00A0. * * @param ch character to check * @return non-zero if ch is space, zero otherwise */ static int rhash_isspace(char ch) { unsigned code = (unsigned)(ch - 9); return (code < 0x18 && ((1u << code) & 0x80001f)); } /** * Extended hash parser data. */ struct hash_parser_ext { struct hash_parser hp; file_t* hash_file; file_t parent_dir; FILE* fd; uint64_t expected_hash_mask; unsigned is_sfv; unsigned line_number; char buffer[LINE_BUFFER_SIZE]; }; /** * Information about found token. */ struct hash_token { char* begin; /* start of the buffer to parse */ char* end; /* end of the buffer to parse */ file_t* p_parsed_path; struct hash_parser_ext* parser; struct hash_value* p_hashes; unsigned expected_hash_id; int hash_type; }; /** * Bit-flags for the fstat_path_token(). */ enum FstatPathBitFlags { PathUrlDecode = 1, PathUnescape = 2 }; static int fstat_path_token(struct hash_token* token, char* path, size_t path_length, int is_url); /** * Bit-flags for the match_hash_tokens(). */ enum MhtOptionsBitFlags { MhtFstatPath = 1, MhtAllowOneHash = 2, MhtAllowEscapedPath = 4 }; /** * Constants returned by match_hash_tokens() and some other functions. */ enum MhtResults { ResFailed = 0, ResAllMatched = 1, ResPathNotExists = 2, ResOneHashDetected = 3 }; /** * Parse the buffer pointed by token->begin, into tokens specified by format string. * The format string can contain the following special characters: * '\1' - BSD hash function name, '\2' - any hash, '\3' - specified hash, * '\4' - an URL-encoded file name, '\5' - a file size, * '\6' - a required space or line 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 token->begin and token->end pointers on success. * * @param token the structure to store parsed tokens info * @param format the format string * @param bit_flags MhtFstatPath flag to run fstat on parsed path, * MhtAllowOneHash to allow line containing one message digest without a file path * @return one of the MhtResults constants */ static int match_hash_tokens(struct hash_token* token, const char* format, unsigned bit_flags) { int backward = 0; char buf[20]; const char* fend = strchr(format, '\0'); char* begin = token->begin; char* end = token->end; char* url_path = 0; size_t url_length; struct hash_parser* hp = &token->parser->hp; struct hash_value hv; int unsaved_hashval = 0; int unescape_flag = 0; memset(&hv, 0, sizeof(hv)); if ((bit_flags & MhtAllowEscapedPath) && (opt.flags & OPT_NO_PATH_ESCAPING) == 0 && begin[0] == '\\' && !(begin[1] == '\\' && begin[2] == '?' && begin[3] == '\\')) { begin++; unescape_flag = PathUnescape; } while (format < fend) { const char* search_str; int 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 ResFailed; if (0 != memcmp(search_str, (backward ? end - len : begin), len)) return ResFailed; if (backward) end -= len; else begin += len; continue; } assert(len == 0); /* find substring specified by single character */ switch (*search_str) { case '\1': /* parse BSD 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 ResFailed; /* limit name length */ buf[len] = toupper(begin[len]); } buf[len] = '\0'; token->expected_hash_id = bsd_hash_name_to_id(buf, len, ExactMatch); if (!token->expected_hash_id) return ResFailed; token->hash_type = FmtAll; begin += len; break; case '\2': case '\3': if (backward) { hv.format = test_hash_string(&end, begin, &len); hv.offset = (unsigned short)(end - hp->line_begin); } else { hv.offset = (unsigned short)(begin - hp->line_begin); hv.format = test_hash_string(&begin, end, &len) & token->hash_type; } if (!hv.format) return ResFailed; if (*search_str == '\3') { /* verify message digest type */ int bit_length = rhash_get_digest_size(token->expected_hash_id) * 8; hv.format &= token->hash_type; if ((len * 4) != bit_length) hv.format &= ~FmtHex; if (len != BASE32_LENGTH(bit_length)) hv.format &= ~FmtBase32; if (len != BASE64_LENGTH(bit_length)) hv.format &= ~FmtBase64; if (!hv.format) return ResFailed; hv.hash_id = token->expected_hash_id; } else hv.hash_id = 0; hv.length = (unsigned char)len; unsaved_hashval = 1; break; case '\4': /* get URL-encoded name */ url_path = begin; url_length = strcspn(begin, "?&|"); if (url_length == 0) return ResFailed; /* empty name */ begin += 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 ResFailed; else { hp->file_size = file_size; hp->bit_flags |= HpHasFileSize; } break; case '\6': 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' verify (len > 0 || (MhtAllowOneHash is set && begin == end)) */ if (!(bit_flags & MhtAllowOneHash) || begin < end) return ResFailed; } break; case '$': backward = 1; /* switch to parsing string backward */ break; default: if ((backward ? *(--end) : *(begin++)) != *search_str) return ResFailed; } } if (unsaved_hashval && hp->hashes_num < HP_MAX_HASHES) { token->p_hashes[hp->hashes_num++] = hv; } token->begin = begin; token->end = end; if ((bit_flags & MhtAllowOneHash) != 0 && hp->hashes_num == 1 && begin == end) { struct hash_parser_ext* const parser = token->parser; file_t* parsed_path = &parser->hp.parsed_path; if (file_modify_path(parsed_path, parser->hash_file, NULL, FModifyRemoveExtension) < 0) { /* note: trailing whitespaces were removed from line by hash_parser_parse_line() */ return ResFailed; } if ((bit_flags & MhtFstatPath) != 0 && file_stat(parsed_path, 0) < 0) hp->parsed_path_errno = errno; return ResOneHashDetected; } if ((bit_flags & MhtFstatPath) != 0) { int fstat_res; if (url_path != 0) { fstat_res = fstat_path_token(token, url_path, url_length, PathUrlDecode); } else { size_t path_length; if (begin[0] == '*' && unescape_flag == 0) begin++; path_length = end - begin; fstat_res = fstat_path_token(token, begin, path_length, unescape_flag); } if (fstat_res < 0) return ResPathNotExists; } return ResAllMatched; } /** * Fstat given file path. Optionally prepend it, if needed, by parent directory. * Depending on bit_flags, the path is url-decoded or decoded using escape sequences. * Fstat result is stored into token->p_parsed_path. * * @param token current tokens parsing context * @param str pointer to the path start * @param str_length length of the path * @param bit_flags PathUrlDecode or PathUnescape to decode path * @return 0 on success, -1 on fstat fail */ static int fstat_path_token(struct hash_token* token, char* str, size_t str_length, int bit_flags) { static char buffer[LINE_BUFFER_SIZE]; file_t* parent_dir = &token->parser->parent_dir; unsigned init_flags = (FILE_IS_IN_UTF8(token->parser->hash_file) ? FileInitRunFstat | FileInitUtf8PrintPath : FileInitRunFstat); char* path = (bit_flags == 0 ? str : buffer); size_t path_length = (bit_flags == 0 ? str_length : (bit_flags & PathUrlDecode ? urldecode(buffer, LINE_BUFFER_SIZE, str, str_length) : unescape_characters(buffer, LINE_BUFFER_SIZE, str, str_length))); int res; int is_absolute = IS_PATH_SEPARATOR(path[0]); char saved_char = path[path_length]; path[path_length] = '\0'; IF_WINDOWS(is_absolute = is_absolute || (path[0] && path[1] == ':')); if (is_absolute || !parent_dir->real_path) parent_dir = NULL; if ((bit_flags & PathUnescape) != 0) init_flags |= FileInitUseRealPathAsIs; res = file_init_by_print_path(token->p_parsed_path, parent_dir, path, init_flags); if (res < 0 && token->p_parsed_path == &token->parser->hp.parsed_path) token->parser->hp.parsed_path_errno = errno; path[path_length] = saved_char; return res; } /** * Cleanup token context and fill hash_mask of the parser. * * @param token token parsing context * @return ResPathNotExists if path has not been found, ResAllMatched otherwise */ static int finalize_parsed_data(struct hash_token* token) { int i; struct hash_parser* const parser = &token->parser->hp; if (token->p_parsed_path != &parser->parsed_path) { file_cleanup(&parser->parsed_path); parser->parsed_path = *token->p_parsed_path; } if (FILE_ISBAD(&parser->parsed_path) || !parser->parsed_path.real_path) return ResPathNotExists; if (token->p_hashes != parser->hashes) { assert(parser->hashes_num == 1); parser->hashes[0] = token->p_hashes[0]; } /* post-process parsed message digests */ for (i = 0; i < parser->hashes_num; i++) { struct hash_value* hv = &parser->hashes[i]; char* hash_str = parser->line_begin + hv->offset; hash_str[hv->length] = '\0'; /* terminate the message digest */ if (hv->hash_id == 0) { /* calculate bit-mask of hash function ids */ unsigned mask = 0; if (hv->format & FmtHex) { mask |= hash_bitmask_by_digest_size(hv->length >> 1); } if (hv->format & FmtBase32) { assert(((hv->length * 5 / 8) & 3) == 0); mask |= hash_bitmask_by_digest_size(BASE32_BIT_SIZE(hv->length) / 8); } if (hv->format & FmtBase64) { mask |= hash_bitmask_by_digest_size(BASE64_BIT_SIZE(hv->length) / 8); } assert(mask != 0); if ((mask & token->parser->expected_hash_mask) != 0) mask &= token->parser->expected_hash_mask; hv->hash_id = mask; } parser->hash_mask |= hv->hash_id; } return ResAllMatched; } /** * Parse the rest of magnet link. * * @param token tokens parsing context * @return ResAllMatched on success, ResFailed on a bad magnet link */ static int parse_magnet_url(struct hash_token* token) { char* url_path = 0; size_t url_length; /* loop by magnet link parameters */ while (1) { char* next = strchr(token->begin, '&'); char* param_end = (next ? next++ : token->end); char* hf_end; if ((token->begin += 3) < param_end) { switch (THREEC2U(token->begin[-3], token->begin[-2], token->begin[-1])) { case THREEC2U('d', 'n', '='): /* URL-encoded file path */ url_path = token->begin; url_length = param_end - token->begin; break; case THREEC2U('x', 'l', '='): /* file size */ if (!match_hash_tokens(token, "\5", 0)) return ResFailed; if (token->begin != param_end) return ResFailed; break; case THREEC2U('x', 't', '='): /* a file hash */ { int i; /* find last ':' character (hash name can be complex like tree:tiger) */ for (hf_end = param_end - 1; *hf_end != ':' && hf_end > token->begin; hf_end--); /* test for the "urn:" string */ if ((token->begin += 4) >= hf_end) return ResFailed; if (FOURC2U(token->begin[-4], token->begin[-3], token->begin[-2], token->begin[-1]) != FOURC2U('u', 'r', 'n', ':')) return ResFailed; /* 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 - token->begin; if (strncmp(token->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"), token->begin); } return ResFailed; } token->begin = hf_end + 1; token->expected_hash_id = 1 << i; token->hash_type = (FmtHex | FmtBase32); if (!match_hash_tokens(token, "\3", 0)) return ResFailed; if (token->begin != param_end) return ResFailed; break; } /* note: this switch () skips all unknown parameters */ } } if (next) token->begin = next; else break; } if (!url_path || token->parser->hp.hashes_num == 0) return ResFailed; fstat_path_token(token, url_path, url_length, PathUrlDecode); return finalize_parsed_data(token); } /** * Parse the rest of ed2k link. * * @param token the structure to store parsed tokens info * @return ResAllMatched on success, ResFailed on a bad ed2k link */ static int parse_ed2k_link(struct hash_token* token) { token->expected_hash_id = RHASH_ED2K; token->hash_type = FmtHex; if (!match_hash_tokens(token, "\4|\5|\3|", MhtFstatPath)) return ResFailed; /* try to parse optional AICH hash */ token->expected_hash_id = RHASH_AICH; token->hash_type = (FmtHex | FmtBase32); /* AICH is usually base32-encoded*/ match_hash_tokens(token, "h=\3|", 0); return finalize_parsed_data(token); } /** * 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 parser structure to store parsed message digests, file path and file size * @param check_eol boolean flag meaning that '\n' at the end of the line is required * @return non-zero on success (ResAllMatched, ResOneHashDetected, ResPathNotExists), * ResFailed if couldn't parse the line */ static int parse_hash_file_line(struct hash_parser_ext* parser, int check_eol) { struct hash_token token; char* line = parser->hp.line_begin; char* line_end = strchr(line, '\0'); int res; assert(line[0] != '\0'); /* return if EOL not found at the end of the line */ if (line_end[-1] != '\n' && check_eol) return ResFailed; /* trim line manually, without str_trim(), cause we'll need line_end later */ while (rhash_isspace(line_end[-1]) && line_end > line) *(--line_end) = 0; /* skip white spaces at the start of the line */ while (rhash_isspace(*line)) line++; memset(&token, 0, sizeof(token)); token.begin = line; token.end = line_end; token.parser = parser; token.p_parsed_path = &parser->hp.parsed_path; token.p_hashes = parser->hp.hashes; memset(&parser->hp, 0, sizeof(parser->hp)); parser->hp.line_begin = line; parser->hp.file_size = (uint64_t)-1; /* check for a minimum acceptable message digest length */ if ((line + 8) > line_end) return ResFailed; if (strncmp(token.begin, "ed2k://|file|", 13) == 0) { token.begin += 13; return parse_ed2k_link(&token); } if (strncmp(token.begin, "magnet:?", 8) == 0) { token.begin += 8; return parse_magnet_url(&token); } /* check for BSD-formatted line has been processed */ res = match_hash_tokens(&token, "\1 ( $ ) = \3", MhtFstatPath | MhtAllowEscapedPath); if (res != ResFailed) return finalize_parsed_data(&token); token.hash_type = FmtAll; { const unsigned is_sfv_format = parser->is_sfv; unsigned valid_direction = 0; unsigned state; unsigned token_flags = (MhtFstatPath | MhtAllowEscapedPath | MhtAllowOneHash); struct file_t secondary_path; struct hash_token secondary_token; struct hash_token *cur_token = &token; struct hash_value secondary_hash[1]; memset(&secondary_path, 0, sizeof(secondary_path)); memcpy(&secondary_token, &token, sizeof(token)); secondary_token.p_hashes = secondary_hash; /* parse one hash from each line end */ for (state = 0; state < 2; state++) { const unsigned is_backward = (state ^ is_sfv_format); const char* token_format = (is_backward ? "$\6\2" : "\2\6"); int res = match_hash_tokens(cur_token, token_format, token_flags); if (res == ResAllMatched || res == ResOneHashDetected) { return finalize_parsed_data(cur_token); } else if (res == ResPathNotExists) { assert(parser->hp.hashes_num == 1); valid_direction |= (1 << state); /* mark the current parsing direction as valid */ if (token.p_parsed_path == &parser->hp.parsed_path) token.p_parsed_path = secondary_token.p_parsed_path = &secondary_path; cur_token = &secondary_token; parser->hp.hashes_num = 0; } token_flags &= ~MhtAllowOneHash; } token_flags = MhtFstatPath; /* parse the rest of hashes */ for (state = 0; state < 2; state++) { if ((valid_direction & (1 << state)) != 0) { const unsigned is_backward = (state ^ is_sfv_format); const char* token_format = (is_backward ? "$\6\2" : "\2\6"); /* restore parsing state and a parsed hash */ parser->hp.hashes_num = 1; if (state == 1 && valid_direction == 3) { token.begin = secondary_token.begin; token.end = secondary_token.end; token.p_hashes[0] = secondary_token.p_hashes[0]; } /* allow FmtBase64 only if the first hash can be interpreted only as Base64-encoded */ token.hash_type = (token.hash_type & ~FmtBase64) | (token.p_hashes[0].format == FmtBase64 ? FmtBase64 : 0); for (;;) { int res = match_hash_tokens(&token, token_format, token_flags); assert(res != ResOneHashDetected); if (res == ResAllMatched) return finalize_parsed_data(&token); else if (res == ResFailed) break; } } } file_cleanup(&secondary_path); if (token.p_parsed_path != &parser->hp.parsed_path) return ResPathNotExists; } return ResFailed; /* could not parse line */ } /** * Bit-flags for the hash. */ enum CompareHashBitFlags { CompareHashCaseSensitive = 1, CompareHashReversed = 2 }; /** * Compare two message digests. For base64 encoding, the case-sensitive comparasion is done. * For hexadecimal or base32 encodings, the case-insensitive match occurs. * For the GOST94 hash, the additional reversed case-insensitive match is done. * * @param calculated_hash the calculated message digest, for the hex/base32 the value must be in upper case * @param expected a message digest from a hash file to match against * @param length length of the message digests * @param comparision_mode 0, CompareHashCaseSensitive or CompareHashReversed comparision mode * @return 1 if message digests match, 0 otherwise */ static int is_hash_string_equal(const char* calculated_hash, const char* expected, size_t length, int comparision_mode) { if (comparision_mode == CompareHashCaseSensitive) return (memcmp(calculated_hash, expected, length) == 0); { /* case-insensitive comparision of a hexadecimal or a base32 hash */ size_t i = 0; for (; i < length && (calculated_hash[i] == (expected[i] >= 'a' ? expected[i] & ~0x20 : expected[i])); i++); if (i == length) return 1; } if (comparision_mode == CompareHashReversed) { /* case-insensitive comparision of reversed gost hash */ size_t i = 0, last = length - 1; for (; i < length && (calculated_hash[last - (i ^ 1)] == (expected[i] >= 'a' ? expected[i] & ~0x20 : expected[i])); i++); return (i == length); } 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 checksum */ 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 message digests against original values. * Also verify the file size and embedded CRC32 if present. * The HP_WRONG_* bits are set in the parser->flags field on fail. * * @param parser 'original' parsed message digests, to verify against * @param ctx the rhash context containing calculated message digests * @return 1 on successfull verification, 0 on message digests mismatch */ static int do_hash_sums_match(struct hash_parser* parser, struct rhash_context* ctx) { unsigned unverified_mask; unsigned hash_id; unsigned printed; char hex[132], base32[104], base64[88]; int j; /* verify file size, if present */ if ((parser->bit_flags & HpHasFileSize) != 0 && parser->file_size != ctx->msg_size) parser->bit_flags |= HpWrongFileSize; /* verify embedded CRC32 checksum, if present */ if ((parser->bit_flags & HpHasEmbeddedCrc32) != 0 && get_crc32(ctx) != parser->embedded_crc32) parser->bit_flags |= HpWrongEmbeddedCrc32; /* return if nothing else to verify */ if (parser->hashes_num == 0) return !HP_FAILED(parser->bit_flags); unverified_mask = (1 << parser->hashes_num) - 1; for (hash_id = 1; hash_id <= RHASH_ALL_HASHES && unverified_mask; hash_id <<= 1) { if ((parser->hash_mask & hash_id) == 0) continue; printed = 0; for (j = 0; j < parser->hashes_num; j++) { struct hash_value* hv = &parser->hashes[j]; char* calculated_hash; char* expected_hash; int bit_length; int comparision_mode; /* skip already verified message digests and message digests of different size */ if (!(unverified_mask & (1 << j)) || !(hv->hash_id & hash_id)) continue; comparision_mode = 0; bit_length = rhash_get_digest_size(hash_id) * 8; if ((hv->length * 4) == bit_length) { assert(hv->format & FmtHex); assert(hv->length <= 128); /* print hexadecimal value, if not printed yet */ if ((printed & FmtHex) == 0) { rhash_print(hex, ctx, hash_id, RHPR_HEX | RHPR_UPPERCASE); printed |= FmtHex; } calculated_hash = hex; if ((hash_id & (RHASH_GOST94 | RHASH_GOST94_CRYPTOPRO)) != 0) comparision_mode = CompareHashReversed; } else if (hv->length == BASE32_LENGTH(bit_length)) { assert(hv->format & FmtBase32); assert(hv->length <= 103); /* print base32 value, if not printed yet */ if ((printed & FmtBase32) == 0) { rhash_print(base32, ctx, hash_id, RHPR_BASE32 | RHPR_UPPERCASE); printed |= FmtBase32; } calculated_hash = base32; } else { assert(hv->format & FmtBase64); assert(hv->length == BASE64_LENGTH(bit_length)); assert(hv->length <= 86); /* print base32 value, if not printed yet */ if ((printed & FmtBase64) == 0) { rhash_print(base64, ctx, hash_id, RHPR_BASE64); printed |= FmtBase64; } calculated_hash = base64; comparision_mode = CompareHashCaseSensitive; } expected_hash = parser->line_begin + hv->offset; if (!is_hash_string_equal(calculated_hash, expected_hash, hv->length, comparision_mode)) continue; unverified_mask &= ~(1 << j); /* mark the j-th message digest as verified */ parser->found_hash_ids |= hash_id; /* end the loop if all message digests were successfully verified */ if (unverified_mask == 0) break; } } parser->wrong_hashes = unverified_mask; if (unverified_mask != 0) parser->bit_flags |= HpWrongHashes; return !HP_FAILED(parser->bit_flags); } /** * Verify message digests of the file. * In a case of fail, the error will be logged. * * @param file the file, which hashes are verified * @param hp parsed hash file line * @return 0 on success, 1 on message digests mismatch, * -1/-2 on input/output error */ static int verify_hashes(file_t* file, struct hash_parser* hp) { struct file_info info; timedelta_t timer; int res = 0; if (FILE_ISBAD(file) && (opt.flags & OPT_IGNORE_MISSING) != 0) return -1; memset(&info, 0, sizeof(info)); info.file = file; info.sums_flags = hp->hash_mask; info.hp = hp; /* initialize percents output */ if (init_percents(&info) < 0) { log_error_file_t(&rhash_data.out_file); return -2; } rsh_timer_start(&timer); if (FILE_ISBAD(info.file)) { /* restore errno */ errno = hp->parsed_path_errno; res = -1; } else { res = calc_sums(&info); } if (res < 0) { /* report file error */ int output_res = finish_percents(&info, -1); return (output_res < 0 ? -2 : -1); } info.time = rsh_timer_stop(&timer); if (rhash_data.stop_flags) { report_interrupted(); return 0; } if ((opt.flags & OPT_EMBED_CRC) && find_embedded_crc32(info.file, &hp->embedded_crc32)) { hp->bit_flags |= HpHasEmbeddedCrc32; assert(hp->hash_mask & RHASH_CRC32); } if (!do_hash_sums_match(hp, info.rctx)) res = 1; if (finish_percents(&info, res) < 0) res = -2; if ((opt.flags & OPT_SPEED) && info.sums_flags != 0) print_file_time_stats(&info); return res; } /** * Verify the file against the CRC32 checksum embedded into its filename. * * @param file the file to verify * @return 0 on success, -1 on input error, -2 on results output error */ int check_embedded_crc32(file_t* file) { int res = 0; unsigned crc32; struct hash_parser hp; if (find_embedded_crc32(file, &crc32)) { /* initialize file_info structure */ memset(&hp, 0, sizeof(hp)); hp.hash_mask = RHASH_CRC32; hp.bit_flags = HpHasEmbeddedCrc32; hp.embedded_crc32 = crc32; res = verify_hashes(file, &hp); if (res >= -1 && fflush(rhash_data.out) < 0) { log_error_file_t(&rhash_data.out_file); res = -2; } else if (!rhash_data.stop_flags) { if (res == 0) rhash_data.ok++; else if (res == -1 && errno == ENOENT) rhash_data.miss++; rhash_data.processed++; } } else { /* TRANSLATORS: sample filename with embedded CRC32: file_[A1B2C3D4].mkv */ log_warning_msg_file_t(_("file name doesn't contain a CRC32: %s\n"), file); return -1; } return res; } /** * Structure to store file extension and its length. */ struct file_ext { size_t length; char buffer[20]; }; /** * Extract file extension from given file. * * @param fe buffer to recieve file extension * @param file the file to process * @return 1 on success, 0 on fail */ static int extract_uppercase_file_ext(struct file_ext* fe, file_t* file) { size_t length; char* buffer; const char* basename = file_get_print_path(file, FPathUtf8 | FPathBaseName); const char* ext; if (!basename) return 0; ext = strrchr(basename, '.'); if (!ext) /* If there is no extension, then consider the whole filename * as extension, so callers can do the right thing when * encountering a file called e.g. "SHA256". */ ext = basename; else ext++; buffer = fe->buffer; for (length = 0; '-' <= ext[length] && ext[length] <= 'z'; length++) { if (length >= sizeof(fe->buffer)) return 0; /* limit hash name length */ buffer[length] = toupper(ext[length]); } if (ext[length] != '\0') return 0; buffer[length] = '\0'; fe->length = length; return 1; } /** * Detect SFV format and hash functions by the hash file extension. * * @param hash_file the file, which extension is checked * @param parser the parser to store hash_mask and sfv flag into */ static void set_flags_by_hash_file_extension(file_t* hash_file, struct hash_parser_ext* parser) { struct file_ext ext; unsigned hash_mask; int is_sfv; if(HAS_OPTION(OPT_NO_DETECT_BY_EXT) || !extract_uppercase_file_ext(&ext, hash_file)) return; hash_mask = (opt.sum_flags ? opt.sum_flags : bsd_hash_name_to_id(ext.buffer, ext.length, PrefixMatch)); is_sfv = (ext.length == 3 && memcmp(ext.buffer, "SFV", 3) == 0); if (parser != NULL) { parser->expected_hash_mask = hash_mask; parser->is_sfv = is_sfv; } if (IS_MODE(MODE_UPDATE)) { opt.sum_flags = hash_mask; if (!opt.fmt) rhash_data.is_sfv = is_sfv; } } /** * Close and cleanup hash parser. * * @param parser the hash parser to close * @return 0 on success, -1 on fail with error code stored in errno */ static int hash_parser_close(struct hash_parser* hp) { struct hash_parser_ext* parser = (struct hash_parser_ext*)hp; int res = 0; if (!parser) return 0; file_cleanup(&parser->parent_dir); file_cleanup(&parser->hp.parsed_path); if (parser->fd != stdin) res = fclose(parser->fd); free(parser); return res; } /** * Open a hash file and create a hash_parser for it. * * @param hash_file the hash file to open * @param chdir true if function should emulate chdir to the parent directory of the hash file * @return created hash_parser on success, NULL on fail with error code stored in errno */ static struct hash_parser* hash_parser_open(file_t* hash_file, int chdir) { FILE* fd; struct hash_parser_ext* parser; /* open file or prepare file descriptor */ if (FILE_ISSTDIN(hash_file)) fd = stdin; else if ( !(fd = file_fopen(hash_file, FOpenRead | FOpenBin) )) return NULL; /* allocate and initialize parser */ parser = (struct hash_parser_ext*)rsh_malloc(sizeof(struct hash_parser_ext)); memset(parser, 0, sizeof(struct hash_parser_ext)); parser->hash_file = hash_file; parser->fd = fd; parser->expected_hash_mask = opt.sum_flags; parser->is_sfv = rhash_data.is_sfv; /* extract the parent directory of the hash file, if required */ if (chdir) file_modify_path(&parser->parent_dir, hash_file, NULL, FModifyGetParentDir); if((opt.flags & OPT_NO_DETECT_BY_EXT) == 0) set_flags_by_hash_file_extension(hash_file, parser); return &parser->hp; } /** * Constants returned by hash_parser_process_line() function. */ enum ProcessLineResults { ResReadError = -1, ResStopParsing = 0, ResSkipLine = 1, ResParsedLine = 2, ResFailedToParse = 3 }; /** * Parse one line of the openned hash file. * * @param hp parser processing the hash file * @return one of the ProcessLineResults constants */ static int hash_parser_process_line(struct hash_parser* hp) { struct hash_parser_ext* parser = (struct hash_parser_ext*)hp; char *line = parser->buffer; if (!fgets(parser->buffer, sizeof(parser->buffer), parser->fd)) { if (ferror(parser->fd)) { log_error_file_t(parser->hash_file); return ResReadError; } return ResStopParsing; } parser->line_number++; if (parser->line_number > 1) file_cleanup(&hp->parsed_path); /* skip unicode BOM, if found */ if (STARTS_WITH_UTF8_BOM(line)) { line += 3; if (parser->line_number == 1) parser->hash_file->mode |= FileContentIsUtf8; } if (is_binary_string(line)) { const char* message = (IS_MODE(MODE_UPDATE) ? /* TRANSLATORS: it's printed, when a non-text hash file is encountered in --update mode */ _("skipping binary file") : _("file is binary")); log_msg("%s:%u: %s\n", file_get_print_path(parser->hash_file, FPathPrimaryEncoding | FPathNotNull), parser->line_number, message); hp->bit_flags |= HpIsBinaryFile; return ResReadError; } /* silently skip comments and empty lines */ if (*line == '\0' || *line == '\r' || *line == '\n' || IS_COMMENT(*line)) return ResSkipLine; hp->line_begin = line; if (!parse_hash_file_line(parser, !feof(parser->fd))) { log_msg(_("%s:%u: can't parse line \"%s\"\n"), file_get_print_path(parser->hash_file, FPathPrimaryEncoding | FPathNotNull), parser->line_number, parser->hp.line_begin); return ResFailedToParse; } errno = 0; return ResParsedLine; } /** * Parse content of the openned hash file. * * @param parser hash parser, controlling parsing process * @param files pointer to the vector to load parsed file paths into * @return HashFileBits bit mask on success, -1 on input error, -2 on results output error */ static int hash_parser_process_file(struct hash_parser *parser, file_set* files) { timedelta_t timer; uint64_t time; int parsing_res; int result = (HashFileExist | HashFileIsEmpty); if (IS_MODE(MODE_CHECK) && print_verifying_header(((struct hash_parser_ext*)parser)->hash_file) < 0) { log_error_file_t(&rhash_data.out_file); return -2; } rsh_timer_start(&timer); /* initialize statistics */ rhash_data.processed = rhash_data.ok = rhash_data.miss = 0; rhash_data.total_size = 0; while((parsing_res = hash_parser_process_line(parser)) > ResStopParsing) { result &= ~HashFileIsEmpty; /* skip comments and empty lines */ if (parsing_res == ResSkipLine) continue; if (parsing_res == ResFailedToParse) { result |= HashFileHasUnparsedLines; } else { if (files) { /* put UTF8-encoded file path into the file set */ const char* path = file_get_print_path(&parser->parsed_path, FPathUtf8); if (path) file_set_add_name(files, path); } if (IS_MODE(MODE_CHECK)) { /* verify message digests of the file */ int res = verify_hashes(&parser->parsed_path, parser); if (res >= -1 && fflush(rhash_data.out) < 0) { log_error_file_t(&rhash_data.out_file); return -2; } if (rhash_data.stop_flags || res <= -2) { return res; /* stop on fatal error */ } /* update statistics */ if (res == 0) rhash_data.ok++; else { if (FILE_ISBAD(&parser->parsed_path) && (opt.flags & OPT_IGNORE_MISSING) != 0) continue; if (res == -1 && errno == ENOENT) { result |= HashFileHasMissedFiles; rhash_data.miss++; } else result |= HashFileHasWrongHashes; } } } rhash_data.processed++; } if (parsing_res == ResReadError) return -1; time = rsh_timer_stop(&timer); if (IS_MODE(MODE_CHECK)) { /* check for a hash file errors */ if (result >= 0 && (result & (HashFileHasWrongHashes | HashFileHasMissedFiles | HashFileHasUnparsedLines)) != 0) rhash_data.non_fatal_error = 1; if (result >= -1 && (print_verifying_footer() < 0 || print_check_stats() < 0)) { log_error_file_t(&rhash_data.out_file); result = -2; } if (HAS_OPTION(OPT_SPEED) && !IS_MODE(MODE_UPDATE) && rhash_data.processed > 1) print_time_stats(time, rhash_data.total_size, 1); } return result; } /** * Open the given hash file and process its content. * * @param hash_file the hash file to process * @param files pointer to the vector to load parsed file paths into * @param chdir true if function should emulate chdir to the parent directory of the hash file * @return HashFileBits bit mask on success, -1 on input error, -2 on results output error */ static int process_hash_file(file_t* hash_file, file_set* files, int chdir) { int result; struct hash_parser *parser = hash_parser_open(hash_file, chdir); if (!parser) { /* in the update mode, a non-existent hash file will be created later */ if (IS_MODE(MODE_UPDATE) && errno == ENOENT) { set_flags_by_hash_file_extension(hash_file, 0); return HashFileIsEmpty; } log_error_file_t(hash_file); return -1; } result = hash_parser_process_file(parser, files); if (result >= 0 && (hash_file->mode & FileContentIsUtf8) != 0) result |= HashFileHasBom; hash_parser_close(parser); return result; } /** * Verify message digests of the files listed in the given hash file. * Lines beginning with ';' and '#' are ignored. * In a case of fail, obtained error will be logged. * * @param hash_file the hash file, containing message digests to verify * @param chdir true if function should emulate chdir to directory of filepath before checking it * @return HashFileBits bit mask on success, -1 on input error, -2 on results output error */ int check_hash_file(file_t* hash_file, int chdir) { return process_hash_file(hash_file, 0, chdir); } /** * Load a set of files from the specified hash file. * In a case of fail, errors will be logged. * * @param hash_file the hash file, containing message digests to load * @param files pointer to the vector to load parsed file paths into * @return HashFileBits bit mask on success, -1 on input error, -2 on results output error */ int load_updated_hash_file(file_t* hash_file, file_set* files) { return process_hash_file(hash_file, files, 0); } RHash-1.4.3/hash_check.h000066400000000000000000000042351425216725100147660ustar00rootroot00000000000000/* hash_check.h - functions to parse and verify a hash file contianing message digests */ #ifndef HASH_CHECK_H #define HASH_CHECK_H #include "file.h" #include "file_set.h" #ifdef __cplusplus extern "C" { #endif /* bit flags for hash_parser */ enum HpBitFlags { HpHasFileSize = 0x01, HpHasEmbeddedCrc32 = 0x02, HpWrongFileSize = 0x10, HpWrongEmbeddedCrc32 = 0x20, HpWrongHashes = 0x40, HpIsBinaryFile = 0x100 }; #define HP_FAILED(flags) ((flags) & (HpWrongFileSize | HpWrongEmbeddedCrc32 | HpWrongHashes)) #define HP_MAX_HASHES 32 /** * Parsed message digest. */ struct hash_value { uint32_t hash_id; /* the id of hash, if it was detected */ uint16_t offset; unsigned char length; unsigned char format; }; /** * Parsed file info, like the path, size and file message digests. */ struct hash_parser { file_t parsed_path; /* parsed file path */ uint64_t file_size; /* parsed file size, e.g. from magnet link */ int parsed_path_errno; unsigned bit_flags; uint64_t found_hash_ids; /* bit mask for matched hash ids */ uint64_t wrong_hashes; /* bit mask for mismatched message digests */ char* line_begin; unsigned embedded_crc32; /* CRC32 embedded into filename */ unsigned hash_mask; /* the mask of hash ids to verify against */ int hashes_num; /* number of parsed message digests */ struct hash_value hashes[HP_MAX_HASHES]; }; enum HashFileBits { HashFileExist = 0x01, HashFileIsEmpty = 0x02, HashFileHasBom = 0x04, HashFileHasWrongHashes = 0x08, HashFileHasMissedFiles = 0x10, HashFileHasUnparsedLines = 0x20 }; int load_updated_hash_file(struct file_t* hash_file, file_set* set); int check_hash_file(struct file_t* hash_file, int chdir); int check_embedded_crc32(struct file_t* file); 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); struct rhash_context; unsigned get_crc32(struct rhash_context* ctx); /* note: IS_HEX() is defined on ASCII-8 while isxdigit() only on ASCII-7 */ #define IS_HEX(c) ((c) <= '9' ? (c) >= '0' : (unsigned)(((c) - 'A') & ~0x20) <= ('F' - 'A' + 0U)) #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* HASH_CHECK_H */ RHash-1.4.3/hash_print.c000066400000000000000000000554441425216725100150500ustar00rootroot00000000000000/* hash_print.c - output message digests using printf-like format */ #include "hash_print.h" #include "calc_sums.h" #include "output.h" #include "parse_cmdline.h" #include "rhash_main.h" #include "win_utils.h" #include "librhash/rhash.h" #include #include #include #include #include #ifdef _WIN32 # include # include #endif /* _WIN32 */ /*========================================================================= * 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_URLENCODE = 0x4000000, PRINT_FLAG_PAD_WITH_ZERO = 0x8000000, PRINT_FLAGS_ALL = PRINT_FLAG_UPPERCASE | PRINT_FLAG_PAD_WITH_ZERO | PRINT_FLAG_RAW | PRINT_FLAG_HEX | PRINT_FLAG_BASE32 | PRINT_FLAG_BASE64 | PRINT_FLAG_URLENCODE, PRINT_STR = 0x10000000, PRINT_ZERO, PRINT_NEWLINE, PRINT_FILEPATH, PRINT_BASENAME, PRINT_SIZE, PRINT_MTIME /*PRINT_ATIME, PRINT_CTIME*/ }; /** * 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; /* 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; char* p; print_item* list = NULL; print_item* item = NULL; print_item** tail; 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 * @param flags pointer to unsigned variable to receive print flags * @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 legacy '%{urlname}' directive for compatibility */ if (length == 7 && memcmp(buf, "urlname", 7) == 0) { *flags = PRINT_BASENAME | PRINT_FLAG_URLENCODE; 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 following a percent sign in a printf-like format string. * * @param str a pointer to the string, containing the token to parse * @return 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; print_item* item = NULL; static const char* short_hash = "CMHTGWRAE"; static const char* short_other = "Llpfs"; 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_FLAG_UPPERCASE), PRINT_ED2K_LINK, PRINT_FILEPATH, PRINT_BASENAME, PRINT_SIZE }; /* detect the padding by zeros */ if (*format == '0') { modifier_flags = PRINT_FLAG_PAD_WITH_ZERO; format++; } else if ((*format & ~0x20) == 'U') { modifier_flags = (*format & 0x20 ? PRINT_FLAG_URLENCODE : PRINT_FLAG_URLENCODE | PRINT_FLAG_UPPERCASE); 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 encountered */ if (*format == '{') { /* parse the token of the kind "%{some-token}" */ const char* p = format + 1; for (; isalnum((unsigned char)*p) || (*p == '-'); p++); if (*p == '}') { unsigned flags = 0; hash_id = printf_name_to_id(format + 1, p - (format + 1), &flags); if (hash_id || (flags & PRINT_FLAG_URLENCODE) || flags == PRINT_MTIME) { /* set uppercase flag if the first letter of printf-entity is uppercase */ modifier_flags |= flags | (format[1] & 0x20 ? 0 : PRINT_FLAG_UPPERCASE); format = p; id_found = 1; } } } /* 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 (upper && (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_FLAGS_ALL) == PRINT_ED2K_LINK) hash_id = RHASH_ED2K | RHASH_AICH; } else if ((modifier_flags & PRINT_FLAG_URLENCODE) != 0) { /* handle legacy token: '%u' -> '%uf' */ modifier_flags |= PRINT_BASENAME; format--; } else { return 0; /* no valid token found */ } } 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 message digests * @return 0 on success, -1 on fail with error code stored in errno */ static int fprint_ed2k_url(FILE* out, struct file_info* info, int print_type) { const char* filename = file_get_print_path(info->file, FPathUtf8 | FPathBaseName | FPathNotNull); int upper_case = (print_type & PRINT_FLAG_UPPERCASE ? RHPR_UPPERCASE : 0); char buf[104]; char* dst = buf; assert(info->sums_flags & RHASH_ED2K); assert(info->rctx); if (rsh_fprintf(out, "ed2k://|file|") < 0 || fprint_urlencoded(out, filename, upper_case) < 0) return -1; *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, "|/"); return PRINTF_RES(rsh_fprintf(out, "%s", 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 * @return 0 on success, -1 on fail with error code stored in errno */ static int fprintI64(FILE* out, uint64_t u64, int width, int zero_pad) { char* buf = (char*)rsh_malloc(width > 40 ? width + 1 : 41); int len = int_len(u64); int res; sprintI64(buf, u64, width); if (len < width && zero_pad) { memset(buf, '0', width - len); } res = PRINTF_RES(rsh_fprintf(out, "%s", buf)); free(buf); return res; } /** * Print time formatted as 'YYYY-MM-DD hh:mm:ss' to a file stream. * * @param out the stream to print the time to * @param time the time to print * @param sfv_format if =1, then change time format to 'hh:mm.ss YYYY-MM-DD' * @return 0 on success, -1 on fail with error code stored in errno */ static int print_time64(FILE* out, uint64_t time64, int sfv_format) { time_t time = (time_t)time64; struct tm* t = localtime(&time); char* format = (sfv_format ? "%02u:%02u.%02u %4u-%02u-%02u" : "%4u-%02u-%02u %02u:%02u:%02u"); int date_index = (sfv_format ? 3 : 0); unsigned d[6]; if (!!t) { d[date_index + 0] = t->tm_year + 1900; d[date_index + 1] = t->tm_mon + 1; d[date_index + 2] = t->tm_mday; d[3 - date_index] = t->tm_hour; d[4 - date_index] = t->tm_min; d[5 - date_index] = t->tm_sec; } else { /* if got a strange day, then print the date '1900-01-00 00:00:00' */ memset(d, 0, sizeof(d)); d[date_index + 0] = 1900; d[date_index + 1] = 1; } return PRINTF_RES(rsh_fprintf(out, format, d[0], d[1], d[2], d[3], d[4], d[5])); } /** * Print formatted file information to the given output stream. * * @param out the stream to print information to * @param out_mode output file mode * @param list the format according to which information shall be printed * @param info the file information * @return 0 on success, -1 on fail with error code stored in errno */ int print_line(FILE* out, unsigned out_mode, print_item* list, struct file_info* info) { char buffer[130]; int res = 0; unsigned out_flags = (out_mode & FileContentIsUtf8 ? OutForceUtf8 : 0); #ifdef _WIN32 /* switch to binary mode to correctly output binary message digests */ int out_fd = _fileno(out); int old_mode = (out_fd > 0 && !isatty(out_fd) ? _setmode(out_fd, _O_BINARY) : -1); #endif for (; list && res == 0; list = list->next) { int print_type = list->flags & ~(PRINT_FLAGS_ALL); size_t len; /* output a hash function digest */ if (!print_type) { 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) | (list->flags & PRINT_FLAG_URLENCODE ? RHPR_URLENCODE : 0); if ((hash_id == RHASH_GOST94 || hash_id == RHASH_GOST94_CRYPTOPRO) && (opt.flags & OPT_GOST_REVERSE)) print_flags |= RHPR_REVERSE; assert(hash_id != 0); len = rhash_print(buffer, info->rctx, hash_id, print_flags); assert(len < sizeof(buffer)); /* output the hash, continue on success */ if (rsh_fwrite(buffer, 1, len, out) == len || errno == 0) continue; res = -1; break; /* exit on error */ } /* output other special items: filepath, URL-encoded filename etc. */ switch (print_type) { case PRINT_STR: res = PRINTF_RES(rsh_fprintf(out, "%s", list->data)); break; case PRINT_ZERO: /* the '\0' character */ res = PRINTF_RES(rsh_fprintf(out, "%c", 0)); break; #ifdef _WIN32 case PRINT_NEWLINE: res = PRINTF_RES(rsh_fprintf(out, "%s", "\r\n")); break; #endif case PRINT_FILEPATH: case PRINT_BASENAME: /* the filename without directory */ if ((list->flags & PRINT_FLAG_URLENCODE) != 0) { unsigned fflags = FPathUtf8 | FPathNotNull | (print_type == PRINT_BASENAME ? FPathBaseName : 0); fprint_urlencoded(out, file_get_print_path(info->file, fflags), (list->flags & PRINT_FLAG_UPPERCASE)); } else { unsigned pflags = (print_type == PRINT_BASENAME ? OutBaseName : 0); res = PRINTF_RES(fprintf_file_t(out, NULL, info->file, pflags | out_flags)); } break; case PRINT_MTIME: /* the last-modified tine of the filename */ res = print_time64(out, info->file->mtime, 0); break; case PRINT_SIZE: /* file size */ res = fprintI64(out, info->size, list->width, (list->flags & PRINT_FLAG_PAD_WITH_ZERO)); break; case PRINT_ED2K_LINK: res = fprint_ed2k_url(out, info, list->flags); break; } } if (res == 0 && fflush(out) < 0) res = -1; #ifdef _WIN32 if (old_mode >= 0) _setmode(out_fd, old_mode); #endif return res; } /** * 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 *=========================================================================*/ #define VNUM(v, index) (((unsigned)v >> (24 - index * 8)) & 0xff) /** * Get text representation of librhash version. */ static const char* get_librhash_version(void) { static char buf[20]; rhash_uptr_t v = rhash_get_version(); if (v == RHASH_ERROR) { /* test for version-specific librhash features */ int algorithm_count = rhash_count(); if (rhash_transmit(14, NULL, 0, 0) != RHASH_ERROR) v = 0x01040000; else if (rhash_print(NULL, NULL, RHASH_CRC32, (RHPR_RAW | RHPR_URLENCODE)) != 4) v = 0x01030900; else if (algorithm_count == 29) v = 0x01030800; else if (algorithm_count == 27) v = 0x01030700; else if (rhash_get_openssl_supported_mask() != RHASH_ERROR) v = 0x01030600; else if (algorithm_count == 26) return "1.3.[0-5]"; else return "1.2.*"; } sprintf(buf, "%d.%d.%d", VNUM(v, 0), VNUM(v, 1), VNUM(v, 2)); return buf; } /** * Initialize information about message digests, stored in the * hash_info_table global variable. */ void init_hash_info_table(void) { unsigned bit; const unsigned fullmask = RHASH_ALL_HASHES | OPT_ED2K_LINK; const unsigned custom_bsd_name = RHASH_RIPEMD160 | RHASH_BLAKE2S | RHASH_BLAKE2B | RHASH_SHA224 | RHASH_SHA256 | RHASH_SHA384 | RHASH_SHA512; const 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; const char* short_opt = "cmhteawrgl"; print_hash_info* info = hash_info_table; /* prevent crash on incompatible librhash */ if (rhash_count() < RHASH_HASH_COUNT) { rsh_fprintf(stderr, "fatal error: incompatible librhash version is loaded: %s\n", get_librhash_version()); rsh_exit(2); } else if (RHASH_HASH_COUNT != rhash_count()) log_warning("inconsistent librhash version is loaded: %s\n", get_librhash_version()); memset(hash_info_table, 0, sizeof(hash_info_table)); for (bit = 1; bit && bit <= fullmask; bit = bit << 1) { const char* p; char* e; char* 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; if ((bit & custom_bsd_name) != 0) { switch (bit) { case RHASH_RIPEMD160: info->bsd_name = "RMD160"; break; case RHASH_SHA224: info->bsd_name = "SHA224"; break; case RHASH_SHA256: info->bsd_name = "SHA256"; break; case RHASH_SHA384: info->bsd_name = "SHA384"; break; case RHASH_SHA512: info->bsd_name = "SHA512"; break; case RHASH_BLAKE2S: info->bsd_name = "BLAKE2s"; break; case RHASH_BLAKE2B: info->bsd_name = "BLAKE2b"; break; } } else info->bsd_name = info->name; ++info; } } /** * Initialize printf string according to program options. * The function is called only when a printf format string is not specified by * the command line, so the format string must be constructed from other options. * * @return the string buffer with format string */ strbuf_t* init_printf_format(void) { strbuf_t* out; const char* fmt; const char* tail = 0; unsigned bit, index = 0; int uppercase; unsigned need_modifier = 0; char up_flag; char fmt_modifier = 'b'; uppercase = ((opt.flags & OPT_UPPERCASE) || (!(opt.flags & OPT_LOWERCASE) && rhash_data.is_sfv)); up_flag = (uppercase ? ~0x20 : 0xFF); out = rsh_str_new(); rsh_str_ensure_size(out, 1024); /* allocate big enough buffer */ if ((opt.sum_flags & OPT_ED2K_LINK) != 0) { rsh_str_append_n(out, "%l\\n", 4); out->str[1] &= up_flag; return out; } if (opt.sum_flags == 0) return out; if (opt.fmt == FMT_BSD) { fmt = "\003(%p) = \001\\n"; } else if (opt.fmt == FMT_MAGNET) { rsh_str_append(out, "magnet:?xl=%s&dn="); rsh_str_append(out, (uppercase ? "%Uf" : "%uf")); fmt = "&xt=urn:\002:\001"; need_modifier = RHASH_SHA1; tail = "\\n"; } else if (!rhash_data.is_sfv && 0 == (opt.sum_flags & (opt.sum_flags - 1))) { fmt = "\001 %p\\n"; } else { rsh_str_append_n(out, "%p", 2); fmt = (rhash_data.is_sfv ? " \001" : " \001"); tail = "\\n"; } if ((opt.flags & OPT_FMT_MODIFIERS) != 0) { need_modifier = 0xffffffff; fmt_modifier = (opt.flags & OPT_HEX ? 'x' : opt.flags & OPT_BASE32 ? 'b' : 'B'); } /* loop by message digests */ 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 & need_modifier) != 0 ) out->str[out->len++] = fmt_modifier; 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->bsd_name); /* add some spaces after the hash BSD name */ i = (int)strlen(info->bsd_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'; return out; } /*========================================================================= * 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 out_mode output file mode * @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, unsigned out_mode, file_t* file) { char buf[24]; unsigned out_flags = (out_mode & FileContentIsUtf8 ? OutForceUtf8 : 0); /* skip stdin stream and message-texts passed by command-line */ if (FILE_ISSPECIAL(file)) return 0; /* silently skip unreadable files, the access error will be reported later */ if (!file_is_readable(file)) return 0; sprintI64(buf, file->size, 12); if (rsh_fprintf(out, "; %s ", buf) < 0) return -1; print_time64(out, file->mtime, 1); return PRINTF_RES(fprintf_file_t(out, " %s\n", file, out_flags)); } /** * 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 * @return 0 on success, -1 on fail with error code stored in errno */ int print_sfv_banner(FILE* out) { time_t cur_time = time(NULL); struct tm* t = localtime(&cur_time); if (!t) return 0; if (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) < 0) return -1; return PRINTF_RES(rsh_fprintf(out, _("; Written by Kravchenko Aleksey (Akademgorodok) - http://rhash.sf.net/\n;\n"))); } RHash-1.4.3/hash_print.h000066400000000000000000000020741425216725100150440ustar00rootroot00000000000000/* hash_print.h - functions to print message digests */ #ifndef HASH_PRINT_H #define HASH_PRINT_H #include #ifdef __cplusplus extern "C" { #endif /** * Name and other info of a hash function */ typedef struct print_hash_info { const char* name; const char* bsd_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 print_item; struct strbuf_t; /* initialization of static data */ void init_hash_info_table(void); struct strbuf_t* init_printf_format(void); /* formatted output of message digests and file information */ struct print_item* parse_print_string(const char* format, unsigned* sum_mask); int print_line(FILE* out, unsigned out_mode, struct print_item* list, struct file_info* info); void free_print_list(struct print_item* list); /* SFV format functions */ int print_sfv_banner(FILE* out); int print_sfv_header_line(FILE* out, unsigned out_mode, struct file_t* file); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* HASH_PRINT_H */ RHash-1.4.3/hash_update.c000066400000000000000000000145701425216725100151710ustar00rootroot00000000000000/* hash_update.c - functions to update a hash file */ #include "hash_update.h" #include "calc_sums.h" #include "file_mask.h" #include "file_set.h" #include "hash_print.h" #include "output.h" #include "parse_cmdline.h" #include "rhash_main.h" #include "win_utils.h" #include #include #include #include #include #ifndef _WIN32 # include #endif typedef struct update_ctx { FILE* fd; char* cut_dir_path; file_t file; file_set* crc_entries; unsigned bit_flags; } update_ctx; enum HashFileExtraBits { HashFileErrorOcurred = 0x100 }; /* define some internal functions, implemented later in this file */ static int fix_sfv_header(file_t* file); static int open_and_prepare_hash_file(struct update_ctx* ctx); /** * Construct updated hash file context. * In a case of fail, the error will be logged. * * @param update_file the hash file to update * @return constructed update context on success, NULL on fail */ struct update_ctx* update_ctx_new(file_t* update_file) { struct update_ctx* ctx; file_set* crc_entries = file_set_new(); int update_flags = load_updated_hash_file(update_file, crc_entries); if (update_flags < 0) { file_set_free(crc_entries); return NULL; } file_set_sort(crc_entries); opt.mode &= ~MODE_CHECK; ctx = (update_ctx*)rsh_malloc(sizeof(update_ctx)); memset(ctx, 0, sizeof(*ctx)); file_clone(&(ctx->file), update_file); ctx->crc_entries = crc_entries; ctx->bit_flags = (unsigned)update_flags; return ctx; } /** * Add message digests of the specified file to the updated hash file, * if the path of the first file is not yet present in the second. * In a case of fail, the error will be logged. * * @param ctx the update context for updated hash file * @param file the file to add * @return 0 on success, -1 on fail, -2 on fatal error */ int update_ctx_update(struct update_ctx* ctx, file_t* hash_file) { int res; if ((ctx->bit_flags & HashFileErrorOcurred) != 0) return -1; /* skip files already present in the hash file */ if (file_set_exist(ctx->crc_entries, file_get_print_path(hash_file, FPathUtf8))) return 0; if (!ctx->fd && open_and_prepare_hash_file(ctx) < 0) { log_error_file_t(&ctx->file); ctx->bit_flags |= HashFileErrorOcurred; return -2; } /* print message digests to the hash file */ res = calculate_and_print_sums(ctx->fd, &ctx->file, hash_file); if (res < 0) ctx->bit_flags |= HashFileErrorOcurred; return res; } /** * Destroy update context. * * @param ctx the update context to cleanup * @return 0 on success, -1 on fail */ int update_ctx_free(struct update_ctx* ctx) { int res = 0; if (!ctx) return 0; free(ctx->cut_dir_path); file_set_free(ctx->crc_entries); if (ctx->fd) { if (fclose(ctx->fd) < 0) { log_error_file_t(&ctx->file); res = -1; } else if (!!(ctx->bit_flags & HashFileErrorOcurred)) { res = -1; } else if (!rhash_data.stop_flags) { if (rhash_data.is_sfv) res = fix_sfv_header(&ctx->file); /* finalize the hash file */ if (res == 0) log_msg_file_t(_("Updated: %s\n"), &ctx->file); } } file_cleanup(&ctx->file); free(ctx); return res; } /** * Open the updated hash file for appending. Add SFV header, if required. * * @param ctx the update context for updated hash file * @return 0 on success, -1 on fail with error code stored in errno */ static int open_and_prepare_hash_file(struct update_ctx* ctx) { int open_mode = (ctx->bit_flags & HashFileExist ? FOpenRW : FOpenWrite) | FOpenBin; assert(!ctx->fd); /* open the hash file for reading/writing or create it */ ctx->fd = file_fopen(&ctx->file, open_mode); if (!ctx->fd) return -1; if (!(ctx->bit_flags & HashFileIsEmpty)) { int ch; /* read the last character of the file to check if it is EOL */ if (fseek(ctx->fd, -1, SEEK_END) != 0) return -1; ch = fgetc(ctx->fd); if (ch < 0 && ferror(ctx->fd)) return -1; /* writing doesn't work without seeking */ if (fseek(ctx->fd, 0, SEEK_END) != 0) return -1; /* write EOL, if it isn't present */ if (ch != '\n' && ch != '\r') { if (rsh_fprintf(ctx->fd, "\n") < 0) return -1; } } else { /* skip BOM, if present */ if ((ctx->bit_flags & HashFileHasBom) && fseek(ctx->fd, 0, SEEK_END) != 0) return -1; /* SFV banner will be printed only in SFV mode and only for empty hash files */ if (rhash_data.is_sfv) return print_sfv_banner(ctx->fd); } return 0; } /** * Move all SFV header lines (i.e. all lines starting with a semicolon) * from the end of updated file to its head. * In a case of fail, the error will be logged. * * @param file the hash file requiring fixing of its SFV header * @return 0 on success, -1 on error */ static int fix_sfv_header(file_t* file) { FILE* in; FILE* out; char buf[2048]; file_t new_file; int result = 0; int is_comment; int print_comments; /* open the hash file for reading */ in = file_fopen(file, FOpenRead); if (!in) { log_error_file_t(file); return -1; } /* open a temporary file for writing */ file_modify_path(&new_file, file, ".new", FModifyAppendSuffix); out = file_fopen(&new_file, FOpenWrite); if (!out) { log_error_file_t(&new_file); file_cleanup(&new_file); fclose(in); return -1; } /* The first pass, prints commented lines to the destination file, * and the second pass, prints all other lines */ for (print_comments = 1;; print_comments = 0) { while (fgets(buf, 2048, in)) { char* line = buf; /* skip BOM, unless it is on the first line */ if (STARTS_WITH_UTF8_BOM(line)) { is_comment = (line[3] == ';'); if (ftell(out) != 0) line += 3; } else is_comment = (line[0] == ';'); if (is_comment == print_comments) { if (fputs(line, out) < 0) break; } } if (!print_comments || ferror(out) || ferror(in) || fseek(in, 0, SEEK_SET) != 0) break; } if (ferror(in)) { log_error_file_t(file); result = -1; } else if (ferror(out)) { log_error_file_t(&new_file); result = -1; } fclose(in); if (fclose(out) < 0 && result == 0) { log_error_file_t(&new_file); result = -1; } /* overwrite the hash file with the new one */ if (result == 0 && file_rename(&new_file, file) < 0) { /* TRANSLATORS: printed when a file rename failed */ log_error(_("can't move %s to %s: %s\n"), file_get_print_path(&new_file, FPathPrimaryEncoding | FPathNotNull), file_get_print_path(file, FPathPrimaryEncoding | FPathNotNull), strerror(errno)); result = -1; } file_cleanup(&new_file); return result; } RHash-1.4.3/hash_update.h000066400000000000000000000006711425216725100151730ustar00rootroot00000000000000/* hash_update.h - functions to update a hash file */ #ifndef HASH_UPDATE_H #define HASH_UPDATE_H #ifdef __cplusplus extern "C" { #endif struct file_t; struct update_ctx; struct update_ctx* update_ctx_new(struct file_t* update_file); int update_ctx_update(struct update_ctx* ctx, struct file_t* file); int update_ctx_free(struct update_ctx* ctx); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* HASH_UPDATE_H */ RHash-1.4.3/librhash/000077500000000000000000000000001425216725100143255ustar00rootroot00000000000000RHash-1.4.3/librhash/Doxyfile000066400000000000000000003173541425216725100160500ustar00rootroot00000000000000# 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 # , /