Browse Source

alt lib

ffuzzy
boB Rudis 4 years ago
parent
commit
dee0a1db98
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 2
      DESCRIPTION
  2. 5
      NAMESPACE
  3. 43
      R/RcppExports.R
  4. 2
      cleanup
  5. 75
      configure
  6. 15
      man/check_is_xptr.Rd
  7. 15
      man/is_null_xptr_.Rd
  8. 14
      src/Makevars
  9. 7
      src/Makevars.in
  10. 112
      src/RcppExports.cpp
  11. 76
      src/ffuzzy.hpp
  12. 196
      src/ffuzzypp/base64.hpp
  13. 83
      src/ffuzzypp/context_hash.hpp
  14. 480
      src/ffuzzypp/context_hash_fast.hpp
  15. 495
      src/ffuzzypp/digest.hpp
  16. 254
      src/ffuzzypp/digest_base.hpp
  17. 255
      src/ffuzzypp/digest_blocksize.hpp
  18. 1167
      src/ffuzzypp/digest_comparison.hpp
  19. 649
      src/ffuzzypp/digest_data.hpp
  20. 125
      src/ffuzzypp/digest_filesize.hpp
  21. 544
      src/ffuzzypp/digest_generator.hpp
  22. 425
      src/ffuzzypp/digest_position_array.hpp
  23. 379
      src/ffuzzypp/digest_position_array_base.hpp
  24. 83
      src/ffuzzypp/rolling_hash.hpp
  25. 87
      src/ffuzzypp/rolling_hash_ssdeep.hpp
  26. 345
      src/ffuzzypp/strings/common_substr.hpp
  27. 521
      src/ffuzzypp/strings/edit_dist.hpp
  28. 82
      src/ffuzzypp/strings/nosequences.hpp
  29. 409
      src/ffuzzypp/strings/position_array.hpp
  30. 154
      src/ffuzzypp/strings/sequences.hpp
  31. 58
      src/ffuzzypp/strings/terminators.hpp
  32. 44
      src/ffuzzypp/strings/transform.hpp
  33. 60
      src/ffuzzypp/utils/likely.hpp
  34. 67
      src/ffuzzypp/utils/minmax.hpp
  35. 129
      src/ffuzzypp/utils/numeric_digits.hpp
  36. 116
      src/ffuzzypp/utils/ranges.hpp
  37. 371
      src/ffuzzypp/utils/safe_int.hpp
  38. 97
      src/ffuzzypp/utils/static_assert_query.hpp
  39. 67
      src/ffuzzypp/utils/type_modifier.hpp
  40. 2
      src/lib/ffuzzypp-release-4.0.1/.gitattributes
  41. 41
      src/lib/ffuzzypp-release-4.0.1/.gitignore
  42. 23
      src/lib/ffuzzypp-release-4.0.1/COPYING.Boost
  43. 339
      src/lib/ffuzzypp-release-4.0.1/COPYING.GPLv2
  44. 674
      src/lib/ffuzzypp-release-4.0.1/COPYING.GPLv3
  45. 43
      src/lib/ffuzzypp-release-4.0.1/COPYING.GPLv3Autoconf
  46. 87
      src/lib/ffuzzypp-release-4.0.1/COPYING.md
  47. 64
      src/lib/ffuzzypp-release-4.0.1/Makefile.am
  48. 30
      src/lib/ffuzzypp-release-4.0.1/NEWS.md
  49. 229
      src/lib/ffuzzypp-release-4.0.1/README.md
  50. 2
      src/lib/ffuzzypp-release-4.0.1/bootstrap.sh
  51. 94
      src/lib/ffuzzypp-release-4.0.1/configure.ac
  52. 4
      src/lib/ffuzzypp-release-4.0.1/examples/.gitignore
  53. 31
      src/lib/ffuzzypp-release-4.0.1/examples/Makefile.am
  54. 130
      src/lib/ffuzzypp-release-4.0.1/examples/compare-hash.cpp
  55. 174
      src/lib/ffuzzypp-release-4.0.1/examples/compute-hash.cpp
  56. 2
      src/lib/ffuzzypp-release-4.0.1/ext/.gitignore
  57. 76
      src/lib/ffuzzypp-release-4.0.1/ffuzzy.hpp
  58. 36
      src/lib/ffuzzypp-release-4.0.1/ffuzzy_declarations.cpp
  59. 196
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/base64.hpp
  60. 83
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/context_hash.hpp
  61. 480
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/context_hash_fast.hpp
  62. 495
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest.hpp
  63. 254
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_base.hpp
  64. 255
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_blocksize.hpp
  65. 1167
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_comparison.hpp
  66. 649
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_data.hpp
  67. 125
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_filesize.hpp
  68. 544
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_generator.hpp
  69. 425
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_position_array.hpp
  70. 379
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_position_array_base.hpp
  71. 83
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/rolling_hash.hpp
  72. 87
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/rolling_hash_ssdeep.hpp
  73. 345
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/strings/common_substr.hpp
  74. 521
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/strings/edit_dist.hpp
  75. 82
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/strings/nosequences.hpp
  76. 409
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/strings/position_array.hpp
  77. 154
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/strings/sequences.hpp
  78. 58
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/strings/terminators.hpp
  79. 44
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/strings/transform.hpp
  80. 60
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/utils/likely.hpp
  81. 67
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/utils/minmax.hpp
  82. 129
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/utils/numeric_digits.hpp
  83. 116
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/utils/ranges.hpp
  84. 371
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/utils/safe_int.hpp
  85. 97
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/utils/static_assert_query.hpp
  86. 67
      src/lib/ffuzzypp-release-4.0.1/ffuzzypp/utils/type_modifier.hpp
  87. 7
      src/lib/ffuzzypp-release-4.0.1/tests/.gitignore
  88. 76
      src/lib/ffuzzypp-release-4.0.1/tests/Makefile.am
  89. 98
      src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/common/blockhash_comparison_min_matching.hpp
  90. 70
      src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/large/blockhash_comparison_min_matching.hpp
  91. 183
      src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/blockhash_comparison_max_matching.hpp
  92. 144
      src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/blockhash_comparison_min_matching.hpp
  93. 47
      src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_comparison_identical.hpp
  94. 2149
      src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_comparison_identical_2_9_1.hpp
  95. 46
      src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_comparison_identical_2_9_2.hpp
  96. 47
      src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_data_naturality.hpp
  97. 128
      src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_generator_forms.hpp
  98. 187
      src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_generator_initial_guess.hpp
  99. 38
      src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_generator_nil.hpp
  100. 83
      src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_generator_rolling_hash_overflow.hpp

2
DESCRIPTION

@ -13,7 +13,7 @@ Description: The ssdeep project provides an open source library <https://github.
hashes from character/byte streams.
URL: https://git.rud.is/hrbrmstr/ssdeepr
BugReports: https://git.rud.is/hrbrmstr/ssdeepr/issues
SystemRequirements: libfuzzy <https://ssdeep-project.github.io/ssdeep/index.html#platforms>
SystemRequirements: C++11
Encoding: UTF-8
License: AGPL
Suggests:

5
NAMESPACE

@ -1,10 +1,5 @@
# Generated by roxygen2: do not edit by hand
export("%>%")
export(hash_compare)
export(hash_con)
export(hash_file)
export(hash_raw)
importFrom(Rcpp,sourceCpp)
importFrom(magrittr,"%>%")
useDynLib(ssdeepr, .registration = TRUE)

43
R/RcppExports.R

@ -1,43 +0,0 @@
# Generated by using Rcpp::compileAttributes() -> do not edit by hand
# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
#' Test whether an object is an external pointer
#'
#' @param x object to test
#' @keywords internal
check_is_xptr <- function(s) {
invisible(.Call(`_ssdeepr_check_is_xptr`, s))
}
#' Test whether an external pointer is null
#'
#' @param x object to test
#' @keywords internal
is_null_xptr_ <- function(s) {
.Call(`_ssdeepr_is_null_xptr_`, s)
}
int_fuzzy_context <- function() {
.Call(`_ssdeepr_int_fuzzy_context`)
}
int_fuzzy_update <- function(sctx, v) {
.Call(`_ssdeepr_int_fuzzy_update`, sctx, v)
}
int_fuzzy_digest <- function(sctx) {
.Call(`_ssdeepr_int_fuzzy_digest`, sctx)
}
int_hash_file <- function(path) {
.Call(`_ssdeepr_int_hash_file`, path)
}
int_hash_buf <- function(v) {
.Call(`_ssdeepr_int_hash_buf`, v)
}
int_hash_cmp <- function(h1, h2) {
.Call(`_ssdeepr_int_hash_cmp`, h1, h2)
}

2
cleanup

@ -1,2 +0,0 @@
#!/bin/sh
rm -f src/Makevars

75
configure

@ -1,75 +0,0 @@
#!/bin/sh
# Anticonf (tm) script by Jeroen Ooms (2018)
# This script will query 'pkg-config' for the required cflags and ldflags.
# If pkg-config is unavailable or does not find the library, try setting
# INCLUDE_DIR and LIB_DIR manually via e.g:
# R CMD INSTALL --configure-vars='INCLUDE_DIR=/.../include LIB_DIR=/.../lib'
# Library settings
PKG_CONFIG_NAME="libfuzzy"
PKG_DEB_NAME="libfuzzy-dev"
PKG_RPM_NAME="libfuzzy-devel"
PKG_BREW_NAME="ssdeep"
PKG_TEST_HEADER="<fuzzy.h>"
PKG_LIBS_STATIC="-lfuzzy"
PKG_LIBS="-lfuzzy"
PKG_CFLAGS=""
# Use pkg-config if available
if [ $(command -v pkg-config) ]; then
PKGCONFIG_CFLAGS=$(pkg-config --cflags --silence-errors ${PKG_CONFIG_NAME})
PKGCONFIG_LIBS=$(pkg-config --libs ${PKG_CONFIG_NAME})
fi
# Note that cflags may be empty in case of success
if [ "$INCLUDE_DIR" ] || [ "$LIB_DIR" ]; then
echo "Found INCLUDE_DIR and/or LIB_DIR!"
PKG_CFLAGS="-I$INCLUDE_DIR $PKG_CFLAGS"
PKG_LIBS="-L$LIB_DIR $PKG_LIBS"
elif [ "$PKGCONFIG_CFLAGS" ] || [ "$PKGCONFIG_LIBS" ]; then
echo "Found pkg-config cflags and libs!"
PKG_CFLAGS=${PKGCONFIG_CFLAGS}
PKG_LIBS=${PKGCONFIG_LIBS}
elif [[ "$OSTYPE" == "darwin"* ]]; then
if [ $(command -v brew) ]; then
BREWDIR=$(brew --prefix)
else
curl -sfL "https://jeroen.github.io/autobrew/$PKG_BREW_NAME" > autobrew
source autobrew
fi
PKG_CFLAGS="-I$BREWDIR/opt/ssdeep/include"
PKG_LIBS="-L$BREWDIR/opt/ssdeep/lib -L$BREWDIR/opt/ssdeep/lib $PKG_LIBS"
fi
# For debugging
echo "Using PKG_CFLAGS=$PKG_CFLAGS"
echo "Using PKG_LIBS=$PKG_LIBS"
# Find compiler
CC=$(${R_HOME}/bin/R CMD config CC)
CFLAGS=$(${R_HOME}/bin/R CMD config CFLAGS)
CPPFLAGS=$(${R_HOME}/bin/R CMD config CPPFLAGS)
# Test configuration
echo "#include $PKG_TEST_HEADER" | ${CC} ${CPPFLAGS} ${PKG_CFLAGS} ${CFLAGS} -E -xc - >/dev/null 2>&1 || R_CONFIG_ERROR=1;
# Customize the error
if [ $R_CONFIG_ERROR ]; then
echo "------------------------- ANTICONF ERROR ---------------------------"
echo "Configuration failed because $PKG_CONFIG_NAME was not found. Try installing:"
echo " * deb: $PKG_DEB_NAME (Debian, Ubuntu, etc)"
echo " * rpm: $PKG_RPM_NAME (Fedora, EPEL)"
echo " * brew: $PKG_BREW_NAME (OSX)"
echo "If $PKG_CONFIG_NAME is already installed, check that 'pkg-config' is in your"
echo "PATH and PKG_CONFIG_PATH contains a $PKG_CONFIG_NAME.pc file. If pkg-config"
echo "is unavailable you can set INCLUDE_DIR and LIB_DIR manually via:"
echo "R CMD INSTALL --configure-vars='INCLUDE_DIR=... LIB_DIR=...'"
echo "--------------------------------------------------------------------"
exit 1;
fi
# Write to Makevars
sed -e "s|@cflags@|$PKG_CFLAGS|" -e "s|@libs@|$PKG_LIBS|" src/Makevars.in > src/Makevars
# Success
exit 0

15
man/check_is_xptr.Rd

@ -1,15 +0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/RcppExports.R
\name{check_is_xptr}
\alias{check_is_xptr}
\title{Test whether an object is an external pointer}
\usage{
check_is_xptr(s)
}
\arguments{
\item{x}{object to test}
}
\description{
Test whether an object is an external pointer
}
\keyword{internal}

15
man/is_null_xptr_.Rd

@ -1,15 +0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/RcppExports.R
\name{is_null_xptr_}
\alias{is_null_xptr_}
\title{Test whether an external pointer is null}
\usage{
is_null_xptr_(s)
}
\arguments{
\item{x}{object to test}
}
\description{
Test whether an external pointer is null
}
\keyword{internal}

14
src/Makevars

@ -1,7 +1,15 @@
PKG_CPPFLAGS=-I/usr/local/opt/ssdeep/include
PKG_LIBS=-L/usr/local/opt/ssdeep/lib -L/usr/local/opt/ssdeep/lib -lfuzzy
PKG_CPPFLAGS=-I.
CXX_STD = CXX11
PKG_LIBS=-L. libffuzzypp.a
FUZZY_DIR=ffuzzypp-release-4.0.1
all: clean
all: libffuzzypp.a clean
libffuzzypp.a:
cd lib/${FUZZY_DIR} && ./configure && make
cp lib/${FUZZY_DIR}/libffuzzypp.a ../..
cp -r lib/${FUZZY_DIR}/ffuzzypp ../..
cp lib/${FUZZY_DIR}/ffuzzy.hpp ../..
clean:
rm -Rf $(SHLIB) $(OBJECTS)

7
src/Makevars.in

@ -1,7 +0,0 @@
PKG_CPPFLAGS=@cflags@
PKG_LIBS=@libs@
all: clean
clean:
rm -Rf $(SHLIB) $(OBJECTS)

112
src/RcppExports.cpp

@ -1,112 +0,0 @@
// Generated by using Rcpp::compileAttributes() -> do not edit by hand
// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
#include <Rcpp.h>
using namespace Rcpp;
// check_is_xptr
void check_is_xptr(SEXP s);
RcppExport SEXP _ssdeepr_check_is_xptr(SEXP sSEXP) {
BEGIN_RCPP
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< SEXP >::type s(sSEXP);
check_is_xptr(s);
return R_NilValue;
END_RCPP
}
// is_null_xptr_
SEXP is_null_xptr_(SEXP s);
RcppExport SEXP _ssdeepr_is_null_xptr_(SEXP sSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< SEXP >::type s(sSEXP);
rcpp_result_gen = Rcpp::wrap(is_null_xptr_(s));
return rcpp_result_gen;
END_RCPP
}
// int_fuzzy_context
SEXP int_fuzzy_context();
RcppExport SEXP _ssdeepr_int_fuzzy_context() {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
rcpp_result_gen = Rcpp::wrap(int_fuzzy_context());
return rcpp_result_gen;
END_RCPP
}
// int_fuzzy_update
SEXP int_fuzzy_update(SEXP sctx, std::vector < unsigned char > v);
RcppExport SEXP _ssdeepr_int_fuzzy_update(SEXP sctxSEXP, SEXP vSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< SEXP >::type sctx(sctxSEXP);
Rcpp::traits::input_parameter< std::vector < unsigned char > >::type v(vSEXP);
rcpp_result_gen = Rcpp::wrap(int_fuzzy_update(sctx, v));
return rcpp_result_gen;
END_RCPP
}
// int_fuzzy_digest
String int_fuzzy_digest(SEXP sctx);
RcppExport SEXP _ssdeepr_int_fuzzy_digest(SEXP sctxSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< SEXP >::type sctx(sctxSEXP);
rcpp_result_gen = Rcpp::wrap(int_fuzzy_digest(sctx));
return rcpp_result_gen;
END_RCPP
}
// int_hash_file
String int_hash_file(String path);
RcppExport SEXP _ssdeepr_int_hash_file(SEXP pathSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< String >::type path(pathSEXP);
rcpp_result_gen = Rcpp::wrap(int_hash_file(path));
return rcpp_result_gen;
END_RCPP
}
// int_hash_buf
String int_hash_buf(std::vector < unsigned char > v);
RcppExport SEXP _ssdeepr_int_hash_buf(SEXP vSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< std::vector < unsigned char > >::type v(vSEXP);
rcpp_result_gen = Rcpp::wrap(int_hash_buf(v));
return rcpp_result_gen;
END_RCPP
}
// int_hash_cmp
IntegerVector int_hash_cmp(String h1, String h2);
RcppExport SEXP _ssdeepr_int_hash_cmp(SEXP h1SEXP, SEXP h2SEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< String >::type h1(h1SEXP);
Rcpp::traits::input_parameter< String >::type h2(h2SEXP);
rcpp_result_gen = Rcpp::wrap(int_hash_cmp(h1, h2));
return rcpp_result_gen;
END_RCPP
}
static const R_CallMethodDef CallEntries[] = {
{"_ssdeepr_check_is_xptr", (DL_FUNC) &_ssdeepr_check_is_xptr, 1},
{"_ssdeepr_is_null_xptr_", (DL_FUNC) &_ssdeepr_is_null_xptr_, 1},
{"_ssdeepr_int_fuzzy_context", (DL_FUNC) &_ssdeepr_int_fuzzy_context, 0},
{"_ssdeepr_int_fuzzy_update", (DL_FUNC) &_ssdeepr_int_fuzzy_update, 2},
{"_ssdeepr_int_fuzzy_digest", (DL_FUNC) &_ssdeepr_int_fuzzy_digest, 1},
{"_ssdeepr_int_hash_file", (DL_FUNC) &_ssdeepr_int_hash_file, 1},
{"_ssdeepr_int_hash_buf", (DL_FUNC) &_ssdeepr_int_hash_buf, 1},
{"_ssdeepr_int_hash_cmp", (DL_FUNC) &_ssdeepr_int_hash_cmp, 2},
{NULL, NULL, 0}
};
RcppExport void R_init_ssdeepr(DllInfo *dll) {
R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
R_useDynamicSymbols(dll, FALSE);
}

76
src/ffuzzy.hpp

@ -0,0 +1,76 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hasing
ffuzzy.hpp
Fuzzy hashing implementation
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_ROOT_FFUZZY_HPP
#define FFUZZYPP_ROOT_FFUZZY_HPP
#include "ffuzzypp/utils/likely.hpp"
#include "ffuzzypp/utils/minmax.hpp"
#include "ffuzzypp/utils/safe_int.hpp"
#include "ffuzzypp/utils/static_assert_query.hpp"
#include "ffuzzypp/utils/numeric_digits.hpp"
#include "ffuzzypp/utils/type_modifier.hpp"
#include "ffuzzypp/utils/ranges.hpp"
#include "ffuzzypp/base64.hpp"
#include "ffuzzypp/context_hash.hpp"
#include "ffuzzypp/context_hash_fast.hpp"
#include "ffuzzypp/rolling_hash.hpp"
#include "ffuzzypp/rolling_hash_ssdeep.hpp"
#include "ffuzzypp/strings/position_array.hpp"
#include "ffuzzypp/strings/common_substr.hpp"
#include "ffuzzypp/strings/edit_dist.hpp"
#include "ffuzzypp/strings/terminators.hpp"
#include "ffuzzypp/strings/transform.hpp"
#include "ffuzzypp/strings/sequences.hpp"
#include "ffuzzypp/strings/nosequences.hpp"
#include "ffuzzypp/digest_blocksize.hpp"
#include "ffuzzypp/digest_data.hpp"
#include "ffuzzypp/digest_position_array_base.hpp"
#include "ffuzzypp/digest_comparison.hpp"
#include "ffuzzypp/digest_base.hpp"
#include "ffuzzypp/digest_position_array.hpp"
#include "ffuzzypp/digest.hpp"
#include "ffuzzypp/digest_filesize.hpp"
#include "ffuzzypp/digest_generator.hpp"
#ifdef FFUZZYPP_COMPATIBILITY_SSDEEP_2_9
#error Configuration by FFUZZYPP_COMPATIBILITY_SSDEEP_2_9 is now removed. Read README for alternative method.
#endif
#ifdef FFUZZYPP_COMPATIBILITY_SSDEEP
static_assert(ffuzzy::digest_params::max_blockhash_len == 64,
"Given parameter (digest_params::max_blockhash_len) is not compatible with ssdeep.");
static_assert(ffuzzy::digest_params::max_blockhash_sequence == 3,
"Given parameter (digest_params::max_blockhash_sequence) is not compatible with ssdeep.");
static_assert(ffuzzy::blockhash_comparison_params::min_match_len == 7,
"Given parameter (blockhash_comparison_params::min_match_len) is not compatible with ssdeep.");
static_assert(ffuzzy::rolling_hash::window_size == 7,
"Given parameter (rolling_hash::window_size) is not compatible with ssdeep.");
static_assert(ffuzzy::digest_blocksize::number_of_blockhashes == 31,
"Given parameter (digest_blocksize::number_of_blockhashes) is not compatible with ssdeep.");
static_assert(ffuzzy::digest_blocksize::min_blocksize == 3,
"Given parameter (digest_blocksize::min_blocksize) is not compatible with ssdeep.");
static_assert(ffuzzy::digest_filesize::min_supported_size == 4097,
"Given parameter (digest_filesize::min_supported_size) is not compatible with ssdeep.");
#endif
#endif

196
src/ffuzzypp/base64.hpp

@ -0,0 +1,196 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
base64.hpp
Base64 utilities
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_BASE64_HPP
#define FFUZZYPP_BASE64_HPP
namespace ffuzzy {
class base64
{
private:
base64(void) = delete;
base64(const base64&) = delete;
// Base64 table
public:
static constexpr const char invalid_index = 64;
static constexpr const char values[64] =
{
// This should be the same order of ordinal Base64
// (as well as b64 variable in fuzzy.c)
'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U',
'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u',
'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4',
'5', '6', '7', '8', '9',
'+', '/'
};
static_assert(
sizeof(values) == 64 &&
values[ 0] == 'A' &&
values[26] == 'a' &&
values[52] == '0' &&
values[62] == '+' &&
values[63] == '/',
"minimum sanity check for Base64 failed.");
static_assert(
invalid_index < 0 || invalid_index >= 64,
"invalid_index is not out of range.");
public:
// Utility to check whether given character is in Base64 charset
static bool isbase64(char c) noexcept
{
switch (c)
{
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '+': case '/':
return true;
default:
return false;
}
}
// Utility to convert character to Base64 index
static char toindex(char c) noexcept
{
switch (c)
{
case 'A': return 0;
case 'B': return 1;
case 'C': return 2;
case 'D': return 3;
case 'E': return 4;
case 'F': return 5;
case 'G': return 6;
case 'H': return 7;
case 'I': return 8;
case 'J': return 9;
case 'K': return 10;
case 'L': return 11;
case 'M': return 12;
case 'N': return 13;
case 'O': return 14;
case 'P': return 15;
case 'Q': return 16;
case 'R': return 17;
case 'S': return 18;
case 'T': return 19;
case 'U': return 20;
case 'V': return 21;
case 'W': return 22;
case 'X': return 23;
case 'Y': return 24;
case 'Z': return 25;
case 'a': return 26;
case 'b': return 27;
case 'c': return 28;
case 'd': return 29;
case 'e': return 30;
case 'f': return 31;
case 'g': return 32;
case 'h': return 33;
case 'i': return 34;
case 'j': return 35;
case 'k': return 36;
case 'l': return 37;
case 'm': return 38;
case 'n': return 39;
case 'o': return 40;
case 'p': return 41;
case 'q': return 42;
case 'r': return 43;
case 's': return 44;
case 't': return 45;
case 'u': return 46;
case 'v': return 47;
case 'w': return 48;
case 'x': return 49;
case 'y': return 50;
case 'z': return 51;
case '0': return 52;
case '1': return 53;
case '2': return 54;
case '3': return 55;
case '4': return 56;
case '5': return 57;
case '6': return 58;
case '7': return 59;
case '8': return 60;
case '9': return 61;
case '+': return 62;
case '/': return 63;
default: return invalid_index;
}
}
// Base64 transformation (from index to actual character)
public:
class transform_to_b64
{
private:
transform_to_b64(void) = delete;
transform_to_b64(const transform_to_b64&) = delete;
public:
static constexpr char transform(char ch) noexcept
{
return base64::values[static_cast<unsigned char>(ch)];
}
};
// Base64 reverse-transformation (from Base64 character to index)
public:
class transform_from_b64
{
private:
transform_from_b64(void) = delete;
transform_from_b64(const transform_from_b64&) = delete;
public:
static char transform(char ch) noexcept
{
return toindex(ch);
}
};
};
#ifdef FFUZZYPP_DECLARATIONS
constexpr const char base64::values[64];
#endif
}
#endif

83
src/ffuzzypp/context_hash.hpp

@ -0,0 +1,83 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
context_hash.hpp
Context computation (non-rolling) hash implementation
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_CONTEXT_HASH_HPP
#define FFUZZYPP_CONTEXT_HASH_HPP
#include <cstdint>
namespace ffuzzy {
class context_hash
{
private:
// Don't use UINT32_C not to define __STDC_CONSTANT_MACROS in ffuzzy++
static constexpr const uint_least32_t hash_init = uint_least32_t(0x28021967ul);
static constexpr const uint_least32_t hash_prime = uint_least32_t(0x01000193ul);
private:
uint_least32_t h;
public:
static constexpr uint_least32_t initial_state(void) noexcept
{
return hash_init;
}
void reset(void) noexcept
{
h = initial_state();
}
static constexpr uint_least32_t next_state(uint_least32_t h, unsigned char c) noexcept
{
return ((h * hash_prime) ^ uint_least32_t(c)) & uint_least32_t(0xfffffffful);
}
void update(unsigned char c) noexcept
{
h = next_state(h, c);
}
uint_least32_t sum(void) const noexcept
{
return h;
}
public:
char sum_in_base64(void) const noexcept
{
// sum for Base64 (returns Base64 index)
return static_cast<char>(h & 0x3f);
}
public:
context_hash(void) noexcept = default; // initialize to undefined state
};
}
#endif

480
src/ffuzzypp/context_hash_fast.hpp

@ -0,0 +1,480 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
context_hash_fast.hpp
Fast implementation of context_hash (only lowest 6-bits)
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_CONTEXT_HASH_FAST_HPP
#define FFUZZYPP_CONTEXT_HASH_FAST_HPP
#include <cstdint>
#include "context_hash.hpp"
#include "utils/static_assert_query.hpp"
namespace ffuzzy {
class context_hash_fast
{
private:
static constexpr const char hash_init = static_cast<char>(context_hash::initial_state() & 0x3f);
static constexpr const char table_translate[64][64] =
{
{ // 0x00
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
},
{ // 0x01
0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c,
0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c,
0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c,
},
{ // 0x02
0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29,
0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39,
0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09,
0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19,
},
{ // 0x03
0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36,
0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26,
0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16,
0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06,
},
{ // 0x04
0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03,
0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13,
0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33,
},
{ // 0x05
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
},
{ // 0x06
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
},
{ // 0x07
0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a,
0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a,
0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a,
},
{ // 0x08
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
},
{ // 0x09
0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24,
0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34,
0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04,
0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14,
},
{ // 0x0a
0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21,
0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11,
0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01,
},
{ // 0x0b
0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e,
0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e,
0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e,
},
{ // 0x0c
0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b,
0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b,
0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b,
0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b,
},
{ // 0x0d
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
},
{ // 0x0e
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
},
{ // 0x0f
0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12,
0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02,
0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32,
0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22,
},
{ // 0x10
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
},
{ // 0x11
0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c,
0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c,
0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c,
},
{ // 0x12
0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19,
0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09,
0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39,
0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29,
},
{ // 0x13
0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26,
0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36,
0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06,
0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16,
},
{ // 0x14
0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33,
0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13,
0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03,
},
{ // 0x15
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
},
{ // 0x16
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
},
{ // 0x17
0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a,
0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a,
0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a,
},
{ // 0x18
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
},
{ // 0x19
0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14,
0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04,
0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34,
0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24,
},
{ // 0x1a
0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21,
0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01,
0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11,
},
{ // 0x1b
0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e,
0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e,
0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e,
},
{ // 0x1c
0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b,
0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b,
0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b,
0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b,
},
{ // 0x1d
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
},
{ // 0x1e
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
},
{ // 0x1f
0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02,
0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12,
0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22,
0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32,
},
{ // 0x20
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
},
{ // 0x21
0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c,
0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c,
0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c,
},
{ // 0x22
0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09,
0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19,
0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29,
0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39,
},
{ // 0x23
0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16,
0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06,
0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36,
0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26,
},
{ // 0x24
0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33,
0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03,
0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13,
},
{ // 0x25
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
},
{ // 0x26
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
},
{ // 0x27
0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a,
0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a,
0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a,
},
{ // 0x28
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
},
{ // 0x29
0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04,
0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14,
0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24,
0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34,
},
{ // 0x2a
0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11,
0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01,
0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21,
},
{ // 0x2b
0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e,
0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e,
0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e,
0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
},
{ // 0x2c
0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b,
0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b,
0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b,
0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b,
},
{ // 0x2d
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
},
{ // 0x2e
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
},
{ // 0x2f
0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32,
0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22,
0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12,
0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02,
},
{ // 0x30
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
},
{ // 0x31
0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c,
0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c,
0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c,
0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
},
{ // 0x32
0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39,
0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29,
0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19,
0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09,
},
{ // 0x33
0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06,
0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16,
0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26,
0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36,
},
{ // 0x34
0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13,
0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03,
0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33,
0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
},
{ // 0x35
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
},
{ // 0x36
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
},
{ // 0x37
0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a,
0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a,
0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a,
0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
},
{ // 0x38
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
},
{ // 0x39
0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34,
0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24,
0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14,
0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04,
},
{ // 0x3a
0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01,
0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11,
0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21,
0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
},
{ // 0x3b
0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e,
0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e,
0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e,
},
{ // 0x3c
0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b,
0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b,
0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b,
0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b,
},
{ // 0x3d
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
},
{ // 0x3e
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
},
{ // 0x3f
0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22,
0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32,
0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02,
0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12,
},
};
#ifdef FFUZZYPP_STATIC_SANITY_CHECKS
template <uintmax_t i>
struct translate_check
{
template <uintmax_t j>
struct translate_check_2
{
static constexpr const bool value =
table_translate[i][j] == (context_hash::next_state(i, j) & 0x3f);
};
static constexpr const bool value =
static_assert_query::is_all<translate_check_2, 64>::value;
};
static_assert(static_assert_query::is_all<translate_check, 64>::value,
"table_translate is not equivalent to actual context_hash translation.");
#endif
private:
char h;
public:
void reset(void) noexcept
{
h = hash_init;
}
void update(unsigned char c) noexcept
{
h = table_translate[static_cast<unsigned char>(h)][c & 0x3f];
}
char sum_in_base64(void) const noexcept
{
// sum for Base64 (returns Base64 index)
return h;
}
public:
context_hash_fast(void) noexcept = default; // initialize to undefined state
};
#ifdef FFUZZYPP_DECLARATIONS
constexpr const char context_hash_fast::table_translate[64][64];
#endif
}
#endif

495
src/ffuzzypp/digest.hpp

@ -0,0 +1,495 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest.hpp
Fuzzy digest (wrapper with converters)
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_DIGEST_HPP
#define FFUZZYPP_DIGEST_HPP
#include <algorithm>
#include <functional>
#include <string>
#include <type_traits>
#include "digest_data.hpp"
#include "digest_base.hpp"
#include "utils/type_modifier.hpp"
namespace ffuzzy {
// Wrapper class
template <bool IsAlphabetRestricted, bool IsShort, bool IsNormalized> class digest;
// Digest (alphabet restricted; short; normalized)
template <>
class digest<true, true, true>
: public digest_base<true, true, true>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<true, true, true>(other) {}
explicit digest(const char* str) noexcept(false) : digest_base<true, true, true>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<true, true, true>::operator=(other);
return *this;
}
};
// Digest (alphabet restricted; short; unnormalized)
template <>
class digest<true, true, false>
: public digest_base<true, true, false>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<true, true, false>(other) {}
digest(const digest<true, true, true>& other) noexcept
{
digest_data<true, true>::operator=(other);
}
explicit digest(const char* str) noexcept(false) : digest_base<true, true, false>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<true, true, false>::operator=(other);
return *this;
}
const digest& operator=(const digest<true, true, true>& other) noexcept
{
digest_data<true, true>::operator=(other);
return *this;
}
};
// Digest (alphabet restricted; long; normalized)
template <>
class digest<true, false, true>
: public digest_base<true, false, true>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<true, false, true>(other) {}
digest(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
}
explicit digest(const char* str) noexcept(false) : digest_base<true, false, true>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<true, false, true>::operator=(other);
return *this;
}
const digest& operator=(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
return *this;
}
};
// Digest (alphabet restricted; long; unnormalized)
template <>
class digest<true, false, false>
: public digest_base<true, false, false>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<true, false, false>(other) {}
digest(const digest<true, false, true>& other) noexcept
{
digest_data<true, false>::operator=(other);
}
digest(const digest<true, true, false>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
}
digest(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
}
explicit digest(const char* str) noexcept(false) : digest_base<true, false, false>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<true, false, false>::operator=(other);
return *this;
}
const digest& operator=(const digest<true, false, true>& other) noexcept
{
digest_data<true, false>::operator=(other);
return *this;
}
const digest& operator=(const digest<true, true, false>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
return *this;
}
const digest& operator=(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
return *this;
}
};
// Digest (alphabet not restricted; short; normalized)
template <>
class digest<false, true, true>
: public digest_base<false, true, true>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<false, true, true>(other) {}
digest(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
}
explicit digest(const char* str) noexcept(false) : digest_base<false, true, true>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<false, true, true>::operator=(other);
return *this;
}
const digest& operator=(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
return *this;
}
};
// Digest (alphabet not restricted; short; unnormalized)
template <>
class digest<false, true, false>
: public digest_base<false, true, false>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<false, true, false>(other) {}
digest(const digest<false, true, true>& other) noexcept
{
digest_data<false, true>::operator=(other);
}
digest(const digest<true, true, false>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
}
digest(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
}
explicit digest(const char* str) noexcept(false) : digest_base<false, true, false>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<false, true, false>::operator=(other);
return *this;
}
const digest& operator=(const digest<false, true, true>& other) noexcept
{
digest_data<false, true>::operator=(other);
return *this;
}
const digest& operator=(const digest<true, true, false>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
return *this;
}
const digest& operator=(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
return *this;
}
};
// Digest (alphabet not restricted; long; normalized)
template <>
class digest<false, false, true>
: public digest_base<false, false, true>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<false, false, true>(other) {}
digest(const digest<false, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
}
digest(const digest<true, false, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
}
digest(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long_non_ra(*this, other);
}
explicit digest(const char* str) noexcept(false) : digest_base<false, false, true>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<false, false, true>::operator=(other);
return *this;
}
const digest& operator=(const digest<false, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
return *this;
}
const digest& operator=(const digest<true, false, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
return *this;
}
const digest& operator=(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long_non_ra(*this, other);
return *this;
}
};
// Digest (alphabet not restricted; long; unnormalized)
template <>
class digest<false, false, false>
: public digest_base<false, false, false>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<false, false, false>(other) {}
digest(const digest<false, false, true>& other) noexcept
{
digest_data<false, false>::operator=(other);
}
digest(const digest<false, true, false>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
}
digest(const digest<false, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
}
digest(const digest<true, false, false>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
}
digest(const digest<true, false, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
}
digest(const digest<true, true, false>& other) noexcept
{
internal::digest_copy::copy_to_long_non_ra(*this, other);
}
digest(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long_non_ra(*this, other);
}
explicit digest(const char* str) noexcept(false) : digest_base<false, false, false>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<false, false, false>::operator=(other);
return *this;
}
const digest& operator=(const digest<false, false, true>& other) noexcept
{
digest_data<false, false>::operator=(other);
return *this;
}
const digest& operator=(const digest<false, true, false>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
return *this;
}
const digest& operator=(const digest<false, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
return *this;
}
const digest& operator=(const digest<true, false, false>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
return *this;
}
const digest& operator=(const digest<true, false, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
return *this;
}
const digest& operator=(const digest<true, true, false>& other) noexcept
{
internal::digest_copy::copy_to_long_non_ra(*this, other);
return *this;
}
const digest& operator=(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long_non_ra(*this, other);
return *this;
}
};
// Typedefs for digest specializations
typedef digest<false, true, true> digest_t;
typedef digest<false, true, false> digest_unorm_t;
typedef digest<false, false, true> digest_long_t;
typedef digest<false, false, false> digest_long_unorm_t;
typedef digest< true, true, true> digest_ra_t;
typedef digest< true, true, false> digest_ra_unorm_t;
typedef digest< true, false, true> digest_ra_long_t;
typedef digest< true, false, false> digest_ra_long_unorm_t;
/*
Type modifiers
*/
namespace internal
{
template <typename T>
struct digest_traits
{
static constexpr const bool is_valid = false;
};
template <bool IsAlphabetRestricted, bool IsShort, bool IsNormalized>
struct digest_traits<digest_base<IsAlphabetRestricted, IsShort, IsNormalized>>
{
static constexpr const bool is_valid = true;
typedef digest_base<IsAlphabetRestricted, IsShort, true> norm_type;
typedef digest_base<IsAlphabetRestricted, IsShort, false> unorm_type;
typedef digest_base<IsAlphabetRestricted, true, IsNormalized> short_type;
typedef digest_base<IsAlphabetRestricted, false, IsNormalized> long_type;
typedef digest_base< true, IsShort, IsNormalized> ra_type;
typedef digest_base<false, IsShort, IsNormalized> non_ra_type;
};
template <bool IsAlphabetRestricted, bool IsShort, bool IsNormalized>
struct digest_traits<digest<IsAlphabetRestricted, IsShort, IsNormalized>>
{
static constexpr const bool is_valid = true;
typedef digest<IsAlphabetRestricted, IsShort, true> norm_type;
typedef digest<IsAlphabetRestricted, IsShort, false> unorm_type;
typedef digest<IsAlphabetRestricted, true, IsNormalized> short_type;
typedef digest<IsAlphabetRestricted, false, IsNormalized> long_type;
typedef digest< true, IsShort, IsNormalized> ra_type;
typedef digest<false, IsShort, IsNormalized> non_ra_type;
};
template <typename T>
struct digest_alt_type_selector
{
private:
typedef digest_traits<typename std::remove_cv<T>::type> traits_type;
static_assert(traits_type::is_valid, "You must give correct type to retrieve alternative types.");
public:
typedef typename type_mod::cv_match<T, typename traits_type::norm_type>::type norm_type;
typedef typename type_mod::cv_match<T, typename traits_type::unorm_type>::type unorm_type;
typedef typename type_mod::cv_match<T, typename traits_type::short_type>::type short_type;
typedef typename type_mod::cv_match<T, typename traits_type::long_type>::type long_type;
typedef typename type_mod::cv_match<T, typename traits_type::ra_type>::type ra_type;
typedef typename type_mod::cv_match<T, typename traits_type::non_ra_type>::type non_ra_type;
};
}
template <typename T> using digest_to_unorm = typename internal::digest_alt_type_selector<T>::unorm_type;
template <typename T> using digest_to_norm = typename internal::digest_alt_type_selector<T>::norm_type;
template <typename T> using digest_to_short = typename internal::digest_alt_type_selector<T>::short_type;
template <typename T> using digest_to_long = typename internal::digest_alt_type_selector<T>::long_type;
template <typename T> using digest_to_ra = typename internal::digest_alt_type_selector<T>::ra_type;
template <typename T> using digest_to_non_ra = typename internal::digest_alt_type_selector<T>::non_ra_type;
/*
We expect following properties for each digest types:
* is a trivially default constructible type
* is a standard-layout type
Digest types are:
* digest_data<IsAlphabetRestricted, IsShort>
* digest<IsAlphabetRestricted, IsShort, true>
* digest<IsAlphabetRestricted, IsShort, false>
We also expect that these types are nearly equivalent.
*/
#ifdef FFUZZYPP_LOCAL_CHK
#error do not define FFUZZYPP_LOCAL_CHK
#endif
#ifdef FFUZZYPP_LOCAL_CHK1
#error do not define FFUZZYPP_LOCAL_CHK1
#endif
#define FFUZZYPP_LOCAL_CHK1(IsAlphabetRestricted, IsShort, IsNormalized) \
static_assert(std::is_trivially_default_constructible<digest<IsAlphabetRestricted, IsShort, IsNormalized>>::value, \
"digest<" #IsAlphabetRestricted ", " #IsShort ", " #IsNormalized "> must be a trivially default constructible type."); \
static_assert(std::is_standard_layout<digest<IsAlphabetRestricted, IsShort, IsNormalized>>::value, \
"digest<" #IsAlphabetRestricted ", " #IsShort ", " #IsNormalized "> must be a standard-layout type."); \
static_assert(std::is_base_of<digest_data<IsAlphabetRestricted, IsShort>, digest<IsAlphabetRestricted, IsShort, IsNormalized>>::value, \
"digest_data<" #IsAlphabetRestricted ", " #IsShort ">, digest<" #IsAlphabetRestricted ", " #IsShort ", true> and " \
"digest<" #IsAlphabetRestricted ", " #IsShort ", false> must be nearly equivalent."); \
static_assert(sizeof(digest_data<IsAlphabetRestricted, IsShort>) == sizeof(digest<IsAlphabetRestricted, IsShort, IsNormalized>), \
"digest_data<" #IsAlphabetRestricted ", " #IsShort ">, digest<" #IsAlphabetRestricted ", " #IsShort ", true> and " \
"digest<" #IsAlphabetRestricted ", " #IsShort ", false> must be nearly equivalent.")
#define FFUZZYPP_LOCAL_CHK(IsAlphabetRestricted, IsShort) \
static_assert(std::is_trivially_default_constructible<digest_data<IsAlphabetRestricted, IsShort>>::value, \
"digest_data<" #IsAlphabetRestricted ", " #IsShort "> must be a trivially default constructible type."); \
static_assert(std::is_standard_layout<digest_data<IsAlphabetRestricted, IsShort>>::value, \
"digest_data<" #IsAlphabetRestricted ", " #IsShort "> must be a standard-layout type."); \
FFUZZYPP_LOCAL_CHK1(IsAlphabetRestricted, IsShort, true); \
FFUZZYPP_LOCAL_CHK1(IsAlphabetRestricted, IsShort, false)
FFUZZYPP_LOCAL_CHK(true, true);
FFUZZYPP_LOCAL_CHK(true, false);
FFUZZYPP_LOCAL_CHK(false, true);
FFUZZYPP_LOCAL_CHK(false, false);
#undef FFUZZYPP_LOCAL_CHK
#undef FFUZZYPP_LOCAL_CHK1
}
// Specialization of standard hash and swap
namespace std
{
template <bool IsAlphabetRestricted, bool IsShort, bool IsNormalized>
struct hash<ffuzzy::digest<IsAlphabetRestricted, IsShort, IsNormalized>>
{
size_t operator()(const ffuzzy::digest<IsAlphabetRestricted, IsShort, IsNormalized>& value) const
{
return value.hash();
}
};
template <bool IsAlphabetRestricted, bool IsShort, bool IsNormalized>
inline void swap(
ffuzzy::digest<IsAlphabetRestricted, IsShort, IsNormalized>& a,
ffuzzy::digest<IsAlphabetRestricted, IsShort, IsNormalized>& b
) noexcept
{
ffuzzy::digest<IsAlphabetRestricted, IsShort, IsNormalized>::swap(a, b);
}
}
#endif

254
src/ffuzzypp/digest_base.hpp

@ -0,0 +1,254 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest_base.hpp
Fuzzy digest (wrapper with comparison methods)
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_DIGEST_BASE_HPP
#define FFUZZYPP_DIGEST_BASE_HPP
#include <string>
#include "digest_blocksize.hpp"
#include "digest_data.hpp"
#include "digest_comparison.hpp"
#include "utils/type_modifier.hpp"
namespace ffuzzy {
template <bool IsAlphabetRestricted, bool IsShort, bool IsNormalized> class digest_base;
// Normalized form of digest (with specialized/fast comparison)
template <bool IsAlphabetRestricted, bool IsShort>
class digest_base<IsAlphabetRestricted, IsShort, true>
: public digest_data<IsAlphabetRestricted, IsShort>
{
public:
digest_base(void) noexcept = default; // initialize to undefined state
digest_base(const digest_base& other) noexcept : digest_data<IsAlphabetRestricted, IsShort>(other) {}
const digest_base& operator=(const digest_base& other) noexcept
{
digest_data<IsAlphabetRestricted, IsShort>::operator=(other);
return *this;
}
public:
explicit digest_base(const char* str) noexcept(false)
{
if (!digest_data<IsAlphabetRestricted, IsShort>::parse_normalized(*this, str))
throw digest_parse_error();
}
explicit digest_base(const std::string& str)
: digest_base(str.c_str()) {}
static bool parse_normalized(digest_base& digest, const char* str) noexcept
{
return digest_data<IsAlphabetRestricted, IsShort>::parse_normalized(digest, str);
}
static bool parse(digest_base& digest, const char* str) noexcept
{
return digest_data<IsAlphabetRestricted, IsShort>::parse_normalized(digest, str);
}
public:
bool is_valid(void) const noexcept
{
return digest_data<IsAlphabetRestricted, IsShort>::is_valid() && this->template is_normalized();
}
// Comparison
public:
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_identical(
const digest_base& value
) noexcept
{
return digest_comparison<Version>::compare_identical(value);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare_near(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_lt(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare_near_lt(a, b);
}
public:
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare(const digest_base& other) const noexcept
{
return compare<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_identical(void) const noexcept
{
return compare_identical<Version>(*this);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near(const digest_base& other) const noexcept
{
return compare_near<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_eq(const digest_base& other) const noexcept
{
return compare_near_eq<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_lt(const digest_base& other) const noexcept
{
return compare_near_lt<Version>(*this, other);
}
// Comparison (on different digests)
public:
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_diff(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_diff(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare_near_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq_diff(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq_diff(a, b);
}
public:
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_diff(const digest_base& other) const noexcept
{
return compare_diff<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_diff(const digest_base& other) const noexcept
{
return compare_near_diff<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_eq_diff(const digest_base& other) const noexcept
{
return compare_near_eq_diff<Version>(*this, other);
}
};
// Unnormalized form of digest (with normalization ability and slow comparison)
template <bool IsAlphabetRestricted, bool IsShort>
class digest_base<IsAlphabetRestricted, IsShort, false>
: public digest_data<IsAlphabetRestricted, IsShort>
{
public:
digest_base(void) noexcept = default; // initialize to undefined state
digest_base(const digest_base& other) noexcept : digest_data<IsAlphabetRestricted, IsShort>(other) {}
digest_base(const digest_base<IsAlphabetRestricted, IsShort, true>& other) noexcept : digest_data<IsAlphabetRestricted, IsShort>(other) {}
const digest_base& operator=(const digest_base& other) noexcept
{
digest_data<IsAlphabetRestricted, IsShort>::operator=(other);
return *this;
}
const digest_base& operator=(const digest_base<IsAlphabetRestricted, IsShort, true>& other) noexcept
{
digest_data<IsAlphabetRestricted, IsShort>::operator=(other);
return *this;
}
public:
explicit digest_base(const char* str) noexcept(false)
{
if (!digest_data<IsAlphabetRestricted, IsShort>::parse(*this, str))
throw digest_parse_error();
}
explicit digest_base(const std::string& str)
: digest_base(str.c_str()) {}
static bool parse_normalized(digest_base& digest, const char* str) noexcept
{
return digest_data<IsAlphabetRestricted, IsShort>::parse_normalized(digest, str);
}
static bool parse(digest_base& digest, const char* str) noexcept
{
return digest_data<IsAlphabetRestricted, IsShort>::parse(digest, str);
}
public:
digest_base<IsAlphabetRestricted, IsShort, true> to_normalized(void) const noexcept
{
return digest_data<IsAlphabetRestricted, IsShort>::
template normalize<digest_base<IsAlphabetRestricted, IsShort, true>>(*this);
}
explicit operator digest_base<IsAlphabetRestricted, IsShort, true>(void) const noexcept { return to_normalized(); }
public:
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare_unnormalized(a, b);
}
public:
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare(const digest_base& other) const noexcept { return compare<Version>(*this, other); }
};
}
#endif

255
src/ffuzzypp/digest_blocksize.hpp

@ -0,0 +1,255 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest_blocksize.hpp
Fuzzy digest block size utilities
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_DIGEST_BLOCKSIZE_HPP
#define FFUZZYPP_DIGEST_BLOCKSIZE_HPP
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <limits>
#include "utils/safe_int.hpp"
#include "utils/static_assert_query.hpp"
#include "utils/numeric_digits.hpp"
namespace ffuzzy {
// Block size type for fuzzy digest
typedef uint_least32_t digest_blocksize_t;
// Block size utilities
class digest_blocksize
{
static_assert(
safe_int::contracts::is_unsigned_integral_type<digest_blocksize_t>() &&
std::numeric_limits<digest_blocksize_t>::max() >= 0xfffffffful,
"digest_blocksize_t must be an unsigned integral type which can represent all 32-bit values."
);
private:
digest_blocksize(void) = delete;
digest_blocksize(const digest_blocksize&) = delete;
// Parameters
public:
static constexpr const unsigned number_of_blockhashes = 31;
static constexpr const digest_blocksize_t min_blocksize = 3;
static constexpr const digest_blocksize_t max_blocksize = min_blocksize << (number_of_blockhashes - 1);
static_assert(min_blocksize != 0, "min_blocksize must not be zero.");
static_assert(number_of_blockhashes != 0, "number_of_blockhashes must not be zero.");
static_assert(number_of_blockhashes <= 32, "number_of_blockhashes must be less than 32.");
static_assert(min_blocksize <= 0xfffffffful, "min_blocksize must be less than 2^32.");
static_assert(
safe_int::safe_lshift<
safe_int::uvalue<digest_blocksize_t, min_blocksize>,
safe_int::uvalue<unsigned, number_of_blockhashes - 1>
>::is_valid &&
(min_blocksize << (number_of_blockhashes - 1)) <= 0xfffffffful,
"(min_blocksize << (number_of_blockhashes - 1)) must be less than 2^32.");
// Maximum characters required to represent all "natural" block sizes
// (excluding '\0' character at the end)
public:
static constexpr const size_t max_natural_digits =
numeric_digits::in_decimal(max_blocksize);
// Block size naturality
// (whether this is possibly generated by ssdeep)
public:
static bool is_natural(digest_blocksize_t blocksize) noexcept
{
if (blocksize < min_blocksize)
return false;
if (blocksize > max_blocksize)
return false;
while (blocksize != min_blocksize)
{
if (blocksize % 2 != 0)
return false;
blocksize /= 2;
}
return true;
}
// Utility to prevent arithmetic overflow
public:
static constexpr bool is_safe_to_double(digest_blocksize_t value) noexcept
{
return value <= (std::numeric_limits<digest_blocksize_t>::max() / 2);
}
/*
"Near" relations
fuzzy digests are compared against other if their block sizes are "near".
There are three such cases (if there is no arithmetic overflow).
Case 1: a == b (eq)
Digest A : 3:xxxxxxx:yyyyyyy
Digest A : 3:xxxxxxx:yyyyyyy
| ~~~~~~~ ~~~~~~~
| (both block hashes are compared and the maximum score is chosen)
Case 2: a * 2 == b (implies a < b; lt)
Digest A : 3:xxxxxxx:yyyyyyy
Digest B : 6: yyyyyyy:zzzzzzz
| ~~~~~~~
| (block hash in common block size is compared)
Case 3: a == b * 2 (implies a > b; gt)
Digest A : 6: yyyyyyy:zzzzzzz
Digest B : 3:xxxxxxx:yyyyyyy
| ~~~~~~~
| (block hash in common block size is compared)
*/
public:
static constexpr bool is_near_eq(digest_blocksize_t a, digest_blocksize_t b) noexcept
{
return a == b;
}
static constexpr bool is_near_lt(digest_blocksize_t a, digest_blocksize_t b) noexcept
{
return a != b && is_safe_to_double(a) && a * 2 == b;
}
static constexpr bool is_near_gt(digest_blocksize_t a, digest_blocksize_t b) noexcept
{
return a != b && a % 2 == 0 && a / 2 == b;
}
static constexpr bool is_near_leq(digest_blocksize_t a, digest_blocksize_t b) noexcept
{
return is_near_eq(a, b) || is_near_lt(a, b);
}
static constexpr bool is_near(digest_blocksize_t a, digest_blocksize_t b) noexcept
{
return is_near_eq(a, b) || is_near_lt(a, b) || is_near_gt(a, b);
}
// Utility to convert block size index to a natural block size
public:
static constexpr digest_blocksize_t at(unsigned index) noexcept
{
return min_blocksize << index;
}
// Utility to convert natural block size to corresponding block size index
private:
template <bool UseMagic, typename Tdummy = void> class natural_to_index_impl;
// Implementation by magic table
// (not general [depends on ssdeep parameters] but possibly fast)
static constexpr const digest_blocksize_t nti_magic_mul = digest_blocksize_t(0x017713caul);
static constexpr const unsigned nti_magic_table[31] =
{
0x00, 0x01, 0x02, 0x06, 0x03, 0x0b, 0x07, 0x10,
0x04, 0x0e, 0x0c, 0x18, 0x08, 0x15, 0x11, 0x1a,
0x1e, 0x05, 0x0a, 0x0f, 0x0d, 0x17, 0x14, 0x19,
0x1d, 0x09, 0x16, 0x13, 0x1c, 0x12, 0x1b,
};
template <typename Tdummy>
class natural_to_index_impl<true, Tdummy>
{
public:
static constexpr unsigned natural_to_index_unsafe(digest_blocksize_t blocksize) noexcept
{
return nti_magic_table[((blocksize * nti_magic_mul) >> 27) & 0x1f];
}
private:
#ifdef FFUZZYPP_STATIC_SANITY_CHECKS
template <uintmax_t i>
struct seq_check
{
static constexpr const bool value =
natural_to_index_unsafe(min_blocksize << i) == i;
};
static_assert(static_assert_query::is_all<seq_check, number_of_blockhashes>::value,
"magic table is not constructed correctly.");
#endif
};
// Implementation by De Brujin sequence
// (general but requires a division to make index_from work)
static constexpr const digest_blocksize_t nti_debrujin_mul = digest_blocksize_t(0x077cb531ul);
static constexpr const unsigned nti_debrujin_table[32] =
{
0x00, 0x01, 0x1c, 0x02, 0x1d, 0x0e, 0x18, 0x03,
0x1e, 0x16, 0x14, 0x0f, 0x19, 0x11, 0x04, 0x08,
0x1f, 0x1b, 0x0d, 0x17, 0x15, 0x13, 0x10, 0x07,
0x1a, 0x0c, 0x12, 0x06, 0x0b, 0x05, 0x0a, 0x09,
};
template <typename Tdummy>
class natural_to_index_impl<false, Tdummy>
{
public:
static constexpr unsigned natural_to_index_unsafe(digest_blocksize_t blocksize) noexcept
{
return nti_debrujin_table[((blocksize / min_blocksize * nti_debrujin_mul) >> 27) & 0x1f];
}
private:
#ifdef FFUZZYPP_STATIC_SANITY_CHECKS
template <uintmax_t i>
struct seq_check
{
static constexpr const bool value =
natural_to_index_unsafe(min_blocksize << i) == i;
};
static_assert(static_assert_query::is_all<seq_check, number_of_blockhashes>::value,
"De Brujin sequence is not constructed correctly.");
#endif
};
static constexpr const bool nti_is_magic_available =
min_blocksize == 3 && number_of_blockhashes <= 31;
public:
template <bool UseDebrujin = false>
static constexpr unsigned natural_to_index_unsafe(digest_blocksize_t blocksize) noexcept
{
return natural_to_index_impl<
nti_is_magic_available && !UseDebrujin
>::natural_to_index_unsafe(blocksize);
}
template <bool UseDebrujin = false>
static unsigned natural_to_index(digest_blocksize_t blocksize) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(is_natural(blocksize));
#endif
return natural_to_index_unsafe<UseDebrujin>(blocksize);
}
};
#ifdef FFUZZYPP_DECLARATIONS
constexpr const unsigned digest_blocksize::nti_magic_table[31];
constexpr const unsigned digest_blocksize::nti_debrujin_table[32];
#endif
}
#endif

1167
src/ffuzzypp/digest_comparison.hpp

File diff suppressed because it is too large

649
src/ffuzzypp/digest_data.hpp

@ -0,0 +1,649 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest_data.hpp
Fuzzy digest (data and basic portions)
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_DIGEST_DATA_HPP
#define FFUZZYPP_DIGEST_DATA_HPP
#include <cassert>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <limits>
#include <string>
#include <type_traits>
#include <utility>
#include <errno.h>
#include "base64.hpp"
#include "digest_blocksize.hpp"
#include "strings/sequences.hpp"
#include "strings/nosequences.hpp"
#include "utils/safe_int.hpp"
#include "utils/numeric_digits.hpp"
namespace ffuzzy {
typedef size_t blockhash_len_t;
static_assert(
safe_int::contracts::is_unsigned_integral_type<blockhash_len_t>(),
"blockhash_len_t must be an unsigned integral type.");
struct digest_parse_error {};
class digest_params
{
private:
digest_params(void) = delete;
digest_params(const digest_params&) = delete;
// Common digest parameters (for both short and long forms)
public:
static constexpr const blockhash_len_t max_blockhash_len = 64;
static constexpr const blockhash_len_t max_blockhash_sequence = 3;
static_assert(max_blockhash_len >= 2, "max_blockhash_len must be 2 or greater.");
static_assert(max_blockhash_sequence != 0, "max_blockhash_sequence must not be zero.");
static_assert(safe_int::uvalue<size_t, max_blockhash_len>::is_valid,
"max_blockhash_len must be in range of size_t.");
static_assert(safe_int::uvalue<size_t, max_blockhash_sequence>::is_valid,
"max_blockhash_sequence must be in range of size_t.");
};
template <bool IsAlphabetRestricted> class digest_data_transformation;
template<>
class digest_data_transformation<true>
{
private:
digest_data_transformation(void) = delete;
digest_data_transformation(const digest_data_transformation&) = delete;
public:
typedef base64::transform_from_b64 input_type;
typedef base64::transform_to_b64 output_type;
};
template<>
class digest_data_transformation<false>
{
private:
digest_data_transformation(void) = delete;
digest_data_transformation(const digest_data_transformation&) = delete;
public:
typedef strings::default_char_transform input_type;
typedef strings::default_char_transform output_type;
};
// Friend classes for digest_data class
enum struct comparison_version;
namespace internal
{
template <comparison_version> class digest_comparison_base;
class digest_copy;
}
template <comparison_version> class digest_comparison;
template <bool> class digest_position_array_base;
// Data structure for fuzzy digest (as base class)
template <bool IsAlphabetRestricted, bool IsShort>
class digest_data
{
static_assert(digest_params::max_blockhash_len >= 4,
"max_blockhash_len must be at least 4 due to restrictions in this implementation.");
// Maximum lengths for each block hashes
public:
static constexpr const blockhash_len_t max_blockhash1_len = digest_params::max_blockhash_len;
static constexpr const blockhash_len_t max_blockhash2_len = IsShort
? digest_params::max_blockhash_len / 2
: digest_params::max_blockhash_len;
// Maximum characters required to pretty-print "natural" digests
public:
static_assert(safe_int::safe_mul<
safe_int::uvalue<blockhash_len_t, digest_params::max_blockhash_len>,
safe_int::uvalue<blockhash_len_t, 2>
>::is_valid,
"max_blockhash_len * 2 must be in range of blockhash_len_t.");
static_assert(
safe_int::safe_add<
safe_int::safe_add<
safe_int::uvalue<size_t, 3>,
safe_int::uvalue<size_t, digest_blocksize::max_natural_digits>
>,
safe_int::safe_mul<
safe_int::uvalue<size_t, digest_params::max_blockhash_len>,
safe_int::uvalue<size_t, 2>
>
>::is_valid,
"max_blockhash_len * 2 + max_natural_digits + 3 must be in range of size_t.");
static constexpr const size_t max_natural_chars =
max_blockhash1_len + max_blockhash2_len + // two block hashes
digest_blocksize::max_natural_digits + // block size
3; // two colons and '\0' as a terminator
// width == chars exclusing '\0' (== chars - 1)
static constexpr const size_t max_natural_width = max_natural_chars - 1;
static constexpr const size_t max_natural_width_digits =
numeric_digits::in_decimal<size_t>(max_natural_width);
static_assert(max_natural_width != 0, "sanity check for max_natural_width failed.");
// Data structure
private:
char digest[max_blockhash1_len + max_blockhash2_len];
blockhash_len_t blkhash1_len;
blockhash_len_t blkhash2_len;
digest_blocksize_t blksize;
public:
size_t blockhash1_len(void) const noexcept { return blkhash1_len; }
size_t blockhash2_len(void) const noexcept { return blkhash2_len; }
unsigned long blocksize(void) const noexcept { return blksize; }
size_t digest_size_used(void) const noexcept { return blkhash1_len + blkhash2_len; }
const char* digest_buffer(void) const noexcept { return digest; }
void copy_digest_buffer(char* buf) const noexcept { memcpy(buf, digest, digest_size_used()); }
// "Initialization" and assignment
public:
digest_data(void) noexcept = default; // initialize to undefined state
digest_data(const digest_data& other) noexcept
: blkhash1_len(other.blkhash1_len)
, blkhash2_len(other.blkhash2_len)
, blksize(other.blksize)
{
#ifdef FFUZZYPP_DEBUG
assert(other.is_valid());
#endif
if (digest != other.digest)
memcpy(digest, other.digest, blkhash1_len + blkhash2_len);
}
const digest_data& operator=(const digest_data& other) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(other.is_valid());
#endif
blkhash1_len = other.blkhash1_len;
blkhash2_len = other.blkhash2_len;
blksize = other.blksize;
if (digest != other.digest)
memcpy(digest, other.digest, blkhash1_len + blkhash2_len);
return *this;
}
static void swap(digest_data& a, digest_data& b) noexcept
{
std::swap(a.blksize, b.blksize);
std::swap(a.blkhash1_len, b.blkhash1_len);
std::swap(a.blkhash2_len, b.blkhash2_len);
std::swap(a.digest, b.digest); // C++11 version of swap
}
// Validators (for its validness and naturality)
public:
bool is_valid(void) const noexcept
{
if (blkhash1_len > max_blockhash1_len)
return false;
if (blkhash2_len > max_blockhash2_len)
return false;
if (blksize > 0xfffffffful)
return false;
if (IsAlphabetRestricted)
{
for (blockhash_len_t i = 0, l = blkhash1_len + blkhash2_len; i < l; i++)
if (digest[i] < char(0) || 64 <= digest[i])
return false;
}
return true;
}
bool is_natural(void) const noexcept
{
if (!is_valid())
return false;
if (blkhash1_len < blkhash2_len)
return false;
if (!digest_blocksize::is_natural(blksize))
return false;
if (!digest_blocksize::is_safe_to_double(blksize) && blkhash2_len >= 2)
return false;
if (!IsAlphabetRestricted)
{
for (blockhash_len_t i = 0, l = blkhash1_len + blkhash2_len; i < l; i++)
if (!base64::isbase64(digest[i]))
return false;
}
return true;
}
bool is_blocksize_natural(void) const noexcept
{
return digest_blocksize::is_natural(blksize);
}
bool is_normalized(void) const noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(is_valid());
#endif
return
!strings::sequences<digest_params::max_blockhash_sequence>
::has_sequences(digest, blkhash1_len) &&
!strings::sequences<digest_params::max_blockhash_sequence>
::has_sequences(digest+blkhash1_len, blkhash2_len);
}
bool has_valid_base64_data(void) const noexcept
{
if (blkhash1_len > max_blockhash1_len)
return false;
if (blkhash2_len > max_blockhash2_len)
return false;
if (IsAlphabetRestricted)
{
for (blockhash_len_t i = 0, l = blkhash1_len + blkhash2_len; i < l; i++)
if (digest[i] < char(0) || 64 <= digest[i])
return false;
}
else
{
for (blockhash_len_t i = 0, l = blkhash1_len + blkhash2_len; i < l; i++)
if (!base64::isbase64(digest[i]))
return false;
}
return true;
}
// Equality
private:
static bool is_eq_except_blocksize(const digest_data& a, const digest_data& b) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(a.is_valid());
assert(b.is_valid());
#endif
return
a.blkhash1_len == b.blkhash1_len &&
a.blkhash2_len == b.blkhash2_len &&
memcmp(a.digest, b.digest, a.digest_size_used()) == 0;
}
static bool is_eq(const digest_data& a, const digest_data& b) noexcept
{
return
digest_blocksize::is_near_eq(a.blksize, b.blksize) &&
is_eq_except_blocksize(a, b);
}
public:
friend bool operator==(const digest_data& a, const digest_data& b) noexcept { return is_eq(a, b); }
friend bool operator!=(const digest_data& a, const digest_data& b) noexcept { return !is_eq(a, b); }
// Default comparison for sorting (in "dictionary" order or whatever)
// Note that sort order differs depending on IsAlphabetRestricted.
public:
friend bool operator<(const digest_data& a, const digest_data& b) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(a.is_valid());
assert(b.is_valid());
#endif
if (a.blksize < b.blksize)
return true;
if (a.blksize > b.blksize)
return false;
if (a.blkhash1_len < b.blkhash1_len)
return true;
if (a.blkhash1_len > b.blkhash1_len)
return false;
if (a.blkhash2_len < b.blkhash2_len)
return true;
if (a.blkhash2_len > b.blkhash2_len)
return false;
if (memcmp(a.digest, b.digest, a.digest_size_used()) < 0)
return true;
return false;
}
friend bool operator>(const digest_data& a, const digest_data& b) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(a.is_valid());
assert(b.is_valid());
#endif
if (a.blksize > b.blksize)
return true;
if (a.blksize < b.blksize)
return false;
if (a.blkhash1_len > b.blkhash1_len)
return true;
if (a.blkhash1_len < b.blkhash1_len)
return false;
if (a.blkhash2_len > b.blkhash2_len)
return true;
if (a.blkhash2_len < b.blkhash2_len)
return false;
if (memcmp(a.digest, b.digest, a.digest_size_used()) > 0)
return true;
return false;
}
friend bool operator<=(const digest_data& a, const digest_data& b) noexcept { return !(a > b); }
friend bool operator>=(const digest_data& a, const digest_data& b) noexcept { return !(a < b); }
// Predicates (including non-standard comparison predicates for fast sorting)
public:
struct pred_equal_to
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept { return a == b; }
};
struct pred_not_equal_to
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept { return a != b; }
};
struct pred_less
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept { return a < b; }
};
struct pred_less_equal
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept { return a <= b; }
};
struct pred_greater
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept { return a > b; }
};
struct pred_greater_equal
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept { return a >= b; }
};
struct pred_less_blocksize
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept
{
return a.blksize < b.blksize;
}
};
struct pred_less_blocksize_natural
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept
{
bool aN = digest_blocksize::is_natural(a.blksize);
bool bN = digest_blocksize::is_natural(b.blksize);
if (aN && !bN)
return false;
if (!aN && bN)
return true;
if (a.blksize < b.blksize)
return true;
return false;
}
};
// Hash (for sets and dictionaries)
public:
size_t hash(void) const noexcept
{
typedef typename std::conditional<
(std::numeric_limits<size_t>::max() >= 0xfffffffful),
size_t, uint_least32_t
>::type hash_t;
static constexpr const hash_t fnv_init = 2166136261ul;
static constexpr const hash_t fnv_prime = 16777619ul;
hash_t h = fnv_init;
h ^= hash_t(blksize); h *= fnv_prime;
h ^= hash_t(blkhash1_len); h *= fnv_prime;
h ^= hash_t(blkhash2_len); h *= fnv_prime;
for (blockhash_len_t i = 0, l = blkhash1_len + blkhash2_len; i < l; i++)
{
h ^= hash_t(static_cast<unsigned char>(digest[i]));
h *= fnv_prime;
}
if (std::numeric_limits<size_t>::max() < 0xfffffffful)
h ^= (h >> 16);
return size_t(h);
}
// Normalization
public:
static void normalize(digest_data& dest, const digest_data& source) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(source.is_valid());
#endif
dest.blksize = source.blksize;
blockhash_len_t orig_blkhash1_len = source.blkhash1_len;
dest.blkhash1_len = strings::sequences<digest_params::max_blockhash_sequence>
::copy_elim_sequences(dest.digest, source.digest, source.blkhash1_len);
dest.blkhash2_len = strings::sequences<digest_params::max_blockhash_sequence>
::copy_elim_sequences(dest.digest + dest.blkhash1_len, source.digest + orig_blkhash1_len, source.blkhash2_len);
#ifdef FFUZZYPP_DEBUG
assert(dest.is_valid());
assert(dest.is_normalized());
#endif
}
template <typename Treturn = digest_data>
static Treturn normalize(const digest_data& source) noexcept
{
Treturn dest;
digest_data::normalize(dest, source);
return dest;
}
void normalize(void) noexcept
{
normalize(*this, *this);
}
// Utility to parse digests
private:
template <template <char... terms> class Tstring_copy>
static bool parse_internal(digest_data& digest, const char* str) noexcept
{
const char* rem = str;
char* out = digest.digest;
errno = 0;
// size of unsigned long is at least 32-bit
unsigned long blksize = strtoul(str, const_cast<char**>(&rem), 10);
if (rem == str)
return false;
if (errno == ERANGE && blksize == std::numeric_limits<unsigned long>::max())
return false;
if (blksize > 0xfffffffful)
return false;
digest.blksize = digest_blocksize_t(blksize);
if (*rem++ != ':')
return false;
if (!Tstring_copy<':'>::copy_elim_sequences(out, max_blockhash1_len, rem))
return false;
digest.blkhash1_len = out - digest.digest;
char* outtmp = out;
if (*rem++ != ':')
return false;
#ifndef FFUZZYPP_BLOCKDIGEST2_TERMS
// default from ffuzzy++ 4.0
#define FFUZZYPP_BLOCKDIGEST2_TERMS ','
#endif
if (!Tstring_copy<FFUZZYPP_BLOCKDIGEST2_TERMS>::
copy_elim_sequences(out, max_blockhash2_len, rem))
return false;
digest.blkhash2_len = out - outtmp;
if (IsAlphabetRestricted)
{
for (blockhash_len_t i = 0; i < digest.blkhash1_len + digest.blkhash2_len; i++)
{
if (digest.digest[i] == base64::invalid_index)
return false;
}
}
return true;
}
protected:
static bool parse(digest_data& digest, const char* str) noexcept
{
return parse_internal<
strings::nosequences<typename digest_data_transformation<IsAlphabetRestricted>::input_type>::template string_copy
>(digest, str);
}
static bool parse(digest_data& digest, const std::string& str)
{
return parse(digest, str.c_str());
}
static bool parse_normalized(digest_data& digest, const char* str) noexcept
{
return parse_internal<
strings::sequences<digest_params::max_blockhash_sequence,
typename digest_data_transformation<IsAlphabetRestricted>::input_type>::template string_copy
>(digest, str);
}
static bool parse_normalized(digest_data& digest, const std::string& str)
{
return parse_normalized(digest, str.c_str());
}
// Pretty printing
public:
bool pretty_unsafe(char* out) const noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(is_valid());
#endif
int n = sprintf(out, "%lu:", static_cast<unsigned long>(blksize));
if (n < 0)
return false;
out += n;
strings::nosequences<typename digest_data_transformation<IsAlphabetRestricted>::output_type>::copy_raw(out, digest, blkhash1_len);
out += blkhash1_len;
*out++ = ':';
strings::nosequences<typename digest_data_transformation<IsAlphabetRestricted>::output_type>::copy_raw(out, digest+blkhash1_len, blkhash2_len);
out[blkhash2_len] = '\0';
return true;
}
bool pretty(char* out, size_t outsize) const noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(is_valid());
#endif
int n = snprintf(out, outsize, "%lu:", static_cast<unsigned long>(blksize));
if (n < 0)
return false;
if (size_t(n) == outsize)
return false;
outsize -= size_t(n);
out += n;
if (outsize < size_t(blkhash1_len) + size_t(blkhash2_len) + 2)
return false;
strings::nosequences<typename digest_data_transformation<IsAlphabetRestricted>::output_type>::copy_raw(out, digest, blkhash1_len);
out += blkhash1_len;
*out++ = ':';
strings::nosequences<typename digest_data_transformation<IsAlphabetRestricted>::output_type>::copy_raw(out, digest+blkhash1_len, blkhash2_len);
out[blkhash2_len] = '\0';
return true;
}
std::string pretty(void) const
{
#ifdef FFUZZYPP_DEBUG
assert(is_valid());
#endif
unsigned long bs(blksize);
std::string str(std::to_string(bs));
str.push_back(':');
for (blockhash_len_t i = 0; i < blkhash1_len; i++)
str.push_back(digest_data_transformation<IsAlphabetRestricted>::output_type::transform(digest[i]));
str.push_back(':');
for (blockhash_len_t i = 0; i < blkhash2_len; i++)
str.push_back(digest_data_transformation<IsAlphabetRestricted>::output_type::transform(digest[blkhash1_len + i]));
return str;
}
// Friend classes
template <comparison_version> friend class internal::digest_comparison_base;
template <comparison_version> friend class digest_comparison;
template <bool> friend class digest_position_array_base;
friend class digest_generator;
friend class internal::digest_copy;
};
namespace internal
{
// Utility to copy constrained digest data to non-constrained digest object
class digest_copy
{
private:
digest_copy(void) = delete;
digest_copy(const digest_copy&) = delete;
public:
template <bool IsAlphabetRestricted>
static void copy_to_long(
digest_data<IsAlphabetRestricted, false>& dest,
const digest_data<IsAlphabetRestricted, true>& src
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(src.is_valid());
#endif
dest.blkhash1_len = src.blkhash1_len;
dest.blkhash2_len = src.blkhash2_len;
dest.blksize = src.blksize;
memcpy(dest.digest, src.digest, src.blkhash1_len + src.blkhash2_len);
}
template <bool IsShort>
static void copy_to_non_ra(
digest_data<false, IsShort>& dest,
const digest_data<true, IsShort>& src
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(src.is_valid());
#endif
dest.blkhash1_len = src.blkhash1_len;
dest.blkhash2_len = src.blkhash2_len;
dest.blksize = src.blksize;
strings::nosequences<base64::transform_to_b64>::
copy_raw(dest.digest, src.digest, src.blkhash1_len + src.blkhash2_len);
}
static void copy_to_long_non_ra(
digest_data<false, false>& dest,
const digest_data<true, true>& src
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(src.is_valid());
#endif
dest.blkhash1_len = src.blkhash1_len;
dest.blkhash2_len = src.blkhash2_len;
dest.blksize = src.blksize;
strings::nosequences<base64::transform_to_b64>::
copy_raw(dest.digest, src.digest, src.blkhash1_len + src.blkhash2_len);
}
};
}
}
#endif

125
src/ffuzzypp/digest_filesize.hpp

@ -0,0 +1,125 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest_filesize.hpp
File size utilities
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_DIGEST_FILESIZE_HPP
#define FFUZZYPP_DIGEST_FILESIZE_HPP
#include <cstddef>
#include <cstdint>
#include "digest_blocksize.hpp"
#include "digest_data.hpp"
#include "utils/safe_int.hpp"
namespace ffuzzy {
typedef uint_least64_t digest_filesize_t;
// File size utilities
class digest_filesize
{
static_assert(safe_int::contracts::is_unsigned_integral_type<digest_filesize_t>(),
"digest_filesize_t must be an unsigned integral type.");
private:
digest_filesize(void) = delete;
digest_filesize(const digest_filesize&) = delete;
// Minimum size (as supported by ssdeep)
private:
static constexpr const unsigned long u_min_supported_size = 4096 + 1;
public:
static_assert(u_min_supported_size <= 0xfffffffful,
"u_min_supported_size must be in range of 32-bit unsigned integer.");
static_assert(safe_int::uvalue<digest_filesize_t, u_min_supported_size>::is_valid,
"u_min_supported_size must be in range of digest_filesize_t.");
static constexpr const digest_filesize_t min_supported_size = u_min_supported_size;
// Maximum size (theoretical limit)
public:
static_assert(safe_int::safe_add<
safe_int::safe_mul<
safe_int::uvalue<digest_filesize_t, digest_blocksize::max_blocksize>,
safe_int::uvalue<digest_filesize_t, digest_params::max_blockhash_len>
>,
safe_int::uvalue<digest_filesize_t, 1>
>::is_valid,
"max_blocksize * max_blockhash_len + 1 (== max_size + 1) must be "
"in range of digest_filesize_t.");
static constexpr const digest_filesize_t max_size =
digest_filesize_t(digest_blocksize::max_blocksize) *
digest_filesize_t(digest_params::max_blockhash_len);
static constexpr const digest_filesize_t max_theoretical_size = max_size;
// Maximum portable size (with ssdeep 2.6-2.12)
public:
static_assert(safe_int::uvalue<digest_filesize_t, 0xfffffffful>::is_valid,
"digest_filesize_t must be able to represent all 32-bit unsigned integer values.");
static constexpr const digest_filesize_t max_portable_size =
minmax::min(max_size, digest_filesize_t(0xfffffffful));
static_assert(min_supported_size <= max_portable_size,
"min_supported_size must not exceed max_portable_size.");
// Predicates
public:
static constexpr bool is_portable(digest_filesize_t total_size) noexcept
{
/*
WARNING: Given size may not be "portable" on insane architectures.
Portability:
* ffuzzy++ (3.0)
* ssdeep (including 2.6-2.12)
Note:
Mr.Kornblum (the original author of ssdeep) considers
version 2.9 the "standard". Note that this release does not
support files equal to or larger than 4GiB.
*/
return total_size >= min_supported_size && total_size <= max_portable_size;
}
static constexpr bool is_supported_by_ssdeep_2_12(digest_filesize_t total_size) noexcept
{
return total_size >= min_supported_size && total_size <= max_portable_size;
}
static constexpr bool is_supported_by_ffuzzy_3_0(digest_filesize_t total_size) noexcept
{
return total_size <= max_theoretical_size;
}
static constexpr bool is_supported(digest_filesize_t total_size) noexcept
{
// whether supported by "this" version of ffuzzy++
return is_supported_by_ffuzzy_3_0(total_size);
}
// Predicate (equivalent to "not meaningful results" in ssdeep)
public:
static constexpr bool is_not_meaningful(digest_filesize_t total_size) noexcept
{
return total_size < min_supported_size;
}
};
}
#endif

544
src/ffuzzypp/digest_generator.hpp

@ -0,0 +1,544 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest_generator.hpp
Fuzzy digest generator
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_DIGEST_GENERATOR_HPP
#define FFUZZYPP_DIGEST_GENERATOR_HPP
#include <cassert>
#include <cstdint>
#include <cstddef>
#include <algorithm>
#include <string>
#include "base64.hpp"
#include "context_hash.hpp"
#include "context_hash_fast.hpp"
#include "rolling_hash.hpp"
#include "rolling_hash_ssdeep.hpp"
#include "digest_blocksize.hpp"
#include "digest_data.hpp"
#include "digest_base.hpp"
#include "digest_filesize.hpp"
#include "utils/likely.hpp"
#include "utils/safe_int.hpp"
#include "strings/transform.hpp"
#include "strings/sequences.hpp"
#include "strings/nosequences.hpp"
namespace ffuzzy {
struct digest_generator_error {};
class digest_generator
{
// Digest characters and transformation for them
private:
/*
This type contains digest characters as Base64 indices.
To distinguish valid and invalid characters,
we need a "nil" value.
We transform Base64 indices to actual Base64 characters
when we are copying final digest value.
*/
typedef base64::transform_to_b64 digest_transform_t;
static constexpr const char digest_nil = 64;
static_assert(digest_nil < 0 || digest_nil > 63,
"digest_nil must be out of Base64 range.");
// Heuristics to guess maximum file size from block size (or its index)
public:
static constexpr digest_filesize_t guessed_filesize(digest_blocksize_t blocksize) noexcept
{
return digest_filesize_t(blocksize) * digest_params::max_blockhash_len;
}
static constexpr digest_filesize_t guessed_filesize_at(unsigned i) noexcept
{
return guessed_filesize(digest_blocksize::at(i));
}
// Heuristic to guess block size from file size
public:
static unsigned blockhash_index_guessed_by_filesize(digest_filesize_t size, unsigned start = 0) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(start < digest_blocksize::number_of_blockhashes);
assert(size <= digest_filesize::max_size);
#endif
unsigned bi = start;
digest_filesize_t bgs = guessed_filesize_at(bi);
while (bgs < size)
{
bi++;
bgs *= 2;
}
return bi;
}
// Data Structure
private:
typedef context_hash_fast context_hash_t;
struct blockhash_context
{
context_hash_t hfull;
context_hash_t hhalf;
char digest[digest_params::max_blockhash_len];
char digesth;
blockhash_len_t dindex;
};
blockhash_context bh[digest_blocksize::number_of_blockhashes];
digest_filesize_t totalsz;
digest_filesize_t totalsz_constant;
digest_filesize_t reduce_border;
rolling_hash roll;
unsigned bhstart;
unsigned bhend;
unsigned bhendlimit;
uint_least32_t rollmask;
context_hash_t hlast;
unsigned flags;
static constexpr const unsigned FLAG_LASTHASH = 0x1;
static constexpr const unsigned FLAG_SZCONSTANT = 0x2;
// Simple data structure manipulation
public:
bool is_total_size_clamped(void) const noexcept { return totalsz > digest_filesize::max_size; }
bool is_file_size_constant(void) const noexcept { return flags & FLAG_SZCONSTANT; }
unsigned blockhash_index_start(void) const noexcept { return bhstart; }
unsigned blockhash_index_end(void) const noexcept { return bhend; }
unsigned blockhash_index_end_limit(void) const noexcept { return bhendlimit; }
digest_filesize_t total_size(void) const noexcept { return totalsz; }
// constant file size (for fast ssdeep hashing)
digest_filesize_t get_file_size_constant(void) const noexcept { return totalsz_constant; }
bool set_file_size_constant(digest_filesize_t size) noexcept
{
if (is_file_size_constant() && totalsz_constant != size)
return false;
if (size > digest_filesize::max_size)
return false;
totalsz_constant = size;
bhendlimit = std::min(
digest_blocksize::number_of_blockhashes - 1,
blockhash_index_guessed_by_filesize(size) + 1
);
flags |= FLAG_SZCONSTANT;
return true;
}
public:
// Reset minimum context required
void reset(void) noexcept
{
bh[0].hfull.reset();
bh[0].hhalf.reset();
bh[0].digest[digest_params::max_blockhash_len - 1] = digest_nil;
bh[0].digesth = digest_nil;
bh[0].dindex = 0;
totalsz = 0;
reduce_border = guessed_filesize_at(0);
roll.reset();
bhstart = 0;
bhend = 1;
bhendlimit = digest_blocksize::number_of_blockhashes - 1;
rollmask = 0;
flags = 0;
}
// Update functions (by buffer or by character)
public:
void update(const unsigned char* buf, size_t len) noexcept
{
rolling_hash r = roll;
if (FFUZZYPP_UNLIKELY(len > digest_filesize::max_size
|| digest_filesize::max_size - digest_filesize_t(len) < totalsz))
{
totalsz = digest_filesize::max_size + 1;
}
else
{
totalsz += digest_filesize_t(len);
}
while (len--)
{
unsigned char c = *buf++;
r.update(c);
for (unsigned i = bhstart; i < bhend; i++)
{
bh[i].hfull.update(c);
bh[i].hhalf.update(c);
}
if (flags & FLAG_LASTHASH)
hlast.update(c);
uint_least32_t horg = (r.sum() + 1) & uint_least32_t(0xfffffffful);
uint_least32_t h = horg / uint_least32_t(digest_blocksize::min_blocksize);
if (0xfffffffful % digest_blocksize::min_blocksize != digest_blocksize::min_blocksize - 1 && !horg)
continue;
if (FFUZZYPP_LIKELY(h & rollmask))
continue;
if (horg % uint_least32_t(digest_blocksize::min_blocksize))
continue;
h >>= bhstart;
unsigned i = bhstart;
do
{
if (FFUZZYPP_UNLIKELY(bh[i].dindex == 0))
{
// fork to prepare larger block sizes
if (bhend > bhendlimit)
{
if (bhendlimit == digest_blocksize::number_of_blockhashes - 1
&& !(flags & FLAG_LASTHASH))
{
hlast = bh[i].hfull;
flags |= FLAG_LASTHASH;
}
}
else
{
bh[i+1].hfull = bh[i].hfull;
bh[i+1].hhalf = bh[i].hhalf;
bh[i+1].digest[digest_params::max_blockhash_len - 1] = digest_nil;
bh[i+1].digesth = digest_nil;
bh[i+1].dindex = 0;
bhend++;
}
}
bh[i].digest[bh[i].dindex] = bh[i].hfull.sum_in_base64();
bh[i].digesth = bh[i].hhalf.sum_in_base64();
if (bh[i].dindex < digest_params::max_blockhash_len - 1)
{
bh[i].dindex++;
bh[i].hfull.reset();
if (bh[i].dindex < digest_params::max_blockhash_len / 2)
{
bh[i].digesth = digest_nil;
bh[i].hhalf.reset();
}
}
// eliminate block sizes which will not be chosen
else if (FFUZZYPP_UNLIKELY(bhend - bhstart >= 2
&& reduce_border < (is_file_size_constant() ? totalsz_constant : totalsz)
&& bh[i+1].dindex >= digest_params::max_blockhash_len / 2))
{
bhstart++;
rollmask = rollmask * 2 + 1;
reduce_border *= 2;
}
if (h & 1)
break;
h >>= 1;
} while (++i < bhend);
}
roll = r;
}
void update(unsigned char c) noexcept
{
unsigned char C(c);
update(&C, 1);
}
// High-level update utilities
// (by file pointer or by file name; w/ or w/o internal buffer)
public:
static constexpr const size_t default_buffer_size = 4096;
template <size_t buffer_size = default_buffer_size>
bool update_by_stream(FILE* fp, unsigned char* tmpbuf) noexcept
{
static_assert(buffer_size != 0, "buffer_size must not be zero.");
if (!fp)
return false;
while (true)
{
size_t n = fread(tmpbuf, 1, buffer_size, fp);
if (n == 0)
break;
update(tmpbuf, n);
}
if (feof(fp))
return true;
return false;
}
template <size_t buffer_size = default_buffer_size>
bool update_by_stream(FILE* fp) noexcept
{
static_assert(buffer_size != 0, "buffer_size must not be zero.");
unsigned char buf[buffer_size];
return update_by_stream<buffer_size>(fp, buf);
}
template <size_t buffer_size = default_buffer_size>
bool update_by_file(const char* filename) noexcept
{
static_assert(buffer_size != 0, "buffer_size must not be zero.");
FILE* fp = fopen(filename, "rb");
if (!fp)
return false;
bool ret = update_by_stream<buffer_size>(fp);
fclose(fp);
return ret;
}
template <size_t buffer_size = default_buffer_size>
bool update_by_file(const char* filename, unsigned char* tmpbuf) noexcept
{
static_assert(buffer_size != 0, "buffer_size must not be zero.");
FILE* fp = fopen(filename, "rb");
if (!fp)
return false;
bool ret = update_by_stream<buffer_size>(fp, tmpbuf);
fclose(fp);
return ret;
}
// Digest finalization
private:
// Heuristic to guess block hash index to start from the current state
unsigned blockhash_index_guessed_to_start(void) const noexcept
{
unsigned bi = blockhash_index_guessed_by_filesize(totalsz, bhstart);
#ifdef FFUZZYPP_DEBUG
assert(bi < digest_blocksize::number_of_blockhashes);
#endif
bi = std::min(bi, bhend - 1);
while (bi > bhstart && bh[bi].dindex < digest_params::max_blockhash_len / 2)
bi--;
#ifdef FFUZZYPP_DEBUG
assert(bi >= bhstart && bi < bhend);
assert(bi == 0 || bh[bi].dindex >= digest_params::max_blockhash_len / 2);
#endif
return bi;
}
// Copy the final (resulting) digest
template <typename Tseq, bool IsAlphabetRestricted, bool IsShort, bool Shortened>
bool copy_digest_internal(digest_data<IsAlphabetRestricted, IsShort>& digest) noexcept
{
/*
This function is not exactly "const" but mostly constant.
You can call this function multiple times as you need.
*/
static_assert(Shortened == true || IsShort == false,
"copying long result to short digest_data structure is prohibited.");
if (is_total_size_clamped())
return false;
if (is_file_size_constant() && totalsz != totalsz_constant)
return false;
unsigned bi = blockhash_index_guessed_to_start();
digest.blksize = digest_blocksize::at(bi);
uint_least32_t rh = roll.sum();
// Copy first block hash (digest)
{
char chtmp = bh[bi].digest[digest_params::max_blockhash_len - 1];
size_t sz = bh[bi].dindex;
if (rh != 0)
bh[bi].digest[sz++] = bh[bi].hfull.sum_in_base64();
else if (chtmp != digest_nil)
sz++;
digest.blkhash1_len = Tseq::copy_elim_sequences(digest.digest, bh[bi].digest, sz);
bh[bi].digest[digest_params::max_blockhash_len - 1] = chtmp;
}
// Copy second block hash if we need
if (bi < bhend - 1)
{
size_t dindex = bh[bi+1].dindex;
if (Shortened)
dindex = std::min(dindex, size_t(digest_params::max_blockhash_len / 2 - 1));
char chtmp = bh[bi+1].digest[dindex];
size_t sz = dindex;
if (rh != 0)
{
bh[bi+1].digest[sz++] = Shortened
? bh[bi+1].hhalf.sum_in_base64()
: bh[bi+1].hfull.sum_in_base64();
}
else
{
if (Shortened)
{
if (bh[bi+1].digesth != digest_nil)
bh[bi+1].digest[sz++] = bh[bi+1].digesth;
}
else
{
if (dindex == digest_params::max_blockhash_len - 1 && chtmp != digest_nil)
sz++;
}
}
digest.blkhash2_len = Tseq::copy_elim_sequences(
digest.digest + digest.blkhash1_len, bh[bi+1].digest, sz);
bh[bi+1].digest[dindex] = chtmp;
}
else if (rh != 0)
{
#ifdef FFUZZYPP_DEBUG
assert(bi == 0 || bi == digest_blocksize::number_of_blockhashes - 1);
#endif
if (bi == 0)
digest.digest[digest.blkhash1_len] = bh[bi].hfull.sum_in_base64();
else
digest.digest[digest.blkhash1_len] = hlast.sum_in_base64();
digest.blkhash2_len = Tseq::copy_elim_sequences(
digest.digest + digest.blkhash1_len,
digest.digest + digest.blkhash1_len,
1);
}
else
{
digest.blkhash2_len = 0;
}
return true;
}
// Digest finalization (and copying) utilities
private:
template <bool IsAlphabetRestricted, bool IsShort, bool Shortened>
bool copy_digest_base(digest_data<IsAlphabetRestricted, IsShort>& digest) noexcept
{
return copy_digest_internal<
strings::nosequences<
typename digest_data_transformation<!IsAlphabetRestricted>::output_type
>,
IsAlphabetRestricted, IsShort, Shortened>(digest);
}
public:
template <bool IsAlphabetRestricted, bool IsShort, bool Shortened = true>
bool copy_digest_normalized(digest_data<IsAlphabetRestricted, IsShort>& digest) noexcept
{
return copy_digest_internal<
strings::sequences<
digest_params::max_blockhash_sequence,
typename digest_data_transformation<!IsAlphabetRestricted>::output_type
>, IsAlphabetRestricted, IsShort, Shortened
>(digest);
}
template <bool IsAlphabetRestricted, bool IsShort>
bool copy_digest(digest_base<IsAlphabetRestricted, IsShort, true>& digest) noexcept
{
return copy_digest_normalized<IsAlphabetRestricted, IsShort, true>(digest);
}
template <bool IsAlphabetRestricted, bool IsShort>
bool copy_digest(digest_base<IsAlphabetRestricted, IsShort, false>& digest) noexcept
{
return copy_digest_base<IsAlphabetRestricted, IsShort, true>(digest);
}
public:
template <bool IsAlphabetRestricted>
bool copy_digest_long_normalized(digest_base<IsAlphabetRestricted, false, true>& digest) noexcept
{
return copy_digest_normalized<IsAlphabetRestricted, false, false>(digest);
}
template <bool IsAlphabetRestricted>
bool copy_digest_long(digest_base<IsAlphabetRestricted, false, true>& digest) noexcept
{
return copy_digest_normalized<IsAlphabetRestricted, false, false>(digest);
}
template <bool IsAlphabetRestricted>
bool copy_digest_long(digest_base<IsAlphabetRestricted, false, false>& digest) noexcept
{
return copy_digest_base<IsAlphabetRestricted, false, false>(digest);
}
private:
template <typename T, bool IsAlphabetRestricted, bool IsShort, bool IsNormalized, bool Shortened = true>
T digest_in_type(void)
{
// This object to be erased by NRVO.
T d;
if (IsNormalized)
{
if (!copy_digest_normalized<IsAlphabetRestricted, IsShort, Shortened>(d))
throw digest_generator_error();
}
else
{
if (!copy_digest_base<IsAlphabetRestricted, IsShort, Shortened>(d))
throw digest_generator_error();
}
return d;
}
public:
digest_unorm_t digest(void)
{
// Default options as you need (unnormalized; short form)
return digest_in_type<digest_unorm_t, false, true, false>();
}
std::string digest_str(void)
{
return digest().pretty();
}
public:
template <bool Shortened = false>
digest_long_unorm_t digest_long(void)
{
return digest_in_type<digest_long_unorm_t, false, false, false, Shortened>();
}
digest_t digest_normalized(void)
{
return digest_in_type<digest_t, false, true, true>();
}
template <bool Shortened = false>
digest_long_t digest_long_normalized(void)
{
return digest_in_type<digest_long_t, false, false, true, Shortened>();
}
public:
digest_ra_unorm_t digest_ra(void)
{
return digest_in_type<digest_ra_unorm_t, true, true, false>();
}
template <bool Shortened = false>
digest_ra_long_unorm_t digest_ra_long(void)
{
return digest_in_type<digest_ra_long_unorm_t, true, false, false, Shortened>();
}
digest_ra_t digest_ra_normalized(void)
{
return digest_in_type<digest_ra_t, true, true, true>();
}
template <bool Shortened = false>
digest_ra_long_t digest_ra_long_normalized(void)
{
return digest_in_type<digest_ra_long_t, true, false, true, Shortened>();
}
// Constructors
public:
digest_generator(void) noexcept
{
reset();
}
digest_generator(const digest_generator&) noexcept = default;
};
}
#endif

425
src/ffuzzypp/digest_position_array.hpp

@ -0,0 +1,425 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest_position_array.hpp
Fuzzy digest (position array representation)
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_DIGEST_POSITION_ARRAY_HPP
#define FFUZZYPP_DIGEST_POSITION_ARRAY_HPP
#include <algorithm>
#include <string>
#include "digest_base.hpp"
#include "digest_position_array_base.hpp"
#include "digest_comparison.hpp"
namespace ffuzzy {
template <bool IsAlphabetRestricted>
class digest_position_array
: public digest_position_array_base<IsAlphabetRestricted>
{
public:
static constexpr const bool is_alphabet_restricted = IsAlphabetRestricted;
public:
digest_position_array(void) noexcept = default; // initialize to undefined state
digest_position_array(const digest_position_array& other) noexcept
: digest_position_array_base<IsAlphabetRestricted>(other) {}
const digest_position_array& operator=(const digest_position_array& other) noexcept
{
digest_position_array_base<IsAlphabetRestricted>::operator=(other);
return *this;
}
// Initialization by digest
public:
template <bool IsShort>
digest_position_array(const digest_base<IsAlphabetRestricted, IsShort, true>& src) noexcept
{
digest_position_array_base<IsAlphabetRestricted>::construct(*this, src);
}
template <bool IsShort>
digest_position_array(const digest_base<IsAlphabetRestricted, IsShort, false>& src) noexcept
{
digest_position_array_base<IsAlphabetRestricted>::construct(*this, digest_data<IsAlphabetRestricted, IsShort>::normalize(src));
}
public:
template <bool IsShort>
static void construct(
digest_position_array& dest,
const digest_base<IsAlphabetRestricted, IsShort, true>& src
) noexcept
{
digest_position_array_base<IsAlphabetRestricted>::construct(dest, src);
}
template <bool IsShort>
static void construct(
digest_position_array& dest,
const digest_base<IsAlphabetRestricted, IsShort, false>& src
) noexcept
{
digest_position_array_base<IsAlphabetRestricted>::construct(dest, digest_data<IsAlphabetRestricted, IsShort>::normalize(src));
}
// Initialization by digest string
public:
explicit digest_position_array(const char* str) noexcept(false)
{
digest_base<IsAlphabetRestricted, false, true> digest(str);
construct(*this, digest);
}
explicit digest_position_array(const std::string& str)
: digest_position_array(str.c_str()) {}
// Comparison
public:
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, false, true>& b
) noexcept
{
return digest_comparison<Version>::compare(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, true, true>& b
) noexcept
{
return digest_comparison<Version>::compare(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare(
const digest_base<IsAlphabetRestricted, false, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare(
const digest_base<IsAlphabetRestricted, true, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, false, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, true, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near(
const digest_base<IsAlphabetRestricted, false, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near(
const digest_base<IsAlphabetRestricted, true, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, false, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, true, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq(
const digest_base<IsAlphabetRestricted, false, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq(
const digest_base<IsAlphabetRestricted, true, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_lt(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, false, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_lt(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_lt(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, true, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_lt(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_lt(
const digest_base<IsAlphabetRestricted, false, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_lt(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_lt(
const digest_base<IsAlphabetRestricted, true, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_lt(a, b);
}
public:
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare_near<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare_near<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_eq(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare_near_eq<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_eq(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare_near_eq<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_lt(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare_near_lt<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_lt(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare_near_lt<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_gt(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare_near_lt<Version>(other, *this);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_gt(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare_near_lt<Version>(other, *this);
}
// Comparison (on different digests)
public:
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_diff(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, false, true>& b
) noexcept
{
return digest_comparison<Version>::compare_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_diff(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, true, true>& b
) noexcept
{
return digest_comparison<Version>::compare_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_diff(
const digest_base<IsAlphabetRestricted, false, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_diff(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_diff(
const digest_base<IsAlphabetRestricted, true, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_diff(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_diff(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, false, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_diff(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, true, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_diff(
const digest_base<IsAlphabetRestricted, false, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_diff(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_diff(
const digest_base<IsAlphabetRestricted, true, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_diff(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq_diff(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, false, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq_diff(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, true, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq_diff(
const digest_base<IsAlphabetRestricted, false, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq_diff(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq_diff(
const digest_base<IsAlphabetRestricted, true, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq_diff(b, a);
}
public:
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_diff(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare_diff<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_diff(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare_diff<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_diff(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare_near_diff<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_diff(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare_near_diff<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_eq_diff(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare_near_eq_diff<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_eq_diff(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare_near_eq_diff<Version>(*this, other);
}
};
typedef digest_position_array< true> digest_position_array_t;
typedef digest_position_array<false> digest_position_array_non_ra_t;
}
// Specialization of standard swap
namespace std
{
template <bool IsAlphabetRestricted>
inline void swap(
ffuzzy::digest_position_array<IsAlphabetRestricted>& a,
ffuzzy::digest_position_array<IsAlphabetRestricted>& b
) noexcept
{
ffuzzy::digest_position_array<IsAlphabetRestricted>::swap(a, b);
}
}
#endif

379
src/ffuzzypp/digest_position_array_base.hpp

@ -0,0 +1,379 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest_position_array_base.hpp
Fuzzy digest (position array representation; base class)
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_DIGEST_POSITION_ARRAY_BASE_HPP
#define FFUZZYPP_DIGEST_POSITION_ARRAY_BASE_HPP
#include <cassert>
#include <cstddef>
#include <algorithm>
#include <limits>
#include "base64.hpp"
#include "digest_blocksize.hpp"
#include "digest_data.hpp"
#include "strings/position_array.hpp"
namespace ffuzzy {
template <bool IsAlphabetRestricted>
class digest_position_array_params
{
private:
digest_position_array_params(void) = delete;
digest_position_array_params(const digest_position_array_params&) = delete;
public:
static constexpr const char char_min =
IsAlphabetRestricted ? 0x00 : std::numeric_limits<char>::min();
static constexpr const char char_max =
IsAlphabetRestricted ? 0x3f : std::numeric_limits<char>::max();
static constexpr const bool is_available =
strings::is_auto_position_array_available<digest_params::max_blockhash_len, char, char_min, char_max>::value;
};
// Friend classes for digest_data class
enum struct comparison_version;
namespace internal
{
template <comparison_version> class digest_comparison_base;
}
template <comparison_version> class digest_comparison;
template <bool IsAlphabetRestricted>
class digest_position_array_base
{
public:
typedef strings::auto_position_array<
digest_params::max_blockhash_len, char,
digest_position_array_params<IsAlphabetRestricted>::char_min,
digest_position_array_params<IsAlphabetRestricted>::char_max
> traits_type;
typedef typename traits_type::type pa_type;
typedef typename traits_type::int_type int_type;
// Data structure
private:
pa_type blkhash1;
pa_type blkhash2;
blockhash_len_t blkhash1_len;
blockhash_len_t blkhash2_len;
digest_blocksize_t blksize;
public:
size_t blockhash1_len(void) const noexcept { return blkhash1_len; }
size_t blockhash2_len(void) const noexcept { return blkhash2_len; }
unsigned long blocksize(void) const noexcept { return blksize; }
const pa_type& blockhash1_array(void) const noexcept { return blkhash1; }
const pa_type& blockhash2_array(void) const noexcept { return blkhash2; }
bool is_short(void) const noexcept { return blkhash2_len <= digest_params::max_blockhash_len / 2; }
// "Initialization" and assignment
public:
digest_position_array_base(void) noexcept = default; // initialize to undefined state
digest_position_array_base(const digest_position_array_base& other) noexcept
: blkhash1(other.blkhash1)
, blkhash2(other.blkhash2)
, blkhash1_len(other.blkhash1_len)
, blkhash2_len(other.blkhash2_len)
, blksize(other.blksize)
{
#ifdef FFUZZYPP_DEBUG
assert(other.is_valid());
#endif
}
const digest_position_array_base& operator=(const digest_position_array_base& other) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(other.is_valid());
#endif
blkhash1 = other.blkhash1;
blkhash2 = other.blkhash2;
blkhash1_len = other.blkhash1_len;
blkhash2_len = other.blkhash2_len;
blksize = other.blksize;
return *this;
}
static void swap(digest_position_array_base& a, digest_position_array_base& b) noexcept
{
std::swap(a.blkhash1, b.blkhash1);
std::swap(a.blkhash2, b.blkhash2);
std::swap(a.blkhash1_len, b.blkhash1_len);
std::swap(a.blkhash2_len, b.blkhash2_len);
std::swap(a.blksize, b.blksize);
}
// Construction by digest
protected:
template <bool IsShort>
static void construct(
digest_position_array_base& dest,
const digest_data<IsAlphabetRestricted, IsShort>& src
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(src.is_valid());
#endif
dest.blkhash1.construct(src.digest, src.blkhash1_len);
dest.blkhash2.construct(src.digest+src.blkhash1_len, src.blkhash2_len);
dest.blkhash1_len = src.blkhash1_len;
dest.blkhash2_len = src.blkhash2_len;
dest.blksize = src.blksize;
}
template <bool IsShort>
digest_position_array_base(const digest_data<IsAlphabetRestricted, IsShort>& src) noexcept
{
construct(src);
}
// Validators (for its validness and naturality)
private:
bool is_valid_blockhash_position_array(const pa_type& parray, blockhash_len_t len) const noexcept
{
int_type mask, set_bits;
const int_type* data = parray.bitmap_data();
size_t array_size = parray.array_size;
if (len)
{
mask = int_type(1u) << (len - 1);
mask = mask ^ (-mask);
}
else
{
mask = -1;
}
set_bits = 0;
for (size_t i = 0; i < array_size; i++)
{
int_type D = data[i];
// check for invalid bits "above" length of the string
if (D & mask)
return false;
// check for duplicate bits (e.g. n-th character of the string is BOTH 'A' and 'B')
if (D & set_bits)
return false;
set_bits |= D;
// check for sequences
int_type tmp = D;
for (blockhash_len_t j = 0; j < digest_params::max_blockhash_sequence; j++)
{
tmp <<= 1;
tmp &= D;
}
if (tmp)
return false;
}
// check if set_bits is now "all valid bits"
if (len)
{
mask = int_type(1u) << (len - 1);
mask = mask | (mask - 1);
}
else
{
mask = 0;
}
if (mask != set_bits)
return false;
return true;
}
bool is_natural_blockhash_position_array(const pa_type& parray, blockhash_len_t len) const noexcept
{
if (!IsAlphabetRestricted)
{
// check only if IsAlphabetRestricted is false
// (represented by regular characters and non Base64 characters are possible)
int_type mask, set_bits;
if (len)
{
mask = int_type(1u) << (len - 1);
mask = mask | (mask - 1);
}
else
{
set_bits = 0;
}
for (size_t i = 0; i < 64; i++)
set_bits |= parray[base64::values[i]];
// check if all valid bits are set by valid Base64 chareacters
if (mask != set_bits)
return false;
}
return true;
}
public:
bool is_valid(void) const noexcept
{
if (blkhash1_len > digest_params::max_blockhash_len)
return false;
if (blkhash2_len > digest_params::max_blockhash_len)
return false;
if (blksize > 0xfffffffful)
return false;
// Note: digest_position_array_base::is_valid takes time.
if (!is_valid_blockhash_position_array(blkhash1, blkhash1_len))
return false;
if (!is_valid_blockhash_position_array(blkhash2, blkhash2_len))
return false;
return true;
}
bool is_natural(void) const noexcept
{
if (!is_valid())
return false;
if (blkhash1_len < blkhash2_len)
return false;
if (!digest_blocksize::is_natural(blksize))
return false;
if (!digest_blocksize::is_safe_to_double(blksize) && blkhash2_len >= 2)
return false;
// Note: digest_position_array_base::is_natural takes time.
if (!is_natural_blockhash_position_array(blkhash1, blkhash1_len))
return false;
if (!is_natural_blockhash_position_array(blkhash2, blkhash2_len))
return false;
return true;
}
bool is_blocksize_natural(void) const noexcept
{
return digest_blocksize::is_natural(blksize);
}
// Comparison
public:
static bool is_eq_except_blocksize(
const digest_position_array_base& a,
const digest_position_array_base& b
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(a.is_valid());
assert(b.is_valid());
#endif
if (a.blkhash1_len != b.blkhash1_len)
return false;
if (a.blkhash2_len != b.blkhash2_len)
return false;
int_type data_a = a.bitmap_data();
int_type data_b = b.bitmap_data();
for (size_t i = 0; i < pa_type::array_size; i++)
{
if (data_a[i] != data_b[i])
return false;
}
return true;
}
static bool is_eq(
const digest_position_array_base& a,
const digest_position_array_base& b
) noexcept
{
if (a.blksize != b.blksize)
return false;
return is_eq_except_blocksize(a, b);
}
template <bool IsShort>
static bool is_eq_except_blocksize(
const digest_position_array_base& a,
const digest_data<IsAlphabetRestricted, IsShort>& b
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(a.is_valid());
assert(b.is_valid());
#endif
if (a.blkhash1_len != b.blkhash1_len)
return false;
if (a.blkhash2_len != b.blkhash2_len)
return false;
if (a.blksize != b.blksize)
return false;
const char* p = b.digest;
for (blockhash_len_t i = 0; i < b.blkhash1_len; i++)
{
if (!(a.blkhash1[*p++] & (int_type(1u) << i)))
return false;
}
for (blockhash_len_t i = 0; i < b.blkhash2_len; i++)
{
if (!(a.blkhash2[*p++] & (int_type(1u) << i)))
return false;
}
return true;
}
template <bool IsShort>
static bool is_eq(
const digest_position_array_base& a,
const digest_data<IsAlphabetRestricted, IsShort>& b
) noexcept
{
if (a.blksize != b.blksize)
return false;
return is_eq_except_blocksize(a, b);
}
public:
friend bool operator==(const digest_position_array_base& a, const digest_position_array_base& b) noexcept { return is_eq(a, b); }
friend bool operator!=(const digest_position_array_base& a, const digest_position_array_base& b) noexcept { return !is_eq(a, b); }
public:
template <bool IsShort>
friend bool operator==(
const digest_position_array_base& a,
const digest_data<IsAlphabetRestricted, IsShort>& b
) noexcept
{
return is_eq(a, b);
}
template <bool IsShort>
friend bool operator!=(
const digest_position_array_base& a,
const digest_data<IsAlphabetRestricted, IsShort>& b
) noexcept
{
return !is_eq(a, b);
}
template <bool IsShort>
friend bool operator==(
const digest_data<IsAlphabetRestricted, IsShort>& a,
const digest_position_array_base& b
) noexcept
{
return is_eq(b, a);
}
template <bool IsShort>
friend bool operator!=(
const digest_data<IsAlphabetRestricted, IsShort>& a,
const digest_position_array_base& b
) noexcept
{
return !is_eq(b, a);
}
// Friend classes
template <comparison_version> friend class internal::digest_comparison_base;
template <comparison_version> friend class digest_comparison;
};
}
#endif

83
src/ffuzzypp/rolling_hash.hpp

@ -0,0 +1,83 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
rolling_hash.hpp
Rolling hash implementation (without known bugs)
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_ROLLING_HASH_HPP
#define FFUZZYPP_ROLLING_HASH_HPP
#include <cstddef>
#include <cstdint>
namespace ffuzzy {
class rolling_hash
{
public:
static constexpr const uint_least32_t window_size = 7;
static_assert(window_size != 0, "window_size must not be zero.");
protected:
uint_least32_t h1, h2, h3;
uint_least32_t n;
unsigned char window[window_size];
public:
void reset(void) noexcept
{
h1 = h2 = h3 = n = 0;
for (size_t i = 0; i < window_size; i++)
window[i] = 0;
}
void update(unsigned char c) noexcept
{
uint_least32_t C(c);
h2 = h2 - h1 + window_size * C;
h1 = h1 + C - window[n];
h3 = (h3 << 5) ^ C;
window[n] = c;
n++;
if (n == window_size)
n = 0;
}
uint_least32_t sum(void) const noexcept
{
return (h1 + h2 + h3) & uint_least32_t(0xfffffffful);
}
public:
rolling_hash(void) noexcept
{
reset();
}
};
}
#endif

87
src/ffuzzypp/rolling_hash_ssdeep.hpp

@ -0,0 +1,87 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
rolling_hash_ssdeep.hpp
Rolling hash implementation (with known bug in ssdeep)
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_ROLLING_HASH_SSDEEP_HPP
#define FFUZZYPP_ROLLING_HASH_SSDEEP_HPP
#include <cstddef>
#include <cstdint>
#include "rolling_hash.hpp"
namespace ffuzzy {
// rolling_hash with known rolling-hash bug on ssdeep
class rolling_hash_ssdeep
{
public:
static constexpr const uint_least32_t window_size = rolling_hash::window_size;
private:
uint_least32_t h1, h2, h3;
uint_least32_t n;
unsigned char window[window_size];
public:
void update(unsigned char c) noexcept
{
// emulate bug on ssdeep
uint_least32_t C(c);
h2 = h2 - h1 + window_size * C;
h1 = h1 + C - window[n % window_size];
h3 = (h3 << 5) ^ C;
window[n % window_size] = c;
n++;
if ((n & uint_least32_t(0xfffffffful)) == 0)
n = 0;
}
public:
void reset(void) noexcept
{
h1 = h2 = h3 = n = 0;
for (size_t i = 0; i < window_size; i++)
window[i] = 0;
}
uint_least32_t sum(void) const noexcept
{
return (h1 + h2 + h3) & uint_least32_t(0xfffffffful);
}
public:
rolling_hash_ssdeep(void) noexcept
{
reset();
}
};
}
#endif

345
src/ffuzzypp/strings/common_substr.hpp

@ -0,0 +1,345 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
strings/common_substr.hpp
Utility to find common substring in two strings
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS (HASHARRAY ALGORITHM)
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
CREDIT OF ADDED PORTIONS (BIT-PARALLEL ALGORITHM)
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_STRINGS_COMMON_SUBSTR_HPP
#define FFUZZYPP_STRINGS_COMMON_SUBSTR_HPP
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <limits>
#include <type_traits>
#include "../rolling_hash.hpp"
#include "position_array.hpp"
namespace ffuzzy {
namespace strings {
namespace internal
{
template <size_t SubstrSize>
class common_substr_hasharray_impl
{
private:
common_substr_hasharray_impl(void) = delete;
common_substr_hasharray_impl(const common_substr_hasharray_impl&) = delete;
public:
static constexpr const size_t substr_size = SubstrSize;
static_assert(0 < substr_size, "substr_size must be nonzero.");
static_assert(substr_size >= rolling_hash::window_size,
"substr_size must be equal or greater than window_size.");
public:
static bool match_long_buf(
const char* s1, size_t s1len,
const char* s2, size_t s2len,
uint_least32_t* hashes_buf
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1);
assert(s2);
assert(s1len >= substr_size);
assert(s2len >= substr_size);
#endif
rolling_hash r;
// compute rolling hashes for each index of s1
for (size_t i = 0; i < substr_size - 1; i++)
r.update(static_cast<unsigned char>(s1[i]));
for (size_t i = substr_size - 1; i < s1len; i++)
{
r.update(static_cast<unsigned char>(s1[i]));
hashes_buf[i - (substr_size - 1)] = r.sum();
}
s1len -= (substr_size - 1);
// compute rolling hashes for each index of s2
r.reset();
for (size_t j = 0; j < substr_size - 1; j++)
r.update(static_cast<unsigned char>(s2[j]));
for (size_t j = 0; j < s2len - (substr_size - 1); j++)
{
r.update(static_cast<unsigned char>(s2[j + (substr_size - 1)]));
uint_least32_t h = r.sum();
for (size_t i = 0; i < s1len; i++)
{
// make sure we actually have common substring if hash matches
if (hashes_buf[i] == h && !memcmp(s1 + i, s2 + j, substr_size))
return true;
}
}
return false;
}
};
template <
size_t SubstrSize,
size_t MaxSize = std::numeric_limits<size_t>::max()
>
class common_substr_bitparallel_impl
{
private:
common_substr_bitparallel_impl(void) = delete;
common_substr_bitparallel_impl(const common_substr_bitparallel_impl&) = delete;
public:
static constexpr const size_t substr_size = SubstrSize;
static constexpr const size_t max_size = MaxSize;
static_assert(0 < substr_size, "substr_size must be nonzero.");
static_assert(0 < max_size, "max_size must be nonzero.");
public:
template <typename TBitmap, char CMin, char CMax>
static bool match(
const position_array<TBitmap, char, CMin, CMax>& s1,
const char* s2, size_t s2len
) noexcept
{
typedef position_array<TBitmap, char, CMin, CMax> pa_type;
#ifdef FFUZZYPP_DEBUG
assert(s2);
assert(s2len >= substr_size);
assert(s2len <= max_size);
#endif
// position array is too short to have such substrings
if (pa_type::max_strlen < substr_size)
return false;
size_t r = substr_size - 1;
while (true)
{
size_t l = r - (substr_size - 1);
// we must reverse s2 because bitmap of s1 is reversed.
const char* ch = &s2[s2len - 1 - r];
TBitmap D = s1[*ch];
while (D)
{
r--;
D = (D << 1) & s1[*++ch];
if (r == l && D)
return true;
}
// Boyer-Moore-like skipping
if (max_size - 1 <= std::numeric_limits<size_t>::max() - substr_size)
{
// (max_size - 1) + substr_size <= max(size_t)
r += substr_size;
if (r >= s2len)
break;
}
else
{
// (max_size - 1) + substr_size > max(size_t)
// which means we cannot safely perform r += substr_size first (very unlikely)
if (r >= s2len - substr_size)
break;
r += substr_size;
}
}
return false;
}
};
}
template <size_t MaxSize, size_t SubstrSize>
class common_substr_hasharray
{
private:
common_substr_hasharray(void) = delete;
common_substr_hasharray(const common_substr_hasharray&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static constexpr const size_t substr_size = SubstrSize;
static_assert(0 < substr_size, "substr_size must be nonzero.");
static_assert(substr_size <= max_size, "substring size must not be greater than the maximum size.");
public:
static bool match(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1);
assert(s2);
assert(s1len <= max_size);
#endif
uint_least32_t hashes[max_size - (substr_size - 1)];
if (s1len < substr_size)
return false;
if (s2len < substr_size)
return false;
return internal
::common_substr_hasharray_impl<substr_size>
::match_long_buf(s1, s1len, s2, s2len, hashes);
}
};
template <typename TBitmap, char CMin, char CMax, size_t MaxSize, size_t SubstrSize>
class common_substr_bitparallel
{
private:
common_substr_bitparallel(void) = delete;
common_substr_bitparallel(const common_substr_bitparallel&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static constexpr const size_t substr_size = SubstrSize;
static_assert(0 < substr_size, "substr_size must be nonzero.");
static_assert(substr_size <= max_size, "substring size must not be greater than the maximum size.");
static_assert(max_size <= position_array<TBitmap, char, CMin, CMax>::max_strlen,
"max_size must not be greater than max_strlen of corresponding position_matrix for efficiency.");
public:
static bool match(
const position_array<TBitmap, char, CMin, CMax>& s1,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s2);
assert(s2len <= max_size);
#endif
if (s2len < substr_size)
return false;
return internal
::common_substr_bitparallel_impl<substr_size, max_size>
::match(s1, s2, s2len);
}
};
template <typename TBitmap, char CMin, char CMax, size_t MaxSize, size_t SubstrSize>
class common_substr_bitparallel_wrapper
{
private:
common_substr_bitparallel_wrapper(void) = delete;
common_substr_bitparallel_wrapper(const common_substr_bitparallel_wrapper&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static constexpr const size_t substr_size = SubstrSize;
static_assert(0 < substr_size, "substr_size must be nonzero.");
static_assert(substr_size <= max_size, "substring size must not be greater than the maximum size.");
static_assert(max_size <= position_array<TBitmap, char, CMin, CMax>::max_strlen,
"max_size must not be greater than max_strlen of corresponding position_matrix for efficiency.");
public:
static bool match(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s2);
assert(s2len <= max_size);
#endif
if (s2len < substr_size)
return false;
position_array<TBitmap, char, CMin, CMax> parray(s1, s1len);
return internal
::common_substr_bitparallel_impl<substr_size, max_size>
::match(parray, s2, s2len);
}
};
namespace internal
{
template <char CMin, char CMax, size_t MaxSize, size_t SubstrSize, bool IsPositionArrayAvailable>
class common_substr_impl_selector;
template <char CMin, char CMax, size_t MaxSize, size_t SubstrSize>
class common_substr_impl_selector<CMin, CMax, MaxSize, SubstrSize, true>
{
private:
common_substr_impl_selector(void) = delete;
common_substr_impl_selector(const common_substr_impl_selector&) = delete;
public:
static bool match(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
typename auto_position_array<MaxSize, char, CMin, CMax>::type parray(s1, s1len);
return common_substr_bitparallel<typename decltype(parray)::bitmap_type,
CMin, CMax, MaxSize, SubstrSize>::match(parray, s2, s2len);
}
};
template <char CMin, char CMax, size_t MaxSize, size_t SubstrSize>
class common_substr_impl_selector<CMin, CMax, MaxSize, SubstrSize, false>
{
private:
common_substr_impl_selector(void) = delete;
common_substr_impl_selector(const common_substr_impl_selector&) = delete;
public:
static bool match(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
return common_substr_hasharray<MaxSize, SubstrSize>::match(s1, s1len, s2, s2len);
}
};
}
template <size_t MaxSize, size_t SubstrSize>
class common_substr_fast
{
private:
common_substr_fast(void) = delete;
common_substr_fast(const common_substr_fast&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static constexpr const size_t substr_size = SubstrSize;
public:
template <
char CMin = std::numeric_limits<char>::min(),
char CMax = std::numeric_limits<char>::max()
>
static bool match(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
return internal::common_substr_impl_selector<
CMin, CMax, max_size, substr_size,
is_auto_position_array_available<MaxSize, char, CMin, CMax>::value
>::match(s1, s1len, s2, s2len);
}
};
}}
#endif

521
src/ffuzzypp/strings/edit_dist.hpp

@ -0,0 +1,521 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
strings/edit_dist.hpp
Indel distance implementation
Copyright (C) 2014 kikairoya <kikairoya@gmail.com>
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
This program can be used, redistributed or modified under any of
Boost Software License 1.0, GPL v2 or GPL v3
*/
#ifndef FFUZZYPP_STRINGS_EDIT_DIST_HPP
#define FFUZZYPP_STRINGS_EDIT_DIST_HPP
#include <cassert>
#include <cstddef>
#include <algorithm>
#include <limits>
#include <utility>
#include "../utils/safe_int.hpp"
#include "position_array.hpp"
namespace ffuzzy {
namespace strings {
namespace internal
{
template <typename Tcost>
class edit_dist_dp_impl
{
private:
edit_dist_dp_impl(void) = delete;
edit_dist_dp_impl(const edit_dist_dp_impl&) = delete;
public:
typedef Tcost cost_type;
static_assert(
safe_int::contracts::is_unsigned_integral_type<cost_type>(),
"cost_type must be an unsigned integral type.");
private:
static void update_cost_inner(
const char* s1,
const char* s2, size_t s2len,
size_t i,
cost_type* &row1, cost_type* &row2
) noexcept
{
row2[0] = static_cast<cost_type>(i) + 1;
for (size_t j = 0; j < s2len; j++)
{
cost_type cost_a = row1[j+1] + 1;
cost_type cost_d = row2[j] + 1;
cost_type cost_r = row1[j] + (s1[i] == s2[j] ? 0 : 2);
row2[j+1] = std::min(std::min(cost_a, cost_d), cost_r);
}
std::swap(row1, row2);
}
public:
static cost_type cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len,
cost_type* row1, cost_type* row2
) noexcept
{
for (size_t j = 0; j <= s2len; j++)
row1[j] = static_cast<cost_type>(j);
for (size_t i = 0; i < s1len; i++)
update_cost_inner(s1, s2, s2len, i, row1, row2);
return row1[s2len];
}
static cost_type cost_nonempty(
const char* s1, size_t s1len,
const char* s2, size_t s2len,
cost_type* row1, cost_type* row2
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1len > 0);
assert(s2len > 0);
#endif
row1[0] = 1;
for (size_t j = 0; j < s2len; j++)
{
cost_type cost_d = row1[j] + 1;
cost_type cost_r = static_cast<cost_type>(j) + (s1[0] == s2[j] ? 0 : 2);
row1[j+1] = std::min(cost_d, cost_r);
}
for (size_t i = 1; i < s1len; i++)
update_cost_inner(s1, s2, s2len, i, row1, row2);
return row1[s2len];
}
};
template <typename Tcost, size_t MaxSize>
class edit_dist_bitparallel_impl
{
private:
edit_dist_bitparallel_impl(void) = delete;
edit_dist_bitparallel_impl(const edit_dist_bitparallel_impl&) = delete;
public:
typedef Tcost cost_type;
public:
template <typename TBitmap, char CMin, char CMax>
static cost_type cost_nonempty(
const position_array<TBitmap, char, CMin, CMax>& s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
cost_type cur = s1len;
TBitmap msb = TBitmap(1ull) << (s1len - 1);
TBitmap pv = -1;
TBitmap nv = 0;
for (size_t i = 0; i < s2len; i++)
{
TBitmap mt = s1[s2[i]];
TBitmap zd = (((mt & pv) + pv) ^ pv) | mt | nv;
TBitmap nh = pv & zd;
if (nh & msb)
--cur;
TBitmap x = nv | ~(pv | zd) | (pv & ~mt & TBitmap(1ull));
TBitmap y = (pv - nh) >> 1;
/*
i-th bit of ph does not depend on i-th bit of y
(only upper bits of ph are affected).
So, ph does not depend on invalid bit in y.
*/
TBitmap ph = (x + y) ^ y;
if (ph & msb)
++cur;
TBitmap t = (ph << 1) + TBitmap(1ull);
nv = t & zd;
pv = (nh << 1) | ~(t | zd) | (t & (pv - nh));
}
return cur;
}
template <typename TBitmap, char CMin, char CMax>
static cost_type cost(
const position_array<TBitmap, char, CMin, CMax>& s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
return s1len == 0
? s2len
: cost_nonempty(s1, s1len, s2, s2len);
}
};
}
template <typename Tcost, size_t MaxSize>
class edit_dist_dp
{
private:
edit_dist_dp(void) = delete;
edit_dist_dp(const edit_dist_dp&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static_assert(max_size > 0, "max_size must not be zero.");
static_assert(safe_int::safe_add<
safe_int::uvalue<size_t, max_size>,
safe_int::uvalue<size_t, 1>
>::is_valid,
"max_size + 1 must be in range of size_t.");
typedef Tcost cost_type;
static_assert(safe_int::safe_mul<
safe_int::uvalue<cost_type, max_size>,
safe_int::uvalue<cost_type, 2>
>::is_valid,
"max_size * 2 must be in range of cost_type.");
public:
static cost_type cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1len <= max_size);
assert(s2len <= max_size);
#endif
cost_type rows[2][max_size + 1];
return internal::edit_dist_dp_impl<cost_type>::cost(s1, s1len, s2, s2len, rows[0], rows[1]);
}
};
template <typename Tcost, size_t MaxSize>
class edit_dist_nonempty_dp
{
private:
edit_dist_nonempty_dp(void) = delete;
edit_dist_nonempty_dp(const edit_dist_nonempty_dp&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static_assert(max_size > 0, "max_size must not be zero.");
static_assert(safe_int::safe_add<
safe_int::uvalue<size_t, max_size>,
safe_int::uvalue<size_t, 1>
>::is_valid,
"max_size + 1 must be in range of size_t.");
typedef Tcost cost_type;
static_assert(safe_int::safe_mul<
safe_int::uvalue<cost_type, max_size>,
safe_int::uvalue<cost_type, 2>
>::is_valid,
"max_size * 2 must be in range of cost_type.");
public:
static cost_type cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1len <= max_size);
assert(s2len <= max_size);
#endif
cost_type rows[2][max_size + 1];
return internal::edit_dist_dp_impl<cost_type>::cost_nonempty(s1, s1len, s2, s2len, rows[0], rows[1]);
}
};
template <typename Tcost, typename TBitmap, char CMin, char CMax, size_t MaxSize>
class edit_dist_bitparallel
{
private:
edit_dist_bitparallel(void) = delete;
edit_dist_bitparallel(const edit_dist_bitparallel&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static_assert(max_size > 0, "max_size must not be zero.");
static_assert(safe_int::safe_add<
safe_int::uvalue<size_t, max_size>,
safe_int::uvalue<size_t, 1>
>::is_valid,
"max_size + 1 must be in range of size_t.");
typedef Tcost cost_type;
static_assert(safe_int::safe_mul<
safe_int::uvalue<cost_type, max_size>,
safe_int::uvalue<cost_type, 2>
>::is_valid,
"max_size * 2 must be in range of cost_type.");
public:
static cost_type cost(
const position_array<TBitmap, char, CMin, CMax>& s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1len <= max_size);
assert(s2len <= max_size);
#endif
return internal::edit_dist_bitparallel_impl<Tcost, MaxSize>::cost(s1, s1len, s2, s2len);
}
};
template <typename Tcost, typename TBitmap, char CMin, char CMax, size_t MaxSize>
class edit_dist_bitparallel_wrapper
{
private:
edit_dist_bitparallel_wrapper(void) = delete;
edit_dist_bitparallel_wrapper(const edit_dist_bitparallel_wrapper&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static_assert(max_size > 0, "max_size must not be zero.");
static_assert(safe_int::safe_add<
safe_int::uvalue<size_t, max_size>,
safe_int::uvalue<size_t, 1>
>::is_valid,
"max_size + 1 must be in range of size_t.");
typedef Tcost cost_type;
static_assert(safe_int::safe_mul<
safe_int::uvalue<cost_type, max_size>,
safe_int::uvalue<cost_type, 2>
>::is_valid,
"max_size * 2 must be in range of cost_type.");
public:
static cost_type cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1len <= max_size);
assert(s2len <= max_size);
#endif
position_array<TBitmap, char, CMin, CMax> parray(s1, s1len);
return internal::edit_dist_bitparallel_impl<Tcost, MaxSize>::cost(parray, s1len, s2, s2len);
}
};
template <typename Tcost, typename TBitmap, char CMin, char CMax, size_t MaxSize>
class edit_dist_nonempty_bitparallel
{
private:
edit_dist_nonempty_bitparallel(void) = delete;
edit_dist_nonempty_bitparallel(const edit_dist_nonempty_bitparallel&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static_assert(max_size > 0, "max_size must not be zero.");
static_assert(safe_int::safe_add<
safe_int::uvalue<size_t, max_size>,
safe_int::uvalue<size_t, 1>
>::is_valid,
"max_size + 1 must be in range of size_t.");
typedef Tcost cost_type;
static_assert(safe_int::safe_mul<
safe_int::uvalue<cost_type, max_size>,
safe_int::uvalue<cost_type, 2>
>::is_valid,
"max_size * 2 must be in range of cost_type.");
public:
static cost_type cost(
const position_array<TBitmap, char, CMin, CMax>& s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1len <= max_size);
assert(s2len <= max_size);
#endif
return internal::edit_dist_bitparallel_impl<Tcost, MaxSize>::cost_nonempty(s1, s1len, s2, s2len);
}
};
template <typename Tcost, typename TBitmap, char CMin, char CMax, size_t MaxSize>
class edit_dist_nonempty_bitparallel_wrapper
{
private:
edit_dist_nonempty_bitparallel_wrapper(void) = delete;
edit_dist_nonempty_bitparallel_wrapper(const edit_dist_nonempty_bitparallel_wrapper&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static_assert(max_size > 0, "max_size must not be zero.");
static_assert(safe_int::safe_add<
safe_int::uvalue<size_t, max_size>,
safe_int::uvalue<size_t, 1>
>::is_valid,
"max_size + 1 must be in range of size_t.");
typedef Tcost cost_type;
static_assert(safe_int::safe_mul<
safe_int::uvalue<cost_type, max_size>,
safe_int::uvalue<cost_type, 2>
>::is_valid,
"max_size * 2 must be in range of cost_type.");
public:
static cost_type cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1len <= max_size);
assert(s2len <= max_size);
#endif
position_array<TBitmap, char, CMin, CMax> parray(s1, s1len);
return internal::edit_dist_bitparallel_impl<Tcost, MaxSize>::cost_nonempty(parray, s1len, s2, s2len);
}
};
namespace internal
{
template <typename Tcost, char CMin, char CMax, size_t MaxSize, bool IsPositionArrayAvailable>
class edit_dist_impl_selector;
template <typename Tcost, char CMin, char CMax, size_t MaxSize>
class edit_dist_impl_selector<Tcost, CMin, CMax, MaxSize, true>
{
private:
edit_dist_impl_selector(void) = delete;
edit_dist_impl_selector(const edit_dist_impl_selector&) = delete;
public:
static Tcost cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
typename auto_position_array<MaxSize, char, CMin, CMax>::type parray(s1, s1len);
return edit_dist_bitparallel<Tcost,
typename decltype(parray)::bitmap_type, CMin, CMax, MaxSize>::cost(parray, s1len, s2, s2len);
}
static Tcost cost_nonempty(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
typename auto_position_array<MaxSize, char, CMin, CMax>::type parray(s1, s1len);
return edit_dist_nonempty_bitparallel<Tcost,
typename decltype(parray)::bitmap_type, CMin, CMax, MaxSize>::cost(parray, s1len, s2, s2len);
}
};
template <typename Tcost, char CMin, char CMax, size_t MaxSize>
class edit_dist_impl_selector<Tcost, CMin, CMax, MaxSize, false>
{
private:
edit_dist_impl_selector(void) = delete;
edit_dist_impl_selector(const edit_dist_impl_selector&) = delete;
public:
static Tcost cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
return edit_dist_dp<Tcost, MaxSize>::cost(s1, s1len, s2, s2len);
}
static Tcost cost_nonempty(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
return edit_dist_nonempty_dp<Tcost, MaxSize>::cost(s1, s1len, s2, s2len);
}
};
}
template <typename Tcost, size_t MaxSize>
class edit_dist_fast
{
private:
edit_dist_fast(void) = delete;
edit_dist_fast(const edit_dist_fast&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
typedef Tcost cost_type;
public:
template <
char CMin = std::numeric_limits<char>::min(),
char CMax = std::numeric_limits<char>::max()
>
static Tcost cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
return internal::edit_dist_impl_selector<
cost_type, CMin, CMax, max_size,
is_auto_position_array_available<MaxSize, char, CMin, CMax>::value
>::cost(s1, s1len, s2, s2len);
}
};
template <typename Tcost, size_t MaxSize>
class edit_dist_nonempty_fast
{
private:
edit_dist_nonempty_fast(void) = delete;
edit_dist_nonempty_fast(const edit_dist_nonempty_fast&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
typedef Tcost cost_type;
public:
template <
char CMin = std::numeric_limits<char>::min(),
char CMax = std::numeric_limits<char>::max()
>
static Tcost cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
return internal::edit_dist_impl_selector<
cost_type, CMin, CMax, max_size,
is_auto_position_array_available<MaxSize, char, CMin, CMax>::value
>::cost_nonempty(s1, s1len, s2, s2len);
}
};
template <typename Tedit_dist>
class edit_dist_norm
{
private:
edit_dist_norm(void) = delete;
edit_dist_norm(const edit_dist_norm&) = delete;
public:
typedef typename Tedit_dist::cost_type cost_type;
static cost_type cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
// Normalization: make s1 short for better effficiency
if (s1len <= s2len)
return Tedit_dist::cost(s1, s1len, s2, s2len);
else
return Tedit_dist::cost(s2, s2len, s1, s1len);
}
};
template <typename Tedit_dist>
class edit_dist_norm_rev
{
private:
edit_dist_norm_rev(void) = delete;
edit_dist_norm_rev(const edit_dist_norm_rev&) = delete;
public:
typedef typename Tedit_dist::cost_type cost_type;
static cost_type cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
// Reverse normalization: make s2 short for (possibly) worst effficiency
if (s1len <= s2len)
return Tedit_dist::cost(s2, s2len, s1, s1len);
else
return Tedit_dist::cost(s1, s1len, s2, s2len);
}
};
}}
#endif

82
src/ffuzzypp/strings/nosequences.hpp

@ -0,0 +1,82 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
strings/nosequences.hpp
String utilities with same interface as sequence utilities
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_STRINGS_NOSEQUENCES_HPP
#define FFUZZYPP_STRINGS_NOSEQUENCES_HPP
#include <cstddef>
#include "terminators.hpp"
#include "transform.hpp"
namespace ffuzzy {
namespace strings {
template <typename Ttransform = default_char_transform>
class nosequences
{
private:
nosequences(void) = delete;
nosequences(const nosequences&) = delete;
public:
static constexpr bool has_sequences(const char* buf, size_t size) noexcept
{
return false;
}
static void copy_raw(char* out, const char* in, size_t size) noexcept
{
while (size--)
*out++ = Ttransform::transform(*in++);
}
static size_t copy_elim_sequences(char* out, const char* in, size_t size) noexcept
{
copy_raw(out, in, size);
return size;
}
template <char... terms>
class string_copy
{
private:
string_copy(void) = delete;
string_copy(const string_copy&) = delete;
public:
static bool copy_elim_sequences(char*& out, size_t outsize, const char*& in) noexcept
{
while (outsize--)
{
char ch;
if (terminators<terms...>::isterm(ch = *in))
return true;
in++;
*out++ = Ttransform::transform(ch);
}
if (terminators<terms...>::isterm(*in))
return true;
return false;
}
};
};
}}
#endif

409
src/ffuzzypp/strings/position_array.hpp

@ -0,0 +1,409 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
strings/position_array.hpp
Position array (for bit-parallel algorithms)
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_STRINGS_POSITION_ARRAY_HPP
#define FFUZZYPP_STRINGS_POSITION_ARRAY_HPP
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <limits>
#include <type_traits>
namespace ffuzzy {
namespace strings {
namespace internal
{
template <typename T>
class digits_on_size
{
private:
digits_on_size(void) = delete;
digits_on_size(const digits_on_size&) = delete;
public:
static constexpr const size_t size =
std::numeric_limits<T>::digits <= std::numeric_limits<size_t>::max()
? std::numeric_limits<T>::digits
: std::numeric_limits<size_t>::max();
};
/*
Template to return guaranteed bit length on unsigned integral types:
General template works only for binary (radix==2) types and
specialized templates work for radix!=2 binary types.
*/
template <typename T>
class guaranteed_bitlen
{
private:
guaranteed_bitlen(void) = delete;
guaranteed_bitlen(const guaranteed_bitlen&) = delete;
private:
static_assert(std::is_integral<T>::value, "T must be an integral type.");
static_assert(std::is_unsigned<T>::value, "T must be an unsigned integral type.");
static_assert(std::numeric_limits<T>::radix == 2, "T must be a binary unsigned integral type.");
public:
static constexpr const size_t size = digits_on_size<T>::size;
};
template <>
class guaranteed_bitlen<unsigned>
{
private:
guaranteed_bitlen(void) = delete;
guaranteed_bitlen(const guaranteed_bitlen&) = delete;
private:
typedef std::numeric_limits<unsigned> limits_type;
public:
static constexpr const size_t size =
limits_type::radix == 2 && limits_type::digits < 16
? digits_on_size<unsigned>::size : 16;
};
template <>
class guaranteed_bitlen<unsigned long>
{
private:
guaranteed_bitlen(void) = delete;
guaranteed_bitlen(const guaranteed_bitlen&) = delete;
private:
typedef std::numeric_limits<unsigned long> limits_type;
public:
static constexpr const size_t size =
limits_type::radix == 2 && limits_type::digits < 32
? digits_on_size<unsigned long>::size : 32;
};
template <>
class guaranteed_bitlen<unsigned long long>
{
private:
guaranteed_bitlen(void) = delete;
guaranteed_bitlen(const guaranteed_bitlen&) = delete;
private:
typedef std::numeric_limits<unsigned long long> limits_type;
public:
static constexpr const size_t size =
limits_type::radix == 2 && limits_type::digits < 64
? digits_on_size<unsigned long long>::size : 64;
};
}
class position_array_params
{
private:
position_array_params(void) = delete;
position_array_params(const position_array_params&) = delete;
public:
#ifdef FFUZZYPP_DISABLE_POSITION_ARRAY
static constexpr const bool is_disabled_by_build = true;
#else
static constexpr const bool is_disabled_by_build = false;
#endif
static constexpr const size_t max_efficient_array_size = 1024;
};
static_assert(position_array_params::max_efficient_array_size >= 64,
"position_array_params::max_efficient_array_size must not be less than 64.");
template <
typename TBitmap,
typename TChar,
TChar CMin = std::numeric_limits<TChar>::min(),
TChar CMax = std::numeric_limits<TChar>::max()
>
class position_array_safety
{
private:
position_array_safety(void) = delete;
position_array_safety(const position_array_safety&) = delete;
public:
static constexpr const bool is_welldefined =
std::is_integral<TBitmap>::value &&
std::is_unsigned<TBitmap>::value &&
std::is_same<TBitmap, decltype(TBitmap(0u) | TBitmap(0u))>::value &&
std::is_integral<TChar>::value &&
(std::numeric_limits<TBitmap>::radix == 2 ||
std::is_same<TBitmap, unsigned>::value ||
std::is_same<TBitmap, unsigned long>::value ||
std::is_same<TBitmap, unsigned long long>::value
) &&
(CMin <= CMax) &&
(std::is_unsigned<TChar>::value
? CMax - CMin <= std::numeric_limits<size_t>::max()
: (0 <= CMin
? std::numeric_limits<intmax_t>::min() + intmax_t(CMin) <= intmax_t(CMax)
: intmax_t(CMax) <= std::numeric_limits<intmax_t>::max() + intmax_t(CMin)
) && intmax_t(CMax) - intmax_t(CMin) <= std::numeric_limits<size_t>::max()
) &&
(size_t(CMax) - size_t(CMin) < std::numeric_limits<size_t>::max()) &&
(sizeof(TBitmap) <= std::numeric_limits<size_t>::max() / (size_t(CMax) - size_t(CMin) + 1u));
public:
static constexpr const bool is_considered_efficient =
!position_array_params::is_disabled_by_build && is_welldefined &&
(size_t(CMax) - size_t(CMin) + 1u) <= position_array_params::max_efficient_array_size;
};
template <
typename TBitmap = unsigned long long,
typename TChar = char,
TChar CMin = std::numeric_limits<TChar>::min(),
TChar CMax = std::numeric_limits<TChar>::max()
>
class position_array
{
private:
static_assert(std::is_integral<TBitmap>::value, "TBitmap must be an integral type.");
static_assert(std::is_unsigned<TBitmap>::value, "TBitmap must be an unsigned integral type.");
static_assert(std::is_same<TBitmap, decltype(TBitmap(0u) | TBitmap(0u))>::value,
"TBitmap must preserve its type after integral promotion.");
static_assert(std::is_integral<TChar>::value, "TChar must be an integral type.");
static_assert(CMin <= CMax, "CMin must not be greater than CMax.");
static_assert(
/*
Because signed to unsigned conversion is well-defined,
this predicate also indicates whether size_t(CMax) - size_t(CMin) is valid.
Note that this predicate does not cover all the case where
char is signed and (CMin - CMax) is greater than the maximum value of intmax_t.
*/
std::is_unsigned<TChar>::value
? CMax - CMin <= std::numeric_limits<size_t>::max()
: (0 <= CMin
? std::numeric_limits<intmax_t>::min() + intmax_t(CMin) <= intmax_t(CMax)
: intmax_t(CMax) <= std::numeric_limits<intmax_t>::max() + intmax_t(CMin)
) && intmax_t(CMax) - intmax_t(CMin) <= std::numeric_limits<size_t>::max(),
"(CMax - CMin) must be in range of both size_t and the widest type with same signedness as TChar.");
static_assert(size_t(CMax) - size_t(CMin) < std::numeric_limits<size_t>::max(),
"(size_t(CMax) - size_t(CMin) + 1) must be in range of size_t.");
static_assert(sizeof(TBitmap) <= std::numeric_limits<size_t>::max() / (size_t(CMax) - size_t(CMin) + 1u),
"(array_size * sizeof(TBitmap)) must be in range of size_t.");
public:
static constexpr const size_t array_size = size_t(CMax) - size_t(CMin) + 1u;
static constexpr const size_t max_strlen = internal::guaranteed_bitlen<TBitmap>::size;
typedef TBitmap bitmap_type;
typedef TChar char_type;
static constexpr const char_type char_min = CMin;
static constexpr const char_type char_max = CMax;
private:
bitmap_type bitmap[array_size];
public:
void reset(void) noexcept
{
memset(bitmap, 0, sizeof(bitmap));
}
void construct_noinit(const char_type* str, size_t len) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(len <= max_strlen);
#endif
for (size_t i = 0; i < len; i++)
{
char_type ch = *str++;
#ifdef FFUZZYPP_DEBUG
assert(char_min <= ch && ch <= char_max);
#endif
bitmap[size_t(ch) - size_t(char_min)] |= bitmap_type(1u) << i;
}
}
void construct_noinit_safe(const char_type* str, size_t len) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(len <= max_strlen);
#endif
for (size_t i = 0; i < len; i++)
{
char_type ch = *str++;
if (ch < char_min || char_max < ch)
continue;
bitmap[size_t(ch) - size_t(char_min)] |= bitmap_type(1u) << i;
}
}
void construct(const char_type* str, size_t len) noexcept
{
reset();
construct_noinit(str, len);
}
void construct_safe(const char_type* str, size_t len) noexcept
{
reset();
construct_noinit_safe(str, len);
}
public:
bitmap_type bitmap_for(char_type ch) const noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(char_min <= ch && ch <= char_max);
#endif
return bitmap[size_t(ch) - size_t(char_min)];
}
bitmap_type bitmap_for_safe(char_type ch) const noexcept
{
if (ch < char_min || char_max < ch)
return bitmap_type(0u);
return bitmap[size_t(ch) - size_t(char_min)];
}
bitmap_type operator[](char_type ch) const noexcept
{
return bitmap_for(ch);
}
const bitmap_type* bitmap_data(void) const noexcept
{
return bitmap;
}
public:
position_array(void) noexcept = default; // initialize to undefined state
position_array(const position_array& other) noexcept
{
if (bitmap != other.bitmap)
memcpy(bitmap, other.bitmap, sizeof(bitmap));
}
const position_array& operator=(const position_array& other) noexcept
{
if (bitmap != other.bitmap)
memcpy(bitmap, other.bitmap, sizeof(bitmap));
return *this;
}
position_array(const char_type* str, size_t len) noexcept
{
construct(str, len);
}
position_array(const char_type* str, size_t len, bool safe) noexcept
{
if (safe)
construct_safe(str, len);
else
construct(str, len);
}
static void swap(position_array& a, position_array& b) noexcept
{
std::swap(a.bitmap, b.bitmap); // C++11 version of swap
}
};
namespace internal
{
template <size_t MaxSize, typename TChar, TChar CMin, TChar CMax, typename TEnabler = void>
class auto_position_array_internal;
template <size_t MaxSize, typename TChar, TChar CMin, TChar CMax>
class auto_position_array_internal<MaxSize, TChar, CMin, CMax, typename std::enable_if<(
MaxSize > 0 && MaxSize <= 16 && position_array_safety<unsigned, TChar, CMin, CMax>::is_considered_efficient
)>::type>
{
private:
auto_position_array_internal(void);
auto_position_array_internal(const auto_position_array_internal&) = delete;
public:
typedef unsigned int_type;
};
template <size_t MaxSize, typename TChar, TChar CMin, TChar CMax>
class auto_position_array_internal<MaxSize, TChar, CMin, CMax, typename std::enable_if<(
MaxSize > 16 && MaxSize <= 32 && position_array_safety<unsigned long, TChar, CMin, CMax>::is_considered_efficient
)>::type>
{
private:
auto_position_array_internal(void);
auto_position_array_internal(const auto_position_array_internal&) = delete;
public:
typedef unsigned long int_type;
};
template <size_t MaxSize, typename TChar, TChar CMin, TChar CMax>
class auto_position_array_internal<MaxSize, TChar, CMin, CMax, typename std::enable_if<(
MaxSize > 32 && MaxSize <= 64 && position_array_safety<unsigned long long, TChar, CMin, CMax>::is_considered_efficient
)>::type>
{
private:
auto_position_array_internal(void);
auto_position_array_internal(const auto_position_array_internal&) = delete;
public:
typedef unsigned long long int_type;
};
}
// Predicate to test if automatically-chosen position array available
template <
size_t MaxSize,
typename TChar = char,
TChar CMin = std::numeric_limits<TChar>::min(),
TChar CMax = std::numeric_limits<TChar>::max()
>
struct is_auto_position_array_available
: std::integral_constant<bool, (
(MaxSize > 0 && MaxSize <= 16 && position_array_safety<unsigned, TChar, CMin, CMax>::is_considered_efficient) ||
(MaxSize > 16 && MaxSize <= 32 && position_array_safety<unsigned long, TChar, CMin, CMax>::is_considered_efficient) ||
(MaxSize > 32 && MaxSize <= 64 && position_array_safety<unsigned long long, TChar, CMin, CMax>::is_considered_efficient)
)>
{ };
namespace internal
{
template <size_t MaxSize, typename TChar, TChar CMin, TChar CMax, bool>
class auto_position_array_impl;
template <size_t MaxSize, typename TChar, TChar CMin, TChar CMax>
class auto_position_array_impl<MaxSize, TChar, CMin, CMax, true>
{
private:
auto_position_array_impl(void) = delete;
auto_position_array_impl(const auto_position_array_impl&) = delete;
public:
typedef typename auto_position_array_internal<MaxSize, TChar, CMin, CMax>::int_type int_type;
typedef position_array<int_type, TChar, CMin, CMax> type;
};
template <size_t MaxSize, typename TChar, TChar CMin, TChar CMax>
class auto_position_array_impl<MaxSize, TChar, CMin, CMax, false>
{
private:
auto_position_array_impl(void) = delete;
auto_position_array_impl(const auto_position_array_impl&) = delete;
};
}
// Automatically-chosen position array
template <
size_t MaxSize,
typename TChar = char,
TChar CMin = std::numeric_limits<TChar>::min(),
TChar CMax = std::numeric_limits<TChar>::max()
>
class auto_position_array
: public internal::auto_position_array_impl<
MaxSize, TChar, CMin, CMax,
is_auto_position_array_available<MaxSize, TChar, CMin, CMax>::value
>
{
private:
auto_position_array(void) = delete;
auto_position_array(const auto_position_array&) = delete;
};
}}
#endif

154
src/ffuzzypp/strings/sequences.hpp

@ -0,0 +1,154 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
strings/sequences.hpp
Utilities to find/eliminate sequences of same characters
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_STRINGS_SEQUENCES_HPP
#define FFUZZYPP_STRINGS_SEQUENCES_HPP
#include <cstddef>
#include "terminators.hpp"
#include "transform.hpp"
#include "../utils/safe_int.hpp"
namespace ffuzzy {
namespace strings {
template <size_t MaxSequenceSize, typename Ttransform = default_char_transform>
class sequences
{
static_assert(safe_int::safe_add<
safe_int::uvalue<size_t, MaxSequenceSize>,
safe_int::uvalue<size_t, 1>
>::value,
"MaxSequenceSize + 1 must be in range of size_t.");
private:
sequences(void) = delete;
sequences(const sequences&) = delete;
public:
static constexpr const size_t max_sequence_size = MaxSequenceSize;
static_assert(max_sequence_size != 0, "max_sequence_size must not be zero.");
public:
static bool has_sequences(const char* buf, size_t size) noexcept
{
if (size <= max_sequence_size)
return false;
size_t seq = 0;
char prev = *buf++;
while (--size)
{
char curr = *buf++;
if (curr == prev)
{
if (++seq == max_sequence_size)
return true;
}
else
{
seq = 0;
prev = curr;
}
}
return false;
}
static size_t copy_elim_sequences(char* out, const char* in, size_t size) noexcept
{
if (size <= max_sequence_size)
{
for (size_t i = 0; i < size; i++)
*out++ = Ttransform::transform(*in++);
return size;
}
size_t csz = 1;
size_t seq = 0;
char prev = *in++;
*out++ = Ttransform::transform(prev);
while (--size)
{
char curr = *in++;
if (curr == prev)
{
if (++seq >= max_sequence_size)
{
seq = max_sequence_size;
continue;
}
*out++ = Ttransform::transform(curr); csz++;
}
else
{
*out++ = Ttransform::transform(curr); csz++;
seq = 0; prev = curr;
}
}
return csz;
}
template <char... terms>
class string_copy
{
private:
string_copy(void) = delete;
string_copy(const string_copy&) = delete;
public:
static bool copy_elim_sequences(char*& out, size_t outsize, const char*& in) noexcept
{
size_t seq = 0;
char prev = *in;
if (terminators<terms...>::isterm(prev))
return true;
if (outsize == 0)
return false;
*out++ = Ttransform::transform(prev); in++; outsize--;
while (true)
{
char curr = *in;
if (terminators<terms...>::isterm(curr))
return true;
in++;
if (curr == prev)
{
if (++seq >= max_sequence_size)
{
seq = max_sequence_size;
continue;
}
if (outsize == 0)
return false;
*out++ = Ttransform::transform(curr); outsize--;
}
else
{
if (outsize == 0)
return false;
*out++ = Ttransform::transform(curr); outsize--;
seq = 0; prev = curr;
}
}
// unreachable
return false;
}
};
};
}}
#endif

58
src/ffuzzypp/strings/terminators.hpp

@ -0,0 +1,58 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
strings/terminators.hpp
Terminator characters
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_STRINGS_TERMINATORS_HPP
#define FFUZZYPP_STRINGS_TERMINATORS_HPP
namespace ffuzzy {
namespace strings {
template <char...> class terminators;
template <>
class terminators<>
{
private:
terminators(void) = delete;
terminators(const terminators&) = delete;
public:
static bool isterm(char ch) noexcept
{
return !ch;
}
};
template <char c, char... rem>
class terminators<c, rem...>
{
private:
terminators(void) = delete;
terminators(const terminators&) = delete;
public:
static bool isterm(char ch) noexcept
{
return terminators<rem...>::isterm(ch) || ch == c;
}
};
}}
#endif

44
src/ffuzzypp/strings/transform.hpp

@ -0,0 +1,44 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
strings/transform.hpp
String transformation (char-to-char mapping) utility
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_STRINGS_TRANSFORM_HPP
#define FFUZZYPP_STRINGS_TRANSFORM_HPP
namespace ffuzzy {
namespace strings {
class default_char_transform
{
private:
default_char_transform(void) = delete;
default_char_transform(const default_char_transform&) = delete;
public:
static constexpr char transform(char ch) noexcept
{
return ch;
}
};
}}
#endif

60
src/ffuzzypp/utils/likely.hpp

@ -0,0 +1,60 @@
/*
ffuzzy++ Helper Libraries
likely.hpp
Branch prediction control macros
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_UTILS_LIKELY_HPP
#define FFUZZYPP_UTILS_LIKELY_HPP
#define FFUZZYPP_LIKELY_PORTABLE(x) (!!(x))
#ifndef FFUZZYPP_DISABLE_COMPILER_BUILTINS
#if !defined(__GNUC__)
#define FFUZZYPP_DISABLE_COMPILER_BUILTINS 1
#elif __GNUC__ < 2
// DISABLE: GNU compiler version < 2.0
#define FFUZZYPP_DISABLE_COMPILER_BUILTINS 1
#elif __GNUC__ >= 3
// ENABLE: GNU compiler version >= 3.0
#elif !defined(__GNUC_MINOR__)
#define FFUZZYPP_DISABLE_COMPILER_BUILTINS 1
#elif __GNUC_MINOR__ <= 95
// DISABLE: GNU compiler version <= 2.95
#define FFUZZYPP_DISABLE_COMPILER_BUILTINS 1
#endif
#endif
#ifdef FFUZZYPP_LIKELY
#undef FFUZZYPP_LIKELY
#endif
#ifdef FFUZZYPP_UNLIKELY
#undef FFUZZYPP_UNLIKELY
#endif
#ifdef FFUZZYPP_DISABLE_COMPILER_BUILTINS
#define FFUZZYPP_LIKELY FFUZZYPP_LIKELY_PORTABLE
#define FFUZZYPP_UNLIKELY FFUZZYPP_LIKELY_PORTABLE
#else
#define FFUZZYPP_LIKELY(x) (__builtin_expect(!!(x), 1))
#define FFUZZYPP_UNLIKELY(x) (__builtin_expect(!!(x), 0))
#endif
#endif

67
src/ffuzzypp/utils/minmax.hpp

@ -0,0 +1,67 @@
/*
ffuzzy++ Helper Libraries
minmax.hpp
C++14-compatible minimum / maximum library
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_UTILS_MINMAX_HPP
#define FFUZZYPP_UTILS_MINMAX_HPP
/*
std::min and std::max in C++11 are not marked constexpr.
On the other hand, C++14's std::min and std::max are marked constexpr.
This library implements constexpr min and max in C++11
(but compatible with C++14).
However, we won't implement initializer_list variant of
min and max since we aren't using it.
*/
namespace ffuzzy {
namespace minmax {
template <class T>
inline constexpr const T& min(const T& a, const T& b)
{
return b < a ? b : a;
}
template <class T, class Compare>
inline constexpr const T& min(const T& a, const T& b, Compare comp)
{
return comp(b, a) ? b : a;
}
template <class T>
inline constexpr const T& max(const T& a, const T& b)
{
return a < b ? b : a;
}
template <class T, class Compare>
inline constexpr const T& max(const T& a, const T& b, Compare comp)
{
return comp(a, b) ? b : a;
}
}}
#endif

129
src/ffuzzypp/utils/numeric_digits.hpp

@ -0,0 +1,129 @@
/*
ffuzzy++ Helper Libraries
numeric_digits.hpp
Construction of numeric digits
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_UTILS_NUMERIC_DIGITS_HPP
#define FFUZZYPP_UTILS_NUMERIC_DIGITS_HPP
#include <cstddef>
#include <cstdint>
#include <limits>
#include "safe_int.hpp"
#include "static_assert_query.hpp"
namespace ffuzzy {
namespace numeric_digits {
template <typename T, size_t Base>
static constexpr size_t in_base(T value) noexcept
{
static_assert(
safe_int::contracts::is_unsigned_integral_type<T>(),
"T must be an unsigned integral type.");
static_assert(Base >= 2, "Base must be at least two.");
return (value < Base) ? 1 : 1 + in_base<T, Base>(value / Base);
}
template <typename T>
static constexpr size_t in_decimal(T value) noexcept
{
return in_base<T, 10>(value);
}
// Sanity checks
#ifdef FFUZZYPP_STATIC_SANITY_CHECKS
namespace internal
{
static constexpr uintmax_t expull(uintmax_t base, uintmax_t exponent) noexcept
{
return
exponent == 0 ? 1 :
base * expull(base, exponent-1);
}
static_assert(expull(10, 0) == 1ull, "sanity check for expull(10, 0) failed.");
static_assert(expull(10, 1) == 10ull, "sanity check for expull(10, 1) failed.");
static_assert(expull(10, 2) == 100ull, "sanity check for expull(10, 2) failed.");
static_assert(expull(10, 3) == 1000ull, "sanity check for expull(10, 3) failed.");
static_assert(expull(10, 4) == 10000ull, "sanity check for expull(10, 4) failed.");
static_assert(expull(10, 19) == 10000000000000000000ull, "sanity check for expull(10, 19) failed.");
template <typename T>
struct digits_in_decimal_check
{
private:
template <uintmax_t i>
struct case_digit1
{
static constexpr const bool value = in_decimal<T>(i) == 1;
};
template <uintmax_t i>
struct case_digit2
{
static constexpr const bool value = in_decimal<T>(i + 10u) == 2;
};
template <uintmax_t i>
struct case_many_borders
{
static constexpr const bool value0 =
std::numeric_limits<T>::max() < (expull(10, i+1) - 1)
|| in_decimal<T>(T(expull(10, i+1) - 1)) == i + 1;
static constexpr const bool value1 =
std::numeric_limits<T>::max() < expull(10, i+1)
|| in_decimal<T>(T(expull(10, i+1))) == i + 2;
static constexpr const bool value = value0 && value1;
};
public:
static constexpr const bool value =
static_assert_query::is_all<case_digit1, 10>::value &&
static_assert_query::is_all<case_digit2, 90>::value &&
static_assert_query::is_all<case_many_borders, 19>::value;
};
#ifdef FFUZZYPP_LOCAL_CHK
#error do not define FFUZZYPP_LOCAL_CHK
#endif
#define FFUZZYPP_LOCAL_CHK(typ) \
static_assert(digits_in_decimal_check<typ>::value, \
"sanity checks for digits_in_decimal failed for " #typ ".")
FFUZZYPP_LOCAL_CHK(unsigned char);
FFUZZYPP_LOCAL_CHK(unsigned short);
FFUZZYPP_LOCAL_CHK(unsigned int);
FFUZZYPP_LOCAL_CHK(unsigned long);
FFUZZYPP_LOCAL_CHK(unsigned long long);
FFUZZYPP_LOCAL_CHK(uint_least8_t);
FFUZZYPP_LOCAL_CHK(uint_least16_t);
FFUZZYPP_LOCAL_CHK(uint_least32_t);
FFUZZYPP_LOCAL_CHK(uint_least64_t);
FFUZZYPP_LOCAL_CHK(uint_fast8_t);
FFUZZYPP_LOCAL_CHK(uint_fast16_t);
FFUZZYPP_LOCAL_CHK(uint_fast32_t);
FFUZZYPP_LOCAL_CHK(uint_fast64_t);
FFUZZYPP_LOCAL_CHK(uintmax_t);
FFUZZYPP_LOCAL_CHK(size_t);
#undef FFUZZYPP_LOCAL_CHK
}
#endif
}}
#endif

116
src/ffuzzypp/utils/ranges.hpp

@ -0,0 +1,116 @@
/*
ffuzzy++ Helper Libraries
ranges.hpp
Value range library
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_UTILS_RANGES_HPP
#define FFUZZYPP_UTILS_RANGES_HPP
#include <limits>
namespace ffuzzy {
namespace ranges {
/*
Inclusive range ([a, b] where a <= b)
*/
template <typename T>
class inclusive
{
T v_begin;
T v_end;
public:
class iterator
{
private:
T value;
T value_end;
bool is_end;
private:
constexpr iterator(
T value,
T value_end,
bool is_end = false
) noexcept
: value(value)
, value_end(value_end)
, is_end(is_end)
{ }
friend class inclusive;
public:
constexpr iterator(const iterator&) noexcept = default;
constexpr T operator*(void) const noexcept
{
return value;
}
/* can be constexpr in C++14 */
#if __cpp_constexpr >= 201304L
constexpr
#endif
iterator& operator++(void) noexcept
{
if (!is_end)
{
if (value == value_end)
is_end = true;
else
++value;
}
return *this;
}
public:
constexpr bool operator==(
const iterator& other
) const noexcept
{
return
value == other.value &&
value_end == other.value_end &&
is_end == other.is_end;
}
constexpr bool operator!=(
const iterator& other
) const noexcept
{
return !(*this == other);
}
};
public:
constexpr iterator begin(void) const noexcept
{
return iterator(v_begin, v_end, false);
}
constexpr iterator end(void) const noexcept
{
return iterator(v_end, v_end, true);
}
public:
constexpr inclusive(T vbegin, T vend) noexcept
: v_begin(vbegin), v_end(vend) { }
constexpr inclusive(void) noexcept
: v_begin(std::numeric_limits<T>::min())
, v_end (std::numeric_limits<T>::max()) { }
};
}}
#endif

371
src/ffuzzypp/utils/safe_int.hpp

@ -0,0 +1,371 @@
/*
ffuzzy++ Helper Libraries
safe_int.hpp
Safe integer handling utilities
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_UTILS_SAFE_INT_HPP
#define FFUZZYPP_UTILS_SAFE_INT_HPP
#include <cstdint>
#include <limits>
#include <type_traits>
namespace ffuzzy {
namespace safe_int {
namespace contracts
{
template <typename T>
static inline constexpr bool is_integral_type(void) noexcept
{
return std::is_integral<T>::value;
}
template <typename T>
static inline constexpr bool is_signed_integral_type(void) noexcept
{
return is_integral_type<T>() &&
std::is_unsigned<T>::value == false &&
std::numeric_limits<T>::max() > 0 &&
std::numeric_limits<T>::min() < 0;
}
template <typename T>
static inline constexpr bool is_unsigned_integral_type(void) noexcept
{
return is_integral_type<T>() &&
std::is_unsigned<T>::value == true &&
std::numeric_limits<T>::min() == 0;
}
template <typename T>
static inline constexpr bool is_binary_integral_type(void) noexcept
{
return
std::numeric_limits<T>::radix == 2 &&
std::numeric_limits<T>::digits >= 0;
}
// Same implementation but copying for better diagnostics
template <typename T>
struct integral_type
{
static_assert(std::is_integral<T>::value,
"T must be an integral type.");
};
template <typename T>
struct signed_integral_type
: integral_type<T>
{
static_assert(std::is_unsigned<T>::value == false,
"T must be a signed integral type.");
static_assert(std::numeric_limits<T>::max() > 0,
"numeric_limits<T>::max() must be positive for signed integral type.");
static_assert(std::numeric_limits<T>::min() < 0,
"numeric_limits<T>::min() must be negative for signed integral type.");
};
template <typename T>
struct unsigned_integral_type
: integral_type<T>
{
static_assert(std::is_unsigned<T>::value == true,
"T must be an unsigned integral type.");
static_assert(std::numeric_limits<T>::min() == 0,
"numeric_limits<T>::min() must be zero for unsigned integral type.");
};
template <typename T>
struct binary_integral_type
: integral_type<T>
{
static_assert(std::numeric_limits<T>::radix == 2,
"numeric_limits<T>::radix must be 2 for binary integral type.");
static_assert(std::numeric_limits<T>::digits >= 0,
"numeric_limits<T>::digits must not be negative for binary integral type.");
};
}
namespace internal
{
template <typename T1, typename T2>
struct common_unsigned_integral_type
: contracts::unsigned_integral_type<T1>
, contracts::unsigned_integral_type<T2>
{
typedef typename std::conditional<
std::numeric_limits<T1>::max() < std::numeric_limits<T2>::max(),
T2, T1
>::type type;
};
template <typename T>
struct common_unsigned_integral_type<T, T>
{
typedef T type;
};
template <typename Tcommon, typename Tvalue, Tcommon Value, bool IsValid = true>
struct value_base
{
typedef Tcommon common_type;
typedef Tvalue value_type;
static constexpr const bool is_valid = IsValid
&& std::numeric_limits<Tvalue>::min() <= Value
&& std::numeric_limits<Tvalue>::max() >= Value;
static constexpr const Tcommon value_in_common = Value;
static constexpr const Tvalue value =
is_valid ? static_cast<Tvalue>(Value) : 0;
};
}
template <typename T, uintmax_t Value, bool IsValid = true>
struct uvalue
: contracts::unsigned_integral_type<T>
, public internal::value_base<uintmax_t, T, Value, IsValid>
{};
template <typename T, intmax_t Value, bool IsValid = true>
struct svalue
: contracts::signed_integral_type<T>
, public internal::value_base<intmax_t, T, Value, IsValid>
{};
namespace operations
{
template <typename TV1, typename TV2> struct safe_add;
template <typename T1, uintmax_t V1, bool B1, typename T2, uintmax_t V2, bool B2>
struct safe_add<uvalue<T1, V1, B1>, uvalue<T2, V2, B2>>
{
private:
typedef typename internal::common_unsigned_integral_type<T1, T2>::type common_type;
public:
typedef uvalue<common_type, V1 + V2, B1 && B2 && (
std::numeric_limits<common_type>::max() - V1 >= V2
)> type;
};
template <typename TV1, typename TV2> struct safe_sub;
template <typename T1, uintmax_t V1, bool B1, typename T2, uintmax_t V2, bool B2>
struct safe_sub<uvalue<T1, V1, B1>, uvalue<T2, V2, B2>>
{
private:
typedef typename internal::common_unsigned_integral_type<T1, T2>::type common_type;
public:
typedef uvalue<common_type, V1 - V2, B1 && B2 && V1 >= V2> type;
};
template <typename TV1, typename TV2> struct safe_mul;
template <typename T1, uintmax_t V1, bool B1, typename T2, uintmax_t V2, bool B2>
struct safe_mul<uvalue<T1, V1, B1>, uvalue<T2, V2, B2>>
{
private:
typedef typename internal::common_unsigned_integral_type<T1, T2>::type common_type;
public:
typedef uvalue<common_type, V1 * V2, B1 && B2 && (
V1 == 0 || V2 == 0 ||
std::numeric_limits<common_type>::max() / V2 > V1
)> type;
};
template <typename TV1, typename TV2> struct safe_div;
template <typename T1, uintmax_t V1, bool B1, typename T2, uintmax_t V2, bool B2>
struct safe_div<uvalue<T1, V1, B1>, uvalue<T2, V2, B2>>
{
private:
typedef typename internal::common_unsigned_integral_type<T1, T2>::type common_type;
public:
typedef uvalue<common_type, V2 ? V1 / V2 : 0, B1 && B2 && V2 != 0> type;
};
template <typename TVbase, typename TVshift> struct safe_lshift;
template <typename TB, uintmax_t VB, bool BB, typename TS, uintmax_t VS, bool BS>
struct safe_lshift<uvalue<TB, VB, BB>, uvalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
// Refer C++11 specification [3.9.1 p3] for reason that
// conversion to "unsigned" for non-negative "int" numbers is safe.
static constexpr const bool is_valid = BB && BS
&& VS < static_cast<unsigned>(std::numeric_limits<TB>::digits)
&& (std::numeric_limits<TB>::max() >> VS) >= VB;
public:
typedef uvalue<TB, is_valid ? (VB << VS) : 0, is_valid> type;
};
template <typename TB, uintmax_t VB, bool BB, typename TS, intmax_t VS, bool BS>
struct safe_lshift<uvalue<TB, VB, BB>, svalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
static constexpr const bool is_valid = BB && BS
&& VS >= 0
&& VS < std::numeric_limits<TB>::digits
&& (std::numeric_limits<TB>::max() >> VS) >= VB;
public:
typedef uvalue<TB, is_valid ? (VB << VS) : 0, is_valid> type;
};
template <typename TB, intmax_t VB, bool BB, typename TS, uintmax_t VS, bool BS>
struct safe_lshift<svalue<TB, VB, BB>, uvalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
static constexpr const bool is_valid = BB && BS
&& VS < static_cast<unsigned>(std::numeric_limits<TB>::digits)
&& (std::numeric_limits<TB>::max() >> VS) >= VB;
public:
typedef svalue<TB, is_valid ? (VB << VS) : 0, is_valid> type;
};
template <typename TB, intmax_t VB, bool BB, typename TS, intmax_t VS, bool BS>
struct safe_lshift<svalue<TB, VB, BB>, svalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
static constexpr const bool is_valid = BB && BS
&& VS >= 0
&& VS < std::numeric_limits<TB>::digits
&& (std::numeric_limits<TB>::max() >> VS) >= VB;
public:
typedef svalue<TB, is_valid ? (VB << VS) : 0, is_valid> type;
};
template <typename TVbase, typename TVshift> struct safe_rshift;
template <typename TB, uintmax_t VB, bool BB, typename TS, uintmax_t VS, bool BS>
struct safe_rshift<uvalue<TB, VB, BB>, uvalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
static constexpr const bool is_valid = BB && BS
&& VS < static_cast<unsigned>(std::numeric_limits<TB>::digits);
public:
typedef uvalue<TB, is_valid ? (VB >> VS) : 0, is_valid> type;
};
template <typename TB, uintmax_t VB, bool BB, typename TS, intmax_t VS, bool BS>
struct safe_rshift<uvalue<TB, VB, BB>, svalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
static constexpr const bool is_valid = BB && BS
&& VS >= 0
&& VS < std::numeric_limits<TB>::digits;
public:
typedef uvalue<TB, is_valid ? (VB >> VS) : 0, is_valid> type;
};
template <typename TB, intmax_t VB, bool BB, typename TS, uintmax_t VS, bool BS>
struct safe_rshift<svalue<TB, VB, BB>, uvalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
static constexpr const bool is_valid = BB && BS
&& VS < static_cast<unsigned>(std::numeric_limits<TB>::digits);
public:
typedef svalue<TB, is_valid ? (VB >> VS) : 0, is_valid> type;
};
template <typename TB, intmax_t VB, bool BB, typename TS, intmax_t VS, bool BS>
struct safe_rshift<svalue<TB, VB, BB>, svalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
static constexpr const bool is_valid = BB && BS
&& VS >= 0
&& VS < std::numeric_limits<TB>::digits;
public:
typedef svalue<TB, is_valid ? (VB >> VS) : 0, is_valid> type;
};
namespace internal
{
// internal::value_base performs some required tests
template <typename Tnew, typename TV> struct safe_cast_to_u;
template <typename Tnew, typename Told, uintmax_t V, bool B>
struct safe_cast_to_u<Tnew, uvalue<Told, V, B>>
{
typedef uvalue<Tnew, V, B> type;
};
template <typename Tnew, typename Told, intmax_t V, bool B>
struct safe_cast_to_u<Tnew, svalue<Told, V, B>>
{
private:
static constexpr const bool is_valid = B && V >= 0;
public:
typedef uvalue<Tnew,
is_valid ? static_cast<uintmax_t>(V) : 0,
is_valid> type;
};
template <typename Tnew, typename TV> struct safe_cast_to_s;
template <typename Tnew, typename Told, intmax_t V, bool B>
struct safe_cast_to_s<Tnew, svalue<Told, V, B>>
{
typedef svalue<Tnew, V, B> type;
};
template <typename Tnew, typename Told, uintmax_t V, bool B>
struct safe_cast_to_s<Tnew, uvalue<Told, V, B>>
{
private:
static constexpr const bool is_valid = B
&& V <= static_cast<uintmax_t>(std::numeric_limits<intmax_t>::max());
public:
typedef svalue<Tnew,
is_valid ? static_cast<intmax_t>(V) : 0,
is_valid> type;
};
}
template <typename Tnew, typename TV>
struct safe_cast
: public std::conditional<
contracts::is_unsigned_integral_type<Tnew>(),
internal::safe_cast_to_u<Tnew, TV>,
typename std::conditional<
contracts::is_signed_integral_type<Tnew>(),
internal::safe_cast_to_s<Tnew, TV>, void
>::type
>::type {};
}
template <typename TV1, typename TV2>
using safe_add = typename operations::safe_add<TV1, TV2>::type;
template <typename TV1, typename TV2>
using safe_sub = typename operations::safe_sub<TV1, TV2>::type;
template <typename TV1, typename TV2>
using safe_mul = typename operations::safe_mul<TV1, TV2>::type;
template <typename TV1, typename TV2>
using safe_div = typename operations::safe_div<TV1, TV2>::type;
template <typename TVbase, typename TVshift>
using safe_lshift = typename operations::safe_lshift<TVbase, TVshift>::type;
template <typename TVbase, typename TVshift>
using safe_rshift = typename operations::safe_rshift<TVbase, TVshift>::type;
template <typename Tnew, typename TV>
using safe_cast = typename operations::safe_cast<Tnew, TV>::type;
}}
#endif

97
src/ffuzzypp/utils/static_assert_query.hpp

@ -0,0 +1,97 @@
/*
ffuzzy++ Helper Libraries
static_assert_query.hpp
Basic queries for static assertions
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_UTILS_STATIC_ASSERT_QUERY_HPP
#define FFUZZYPP_UTILS_STATIC_ASSERT_QUERY_HPP
#include <cstdint>
namespace ffuzzy {
namespace static_assert_query {
namespace internal
{
template <template <uintmax_t> class T, uintmax_t a, uintmax_t b>
struct is_all_bounds
{
static_assert(a <= b, "bounds must be valid (a must not exceed b).");
/*
For unsigned types,
a/2 + b/2 + ((a%2)+(b%2))/2
is a remplacement of
(a+b)/2
while preventing arithmetic overflow of (a+b).
*/
static constexpr const bool value =
a > b ? false :
is_all_bounds<T, a, a / 2 + b / 2 + ((a % 2) + (b % 2)) / 2>::value &&
is_all_bounds<T, a / 2 + b / 2 + ((a % 2) + (b % 2)) / 2 + 1, b>::value;
};
template <template <uintmax_t> class T, uintmax_t a>
struct is_all_bounds<T, a, a>
{
static constexpr const bool value = T<a>::value;
};
template <template <uintmax_t> class T, uintmax_t a, uintmax_t b>
struct is_any_bounds
{
static_assert(a <= b, "bounds must be valid (a must not exceed b).");
static constexpr const bool value =
a > b ? false :
is_any_bounds<T, a, a / 2 + b / 2 + ((a % 2) + (b % 2)) / 2>::value ||
is_any_bounds<T, a / 2 + b / 2 + ((a % 2) + (b % 2)) / 2 + 1, b>::value;
};
template <template <uintmax_t> class T, uintmax_t a>
struct is_any_bounds<T, a, a>
{
static constexpr const bool value = T<a>::value;
};
}
template <template <uintmax_t> class T, uintmax_t n>
struct is_all
{
static constexpr const bool value = internal::is_all_bounds<T, 0, n-1>::value;
};
template <template <uintmax_t> class T>
struct is_all<T, 0>
{
static constexpr const bool value = true;
};
template <template <uintmax_t> class T, uintmax_t n>
struct is_any
{
static constexpr const bool value = internal::is_any_bounds<T, 0, n-1>::value;
};
template <template <uintmax_t> class T>
struct is_any<T, 0>
{
static constexpr const bool value = false;
};
}}
#endif

67
src/ffuzzypp/utils/type_modifier.hpp

@ -0,0 +1,67 @@
/*
ffuzzy++ Helper Libraries
type_modifier.hpp
C++11 type modifier utilities
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_UTILS_TYPE_MODIFIER_HPP
#define FFUZZYPP_UTILS_TYPE_MODIFIER_HPP
#include <type_traits>
namespace ffuzzy {
namespace type_mod {
template <typename T, bool IsConst, bool IsVolatile>
struct cv_selector;
template <typename T>
struct cv_selector<T, false, false>
{
typedef T type;
};
template <typename T>
struct cv_selector<T, true, false>
{
typedef const T type;
};
template <typename T>
struct cv_selector<T, false, true>
{
typedef volatile T type;
};
template <typename T>
struct cv_selector<T, true, true>
{
typedef const volatile T type;
};
template <
typename T,
typename Tmatch,
bool IsConst = std::is_const<T>::value,
bool IsVolatile = std::is_volatile<T>::value
>
struct cv_match
{
typedef typename cv_selector<Tmatch, IsConst, IsVolatile>::type type;
};
}}
#endif

2
src/lib/ffuzzypp-release-4.0.1/.gitattributes

@ -0,0 +1,2 @@
/COPYING* -whitespace
*.md -whitespace

41
src/lib/ffuzzypp-release-4.0.1/.gitignore

@ -0,0 +1,41 @@
.*
!.git?*
*~
*.a
*.diff
*.dll
*.exe
*.in
*.la
*.lo
*.o
*.obj
*.out
*.patch
*.pdb
*.swp
*.tmp
aclocal.m4
autoscan.log
autom4te.cache
config.log
config.status
configure
configure.scan
confdefs*
conftest*
conf[0-9]*
ffuzzy_config.h
libtool
Makefile
so_locations
stamp-h1
tmp*
_libs
ffuzzypp-*
/Doxyfile
/html/
/latex/
/doc/

23
src/lib/ffuzzypp-release-4.0.1/COPYING.Boost

@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

339
src/lib/ffuzzypp-release-4.0.1/COPYING.GPLv2

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

674
src/lib/ffuzzypp-release-4.0.1/COPYING.GPLv3

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

43
src/lib/ffuzzypp-release-4.0.1/COPYING.GPLv3Autoconf

@ -0,0 +1,43 @@
AUTOCONF CONFIGURE SCRIPT EXCEPTION
Version 3.0, 18 August 2009
Copyright (C) 2009 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This Exception is an additional permission under section 7 of the GNU
General Public License, version 3 ("GPLv3"). It applies to a given
file that bears a notice placed by the copyright holder of the file
stating that the file is governed by GPLv3 along with this Exception.
The purpose of this Exception is to allow distribution of Autoconf's
typical output under terms of the recipient's choice (including
proprietary).
0. Definitions
"Covered Code" is the source or object code of a version of Autoconf
that is a covered work under this License.
"Normally Copied Code" for a version of Autoconf means all parts of
its Covered Code which that version can copy from its code (i.e., not
from its input file) into its minimally verbose, non-debugging and
non-tracing output.
"Ineligible Code" is Covered Code that is not Normally Copied Code.
1. Grant of Additional Permission.
You have permission to propagate output of Autoconf, even if such
propagation would otherwise violate the terms of GPLv3. However, if
by modifying Autoconf you cause any Ineligible Code of the version you
received to become Normally Copied Code of your modified version, then
you void this Exception for the resulting covered work. If you convey
that resulting covered work, you must remove this Exception in accordance
with the second paragraph of Section 7 of GPLv3.
2. No Weakening of Autoconf Copyleft.
The availability of this Exception does not imply any general presumption
that third-party software is unaffected by the copyleft requirements of
the license of Autoconf.

87
src/lib/ffuzzypp-release-4.0.1/COPYING.md

@ -0,0 +1,87 @@
ffuzzy++ : C++ implementation of fast fuzzy hashing
====================================================
License / Copying (ffuzzy++)
-----------------------------
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
License / Copying (configuration scripts)
------------------------------------------
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the Autoconf Configure Script Exception,
version 3.0, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License
and a copy of the Autoconf Configure Script Exception along with
this program; see the files COPYING.GPLv3 and COPYING.GPLv3Autoconf
respectively. If not, see <http://www.gnu.org/licenses/>.
License Files
--------------
* COPYING.GPLv3
GNU General Public License, version 3
* COPYING.GPLv3Autoconf
Autoconf Configure Script Exception, version 3
* COPYING.GPLv2
GNU General Public License, version 2
* COPYING.Boost
Boost Software License, version 1.0
Credits
--------
The most part of the source code are copied from fuzzy.c
in ssdeep version 2.11 (heavily modified though).
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
fuzzy.c (in ssdeep 2.11) is licensed under the terms of the
GNU General Public License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.
The indel distance code is contributed from kikairoya on Github.
Copyright (C) 2014 kikairoya <kikairoya@gmail.com>
This portion of code is licensed under the terms of the
Boost Software License, version 1.0 (compatible with GPLv2+).
Tsukasa OI (the original author of libffuzzy and ffuzzy++) modified
them and wrote a fast implementation.
Copyright (C) 2014, 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
The license of the modified portion may vary by place
(mostly licensed under the ISC license).
See the source code for details.

64
src/lib/ffuzzypp-release-4.0.1/Makefile.am

@ -0,0 +1,64 @@
#
#
# ffuzzy++ : C++ implementation of fast fuzzy hashing
#
# Makefile.am
# Makefile template for top directory
#
# Copyright (C) 2015 Tsukasa OI.
#
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all copies.
#
# 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.
#
#
if ENABLE_STATIC_LIB
lib_LIBRARIES = libffuzzypp.a
libffuzzypp_a_SOURCES = ffuzzy_declarations.cpp
endif
nobase_include_HEADERS = \
ffuzzy.hpp \
ffuzzypp/base64.hpp \
ffuzzypp/context_hash.hpp \
ffuzzypp/context_hash_fast.hpp \
ffuzzypp/digest.hpp \
ffuzzypp/digest_base.hpp \
ffuzzypp/digest_blocksize.hpp \
ffuzzypp/digest_comparison.hpp \
ffuzzypp/digest_data.hpp \
ffuzzypp/digest_filesize.hpp \
ffuzzypp/digest_generator.hpp \
ffuzzypp/digest_position_array.hpp \
ffuzzypp/digest_position_array_base.hpp \
ffuzzypp/rolling_hash.hpp \
ffuzzypp/rolling_hash_ssdeep.hpp \
ffuzzypp/strings/common_substr.hpp \
ffuzzypp/strings/edit_dist.hpp \
ffuzzypp/strings/nosequences.hpp \
ffuzzypp/strings/position_array.hpp \
ffuzzypp/strings/sequences.hpp \
ffuzzypp/strings/terminators.hpp \
ffuzzypp/strings/transform.hpp \
ffuzzypp/utils/likely.hpp \
ffuzzypp/utils/minmax.hpp \
ffuzzypp/utils/numeric_digits.hpp \
ffuzzypp/utils/ranges.hpp \
ffuzzypp/utils/safe_int.hpp \
ffuzzypp/utils/static_assert_query.hpp \
ffuzzypp/utils/type_modifier.hpp
EXTRA_DIST = \
bootstrap.sh \
README.md NEWS.md \
COPYING.md COPYING.GPLv2 COPYING.Boost \
COPYING.GPLv3 COPYING.GPLv3Autoconf \
.gitignore .gitattributes ext/.gitignore
SUBDIRS = examples tests

30
src/lib/ffuzzypp-release-4.0.1/NEWS.md

@ -0,0 +1,30 @@
ffuzzy++ : C++ implementation of fast fuzzy hashing
====================================================
Version 4.0.1 - 2017-06-28
---------------------------
* `make dist` issue is now fixed.
Version 4.0 - 2017-06-28
-------------------------
* NEW: Bit-parallelism
(clustering can be over 10 times faster than version 3.0)
* Digest generator is optimized
(can be twice as fast as version 3.0)
* Utility methods are added
Version 3.0.1 - 2017-06-04
---------------------------
* Uses of deprecates type trait are now replaced with decent ones.
Version 3.0 - 2015-04-25
-------------------------
* The initial public release

229
src/lib/ffuzzypp-release-4.0.1/README.md

@ -0,0 +1,229 @@
ffuzzy++ : C++ implementation of ssdeep-compatible fast fuzzy hashing
======================================================================
What is ffuzzy++?
------------------
ffuzzy++ is a fuzzy hash implementation compatible with
ssdeep version 2.13 (<http://ssdeep.sourceforge.net/>).
Using this implementation, you can:
* Generate fuzzy digests from files and buffers
* Compare fuzzy digests generated from ffuzzy++ or
other ssdeep-compatible implementations
This implementation is designed to be fast, stable and thread-safe.
Sometimes this is about 60% to 120% faster than ssdeep when you
cluster digests and is about 10% to 60% faster than ssdeep when
you generate digests.
However, this C++ implementation is primarily designed to be fast
by exposing internal structure of fuzzy hashing. So this
implementation may not be safe as you think (depends on function
you use). Instead, you can boost your clustering application
using efficient digest utilities.
Requirements
-------------
You will need C++ compiler with full C++11 support.
You will also need GNU Autoconf Archive when you build `configure`
script (<https://www.gnu.org/software/autoconf-archive/>).
If you wish to run the test, Google C++ Testing Framework
(<https://code.google.com/p/googletest/>) will be needed.
Installation
-------------
This program can be installed without proper "installation".
Just copy `ffuzzy.hpp` and `ffuzzypp` directory to anywhere you want.
In this case, you need to define `FFUZZYPP_DECLARATIONS` before
`ffuzzy.hpp` in **one** of the source files to make the linker happy.
You can compile and install a static helper library `libffuzzypp.a`
by running `./configure && make && make install`.
If you don't have `configure` script on the top directory, you need
to run `./bootstrap.sh` to make build files.
Configuration Options
----------------------
* --disable-static-lib
Disable building `libffuzzypp.a`
* --disable-debug
Disable assertions on examples and tests.
Don't disable assertions if you wish to test ffuzzy++.
* --disable-position-array
Disable using bit-parallel algorithms on examples and tests.
* --enable-examples
Enable building examples (see "Building Examples" section)
* --enable-tests
Enable building test cases (see "Running Tests" section)
* --disable-compatibility-tests
Ignore ssdeep-specific parameters during compilation of
test cases. This option prevents compiling compatibility tests.
Building Examples
------------------
There are two examples:
* examples/compare-hash
You can use this program to compare two fuzzy digests.
* examples/compute-hash
You can use this program to compute fuzzy digests from
given files.
Running Tests
--------------
By default, compatibility tests (which depends on ssdeep-specific
parameters) are enabled and you can disable these tests by adding
`--disable-compatibility-tests` configuration option.
* tests/test-small
Relatively small tests (that can be done in a few minutes).
* tests/test-compatibility-small
Compatibility tests (depends on ssdeep parameters)
* tests/test-compatibility-large
Large compatibility tests (depends on ssdeep parameters)
* tests/test-precond
Precondition tests (it always succeeds at runtime because
all "tests" are performed while compiling this executable).
Configuration
--------------
Defining certain macros before including `ffuzzy.hpp` can change some
behavior of this library.
* `FFUZZYPP_DEBUG`
This macro enables assertions for debugging.
* `FFUZZYPP_DISABLE_POSITION_ARRAY`
This macro disables using bit-parallel algorithms.
Caution
--------
* This package is intended for static-linking to your program.
* Packaging this implementation **alone** for OS distribution
is not recommended. The interface may change without notice.
* Digests generated from files equal to or larger than 4GiB
are not portable enough. See following secions for details.
Differences between ssdeep
---------------------------
When comparing identical digests, ssdeep 2.9 and 2.13 return different
values. By default, ffuzzy++ emulates behavior of version 2.13.
If you give `comparison_version::v2_9` to `comparison`-related function
as a template parameter, ffuzzy++ will emulate behavior of version 2.9.
Result of comparison is not in a signed type but in an unsigned type
because error handling things are moved out of comparison.
So comparison functions cannot return -1 on error (like ssdeep/libfuzzy).
Instead, digest parser (which will be used before comparison) will raise
an exception when it fails to parse digest string.
Differences between ssdeep -2.12 (DETAILS)
-------------------------------------------
Because of current implementation restrictions in ssdeep 2.12 and before
(not in ffuzzy++), the digest and comparison result may different when:
* Extremely large files are given (for example):
* For files equal to or larger than 4GiB,
ssdeep 2.10-2.12 on 32-bit platform and ssdeep -2.9
causes arithmetic overflow while handling file sizes.
This will result in unexpected behavior.
* For files larger than 4GiB,
ssdeep -2.12's rolling hash implementation is not exactly
rolling. This will result in incorrect digest value.
* For files larger than 96GiB,
ssdeep 2.10-2.12 will crash under some circumstances.
ssdeep 2.9 with 64-bit file size patch will use incorrect value
(because of arithmetic overflow) when generating digests.
ffuzzy++'s implementation matches mathematical properties
of ssdeep digest generation algorithm while preventing
arithmetic overflow bug on ssdeep 2.9 with
64-bit file size patch.
* For files equal to or larger than 2^64 bytes,
ssdeep 2.10-2.12 on 64-bit platform will cause arithmetic
overflow on file sizes. Although we don't accept
files larger than 192GiB (see "Limitations" section), ssdeep
-2.12 doesn't have mechanism to prevent file size overflow.
* Some digests generated from extremely large files are given:
* For digests generated from files larger than 12GiB,
ssdeep -2.12 may cause arithmetic overflow while comparing
digests. This may make incorrect comparison score of zero.
Overrall, ffuzzy++ is almost compatible with ssdeep -2.12. But on some
circumstances which ssdeep will fail or did not support (yes, actually
files equal to or larger than 4GiB are not officially supported by
ssdeep -2.12), ffuzzy++ returns mostly legit values
(based on mathematical properties of ssdeep).
Differences between ssdeep 2.13
--------------------------------
ssdeep 2.13 behaves very similar to ffuzzy++ due to bug fixes.
There are few implementation differences but behaves the same when:
* Generating fuzzy digests from arbitrary input
* Comparing digests generated by new implementations
* Comparing digests generated from files up to 96GiB
by previous ssdeep versions
Limitations
------------
Both implementations (ssdeep and ffuzzy++) have a limit of 192GiB in
digest generator. Based on mathematical properties of ssdeep,
we **could** accept much larger files. However, digests generated
from such files are nearly useless (because resulting digests will
not represent signature of whole file contents).
So I decided not to accept files larger than 192GiB on ffuzzy++
as well as ssdeep 2.10+.
Although ffuzzy++ implementation is completely platform-independent,
ssdeep digest for files equal to or larger than 4GiB are still not
portable enough (varies by ssdeep versions and platforms).
Make sure that you use new implementations (ssdeep 2.13 or ffuzzy++)
when you accept extremely large files. If you use older versions of
ssdeep, please consider rejecting such big files (equal to or larger
than 4GiB) when you generate digests.
License / Copying
------------------
See `COPYING.md` file for details.

2
src/lib/ffuzzypp-release-4.0.1/bootstrap.sh

@ -0,0 +1,2 @@
#! /bin/sh
autoreconf -f -i

94
src/lib/ffuzzypp-release-4.0.1/configure.ac

@ -0,0 +1,94 @@
#
#
# ffuzzy++ : C++ implementation of fast fuzzy hashing
#
# configure.ac
# Configuration script
#
# Copyright (C) 2017 Tsukasa OI.
#
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# Under Section 7 of GPL version 3, you are granted additional
# permissions described in the Autoconf Configure Script Exception,
# version 3.0, as published by the Free Software Foundation.
#
# You should have received a copy of the GNU General Public License
# and a copy of the Autoconf Configure Script Exception along with
# this program; see the files COPYING.GPLv3 and COPYING.GPLv3Autoconf
# respectively. If not, see <http://www.gnu.org/licenses/>.
#
#
AC_PREREQ([2.65])
AC_INIT([ffuzzypp], [4.0.1], [floss_ssdeep@irq.a4lg.com])
AC_CONFIG_SRCDIR([ffuzzy_declarations.cpp])
AC_CONFIG_AUX_DIR([ext])
AM_INIT_AUTOMAKE([foreign dist-xz])
dnl --disable-static-lib
AC_ARG_ENABLE([static-lib],
[AS_HELP_STRING([--disable-static-lib],[disable compiling static library libffuzzypp.a])],,
[enable_static_lib=yes])
AM_CONDITIONAL([ENABLE_STATIC_LIB],[test "x$enable_static_lib" != xno])
dnl --disable-debug
AC_ARG_ENABLE([debug],
[AS_HELP_STRING([--disable-debug],[disable debugging support on examples and tests])],,
[enable_debug=yes])
if test "x$enable_debug" != xno
then
AC_DEFINE([FFUZZYPP_DEBUG], [1], [enable testing this implementation])
fi
dnl --disable-position-array
AC_ARG_ENABLE([position-array],
[AS_HELP_STRING([--disable-position-array],[disable using bit-parallel algorithms on examples and tests])],,
[enable_position_array=yes])
if test "x$enable_position_array" = xno
then
AC_DEFINE([FFUZZYPP_DISABLE_POSITION_ARRAY], [1], [disable bit-parallel algorithms])
fi
dnl --enable-examples
AC_ARG_ENABLE([examples],
[AS_HELP_STRING([--enable-examples],[enable building examples (will not be installed)])],,
[enable_examples=no])
AM_CONDITIONAL([ENABLE_EXAMPLES],[test "x$enable_examples" != xno])
dnl --enable-tests
AC_ARG_ENABLE([tests],
[AS_HELP_STRING([--enable-tests],[enable runtime tests])],,
[enable_tests=no])
AM_CONDITIONAL([ENABLE_TESTS],[test "x$enable_tests" != xno])
dnl --disable-compatibility-tests
AC_ARG_ENABLE([compatibility-tests],
[AS_HELP_STRING([--disable-compatibility-tests],[disable compatibility tests])],,
[enable_compatibility_tests=yes])
AM_CONDITIONAL([ENABLE_COMPATIBILITY_TESTS],[test "x$enable_compatibility_tests" != xno])
dnl C++11 compilers and required libraries (when testing)
AC_LANG([C++])
AX_CXX_COMPILE_STDCXX_11
AC_PROG_CXXCPP
if test "x$enable_static_lib" != xno
then
AC_PROG_RANLIB
fi
if test "x$enable_tests" != xno
then
AC_CHECK_HEADER([gtest/gtest.h],,[AC_MSG_ERROR([gtest/gtest.h from Google Test is required to build tests.])])
AC_CHECK_LIB([gtest],[main],[:],[AC_MSG_ERROR([library gtest not found.])])
AC_CHECK_LIB([gtest_main],[main],[:],[AC_MSG_ERROR([library gtest_main not found.])])
fi
AC_OUTPUT([Makefile examples/Makefile tests/Makefile])

4
src/lib/ffuzzypp-release-4.0.1/examples/.gitignore

@ -0,0 +1,4 @@
*
!.gitignore
!Makefile.am
!*.cpp

31
src/lib/ffuzzypp-release-4.0.1/examples/Makefile.am

@ -0,0 +1,31 @@
#
#
# ffuzzy++ : C++ implementation of fast fuzzy hashing
#
# examples/Makefile.am
# Makefile template for examples
#
# Copyright (C) 2014 Tsukasa OI.
#
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all copies.
#
# 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.
#
#
AM_CPPFLAGS = -I$(top_srcdir)
if ENABLE_EXAMPLES
noinst_PROGRAMS = compute-hash compare-hash
compute_hash_SOURCES = compute-hash.cpp
compare_hash_SOURCES = compare-hash.cpp
endif
EXTRA_DIST = .gitignore

130
src/lib/ffuzzypp-release-4.0.1/examples/compare-hash.cpp

@ -0,0 +1,130 @@
/*
ffuzzy++ examples
compare-hash.cpp
Fuzzy hash comparison program
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 <cstdio>
/*
This enables compilation without libffuzzypp.a.
Define this in **one** of the source files to make the linker happy.
*/
#define FFUZZYPP_DECLARATIONS
// the following line will activate assertions.
//#define FFUZZYPP_DEBUG
#include "ffuzzy.hpp"
using namespace ffuzzy;
/*
Both "digest_unorm_t" and "digest_t" are standard layout types and
contains exactly same sequences.
This means you can contain these data in the single union
to save memory. Note that some of operations are still invalid
because "normalized" type requires digest buffer normalized.
*/
typedef union
{
digest_unorm_t u;
digest_t d;
} unified_digest_t;
typedef union
{
digest_long_unorm_t u;
digest_long_t d;
} unified_digest_long_t;
int main(int argc, char** argv)
{
if (argc != 3)
{
fprintf(stderr, "usage: %s HASH1 HASH2\n", argv[0]);
return 1;
}
#if 1
unified_digest_t h1, h2;
#else
unified_digest_long_t h1, h2;
#endif
char digestbuf[decltype(h1.u)::max_natural_chars];
// Parse digests
if (!decltype(h1.u)::parse(h1.u, argv[1]))
{
fprintf(stderr, "error: failed to parse HASH1.\n");
return 1;
}
if (!decltype(h2.u)::parse(h2.u, argv[2]))
{
fprintf(stderr, "error: failed to parse HASH2.\n");
return 1;
}
/*
Restringize digests (just for demo)
Notice that we're using h1.d instead of h1.u?
This is not a good example but works perfectly.
*/
if (!h1.d.pretty_unsafe(digestbuf))
{
fprintf(stderr, "abort: failed to re-stringize HASH1.\n");
return 1;
}
printf("HASH1 : %s\n", digestbuf);
if (!h2.d.pretty_unsafe(digestbuf))
{
fprintf(stderr, "abort: failed to re-stringize HASH2.\n");
return 1;
}
printf("HASH2 : %s\n", digestbuf);
// Normalize digests and restringize them
decltype(h1.d)::normalize(h1.d, h1.u);
decltype(h2.d)::normalize(h2.d, h2.u);
if (!h1.d.pretty_unsafe(digestbuf))
{
fprintf(stderr, "abort: failed to re-stringize HASH1.\n");
return 1;
}
printf("NORM1 : %s\n", digestbuf);
if (!h2.d.pretty_unsafe(digestbuf))
{
fprintf(stderr, "abort: failed to re-stringize HASH2.\n");
return 1;
}
printf("NORM2 : %s\n", digestbuf);
/*
Compare them
"Unnormalized" form has compare function but slow because of additional normalization)
Note:
Use `compare` or `compare<comparison_version::latest>` for latest
version and `compare<comparison_version::v2_9>` for version 2.9 emulation.
*/
digest_comparison_score_t score =
decltype(h1.d)::compare<comparison_version::v2_9>(h1.d, h2.d);
printf("SCORE: %u\n", unsigned(score)); // safe to cast to unsigned (value is in [0,100])
return 0;
}

174
src/lib/ffuzzypp-release-4.0.1/examples/compute-hash.cpp

@ -0,0 +1,174 @@
/*
ffuzzy++ examples
compute-hash.cpp
Fuzzy hash computation program
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 <cstdio>
#include <limits>
/*
This enables compilation without libffuzzypp.a.
Define this in **one** of the source files to make the linker happy.
*/
#define FFUZZYPP_DECLARATIONS
// the following line will activate assertions.
//#define FFUZZYPP_DEBUG
#include "ffuzzy.hpp"
using namespace ffuzzy;
// the following line will enable constant file size optimization.
#define OPTIMIZE_CONSTANT_FILE_SIZE
int main(int argc, char** argv)
{
// digest_generator is reset by default.
digest_generator gen;
// Use "unnormalized" form not to remove
// sequences with 4 or more identical characters.
// You can use "digest_t" and you will get digests without such sequences.
digest_unorm_t d;
// Generated digest is always natural.
// You don't have to give too large sizes.
char digestbuf[digest_unorm_t::max_natural_chars];
// File buffer
static const size_t BUFFER_SIZE = 4096;
unsigned char filebuf[BUFFER_SIZE];
// The buffer which contains the format string.
// Converting to "unsigned" is completely safe for
// ssdeep-compatible configuration
// (I mean, unless you haven't modified many parameters).
static_assert(digest_unorm_t::max_natural_width <= std::numeric_limits<unsigned>::max(),
"digest_unorm_t::max_natural_width must be small enough.");
char digestformatbuf[digest_unorm_t::max_natural_width_digits + 9];
sprintf(digestformatbuf, "%%-%us %%s\n",
static_cast<unsigned>(digest_unorm_t::max_natural_width));
#if 0
fprintf(stderr, "FORMAT STRING: %s\n", digestformatbuf);
#endif
// iterate over all files given
for (int i = 1; i < argc; i++)
{
char* filename = argv[i];
FILE* fp = fopen(filename, "rb");
// error when failed to open file
if (!fp)
{
perror(filename);
return 1;
}
#ifdef OPTIMIZE_CONSTANT_FILE_SIZE
/*
Retrieve file size (but the file is not seekable, do nothing).
Note that using off_t is not safe for 32-bit platform.
Use something much more robust to retrieve file sizes.
*/
bool seekable = false;
off_t filesize;
if (fseek(fp, 0, SEEK_END) == 0)
{
/*
If seekable, set file size constant for
digest generator optimization. The generator will work without it
but using it makes the program significantly faster.
*/
seekable = true;
filesize = ftello(fp);
if (fseek(fp, 0, SEEK_SET) != 0)
{
fprintf(stderr, "%s: could not seek to the beginning.\n", filename);
fclose(fp);
return 1;
}
/*
set_file_size_constant fails if:
* set_file_size_constant is called multiple times (not happens here)
* given file size is too large to optimize
*/
if (!gen.set_file_size_constant(filesize))
{
fprintf(stderr, "%s: cannot optimize performance for this file.\n", filename);
fclose(fp);
return 1;
}
}
else
{
#if 0
fprintf(stderr, "%s: seek operation is not available.\n", filename);
#endif
}
#endif
// update generator by given file stream and buffer
if (!gen.update_by_stream<BUFFER_SIZE>(fp, filebuf))
{
fprintf(stderr, "%s: failed to update fuzzy hashes.\n", filename);
fclose(fp);
return 1;
}
fclose(fp);
/*
copy_digest will fail if:
* The file was too big to process
* The file size did not match with file size constant
(set by set_file_size_constant)
*/
if (!gen.copy_digest(d))
{
if (gen.is_total_size_clamped())
fprintf(stderr, "%s: too big to process.\n", filename);
#ifdef OPTIMIZE_CONSTANT_FILE_SIZE
else if (seekable && (digest_filesize_t(filesize) != gen.total_size()))
fprintf(stderr, "%s: file size changed while reading (or arithmetic overflow?)\n", filename);
#endif
else
fprintf(stderr, "%s: failed to copy digest with unknown error.\n", filename);
return 1;
}
/*
If size of the digest buffer is equal or greater than max_natural_chars,
copying the string digest with pretty_unsafe function is completely safe.
However, this function still may fail due to failure of sprintf.
*/
if (!d.pretty_unsafe(digestbuf))
{
fprintf(stderr, "%s: failed to stringize the digest.\n", filename);
return 1;
}
printf(digestformatbuf, digestbuf, filename);
// reset the generator if we haven't reached the end
if (i + 1 != argc)
gen.reset();
}
return 0;
}

2
src/lib/ffuzzypp-release-4.0.1/ext/.gitignore

@ -0,0 +1,2 @@
*
!/.gitignore

76
src/lib/ffuzzypp-release-4.0.1/ffuzzy.hpp

@ -0,0 +1,76 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hasing
ffuzzy.hpp
Fuzzy hashing implementation
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_ROOT_FFUZZY_HPP
#define FFUZZYPP_ROOT_FFUZZY_HPP
#include "ffuzzypp/utils/likely.hpp"
#include "ffuzzypp/utils/minmax.hpp"
#include "ffuzzypp/utils/safe_int.hpp"
#include "ffuzzypp/utils/static_assert_query.hpp"
#include "ffuzzypp/utils/numeric_digits.hpp"
#include "ffuzzypp/utils/type_modifier.hpp"
#include "ffuzzypp/utils/ranges.hpp"
#include "ffuzzypp/base64.hpp"
#include "ffuzzypp/context_hash.hpp"
#include "ffuzzypp/context_hash_fast.hpp"
#include "ffuzzypp/rolling_hash.hpp"
#include "ffuzzypp/rolling_hash_ssdeep.hpp"
#include "ffuzzypp/strings/position_array.hpp"
#include "ffuzzypp/strings/common_substr.hpp"
#include "ffuzzypp/strings/edit_dist.hpp"
#include "ffuzzypp/strings/terminators.hpp"
#include "ffuzzypp/strings/transform.hpp"
#include "ffuzzypp/strings/sequences.hpp"
#include "ffuzzypp/strings/nosequences.hpp"
#include "ffuzzypp/digest_blocksize.hpp"
#include "ffuzzypp/digest_data.hpp"
#include "ffuzzypp/digest_position_array_base.hpp"
#include "ffuzzypp/digest_comparison.hpp"
#include "ffuzzypp/digest_base.hpp"
#include "ffuzzypp/digest_position_array.hpp"
#include "ffuzzypp/digest.hpp"
#include "ffuzzypp/digest_filesize.hpp"
#include "ffuzzypp/digest_generator.hpp"
#ifdef FFUZZYPP_COMPATIBILITY_SSDEEP_2_9
#error Configuration by FFUZZYPP_COMPATIBILITY_SSDEEP_2_9 is now removed. Read README for alternative method.
#endif
#ifdef FFUZZYPP_COMPATIBILITY_SSDEEP
static_assert(ffuzzy::digest_params::max_blockhash_len == 64,
"Given parameter (digest_params::max_blockhash_len) is not compatible with ssdeep.");
static_assert(ffuzzy::digest_params::max_blockhash_sequence == 3,
"Given parameter (digest_params::max_blockhash_sequence) is not compatible with ssdeep.");
static_assert(ffuzzy::blockhash_comparison_params::min_match_len == 7,
"Given parameter (blockhash_comparison_params::min_match_len) is not compatible with ssdeep.");
static_assert(ffuzzy::rolling_hash::window_size == 7,
"Given parameter (rolling_hash::window_size) is not compatible with ssdeep.");
static_assert(ffuzzy::digest_blocksize::number_of_blockhashes == 31,
"Given parameter (digest_blocksize::number_of_blockhashes) is not compatible with ssdeep.");
static_assert(ffuzzy::digest_blocksize::min_blocksize == 3,
"Given parameter (digest_blocksize::min_blocksize) is not compatible with ssdeep.");
static_assert(ffuzzy::digest_filesize::min_supported_size == 4097,
"Given parameter (digest_filesize::min_supported_size) is not compatible with ssdeep.");
#endif
#endif

36
src/lib/ffuzzypp-release-4.0.1/ffuzzy_declarations.cpp

@ -0,0 +1,36 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hasing
ffuzzy_declarations.cpp
Your linker's friend
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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.
*/
#define FFUZZYPP_DECLARATIONS
#include "ffuzzy.hpp"
extern "C" {
const char* ffuzzy_declarations_version(void)
{
#ifdef PACKAGE_VERSION
return PACKAGE_VERSION;
#else
return "unknown";
#endif
}
}

196
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/base64.hpp

@ -0,0 +1,196 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
base64.hpp
Base64 utilities
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_BASE64_HPP
#define FFUZZYPP_BASE64_HPP
namespace ffuzzy {
class base64
{
private:
base64(void) = delete;
base64(const base64&) = delete;
// Base64 table
public:
static constexpr const char invalid_index = 64;
static constexpr const char values[64] =
{
// This should be the same order of ordinal Base64
// (as well as b64 variable in fuzzy.c)
'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U',
'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u',
'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4',
'5', '6', '7', '8', '9',
'+', '/'
};
static_assert(
sizeof(values) == 64 &&
values[ 0] == 'A' &&
values[26] == 'a' &&
values[52] == '0' &&
values[62] == '+' &&
values[63] == '/',
"minimum sanity check for Base64 failed.");
static_assert(
invalid_index < 0 || invalid_index >= 64,
"invalid_index is not out of range.");
public:
// Utility to check whether given character is in Base64 charset
static bool isbase64(char c) noexcept
{
switch (c)
{
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '+': case '/':
return true;
default:
return false;
}
}
// Utility to convert character to Base64 index
static char toindex(char c) noexcept
{
switch (c)
{
case 'A': return 0;
case 'B': return 1;
case 'C': return 2;
case 'D': return 3;
case 'E': return 4;
case 'F': return 5;
case 'G': return 6;
case 'H': return 7;
case 'I': return 8;
case 'J': return 9;
case 'K': return 10;
case 'L': return 11;
case 'M': return 12;
case 'N': return 13;
case 'O': return 14;
case 'P': return 15;
case 'Q': return 16;
case 'R': return 17;
case 'S': return 18;
case 'T': return 19;
case 'U': return 20;
case 'V': return 21;
case 'W': return 22;
case 'X': return 23;
case 'Y': return 24;
case 'Z': return 25;
case 'a': return 26;
case 'b': return 27;
case 'c': return 28;
case 'd': return 29;
case 'e': return 30;
case 'f': return 31;
case 'g': return 32;
case 'h': return 33;
case 'i': return 34;
case 'j': return 35;
case 'k': return 36;
case 'l': return 37;
case 'm': return 38;
case 'n': return 39;
case 'o': return 40;
case 'p': return 41;
case 'q': return 42;
case 'r': return 43;
case 's': return 44;
case 't': return 45;
case 'u': return 46;
case 'v': return 47;
case 'w': return 48;
case 'x': return 49;
case 'y': return 50;
case 'z': return 51;
case '0': return 52;
case '1': return 53;
case '2': return 54;
case '3': return 55;
case '4': return 56;
case '5': return 57;
case '6': return 58;
case '7': return 59;
case '8': return 60;
case '9': return 61;
case '+': return 62;
case '/': return 63;
default: return invalid_index;
}
}
// Base64 transformation (from index to actual character)
public:
class transform_to_b64
{
private:
transform_to_b64(void) = delete;
transform_to_b64(const transform_to_b64&) = delete;
public:
static constexpr char transform(char ch) noexcept
{
return base64::values[static_cast<unsigned char>(ch)];
}
};
// Base64 reverse-transformation (from Base64 character to index)
public:
class transform_from_b64
{
private:
transform_from_b64(void) = delete;
transform_from_b64(const transform_from_b64&) = delete;
public:
static char transform(char ch) noexcept
{
return toindex(ch);
}
};
};
#ifdef FFUZZYPP_DECLARATIONS
constexpr const char base64::values[64];
#endif
}
#endif

83
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/context_hash.hpp

@ -0,0 +1,83 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
context_hash.hpp
Context computation (non-rolling) hash implementation
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_CONTEXT_HASH_HPP
#define FFUZZYPP_CONTEXT_HASH_HPP
#include <cstdint>
namespace ffuzzy {
class context_hash
{
private:
// Don't use UINT32_C not to define __STDC_CONSTANT_MACROS in ffuzzy++
static constexpr const uint_least32_t hash_init = uint_least32_t(0x28021967ul);
static constexpr const uint_least32_t hash_prime = uint_least32_t(0x01000193ul);
private:
uint_least32_t h;
public:
static constexpr uint_least32_t initial_state(void) noexcept
{
return hash_init;
}
void reset(void) noexcept
{
h = initial_state();
}
static constexpr uint_least32_t next_state(uint_least32_t h, unsigned char c) noexcept
{
return ((h * hash_prime) ^ uint_least32_t(c)) & uint_least32_t(0xfffffffful);
}
void update(unsigned char c) noexcept
{
h = next_state(h, c);
}
uint_least32_t sum(void) const noexcept
{
return h;
}
public:
char sum_in_base64(void) const noexcept
{
// sum for Base64 (returns Base64 index)
return static_cast<char>(h & 0x3f);
}
public:
context_hash(void) noexcept = default; // initialize to undefined state
};
}
#endif

480
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/context_hash_fast.hpp

@ -0,0 +1,480 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
context_hash_fast.hpp
Fast implementation of context_hash (only lowest 6-bits)
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_CONTEXT_HASH_FAST_HPP
#define FFUZZYPP_CONTEXT_HASH_FAST_HPP
#include <cstdint>
#include "context_hash.hpp"
#include "utils/static_assert_query.hpp"
namespace ffuzzy {
class context_hash_fast
{
private:
static constexpr const char hash_init = static_cast<char>(context_hash::initial_state() & 0x3f);
static constexpr const char table_translate[64][64] =
{
{ // 0x00
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
},
{ // 0x01
0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c,
0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c,
0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c,
},
{ // 0x02
0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29,
0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39,
0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09,
0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19,
},
{ // 0x03
0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36,
0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26,
0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16,
0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06,
},
{ // 0x04
0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03,
0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13,
0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33,
},
{ // 0x05
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
},
{ // 0x06
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
},
{ // 0x07
0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a,
0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a,
0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a,
},
{ // 0x08
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
},
{ // 0x09
0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24,
0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34,
0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04,
0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14,
},
{ // 0x0a
0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21,
0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11,
0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01,
},
{ // 0x0b
0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e,
0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e,
0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e,
},
{ // 0x0c
0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b,
0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b,
0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b,
0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b,
},
{ // 0x0d
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
},
{ // 0x0e
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
},
{ // 0x0f
0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12,
0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02,
0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32,
0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22,
},
{ // 0x10
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
},
{ // 0x11
0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c,
0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c,
0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c,
},
{ // 0x12
0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19,
0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09,
0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39,
0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29,
},
{ // 0x13
0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26,
0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36,
0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06,
0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16,
},
{ // 0x14
0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33,
0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13,
0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03,
},
{ // 0x15
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
},
{ // 0x16
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
},
{ // 0x17
0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a,
0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a,
0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a,
},
{ // 0x18
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
},
{ // 0x19
0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14,
0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04,
0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34,
0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24,
},
{ // 0x1a
0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21,
0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01,
0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11,
},
{ // 0x1b
0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e,
0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e,
0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e,
},
{ // 0x1c
0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b,
0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b,
0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b,
0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b,
},
{ // 0x1d
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
},
{ // 0x1e
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
},
{ // 0x1f
0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02,
0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12,
0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22,
0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32,
},
{ // 0x20
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
},
{ // 0x21
0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c,
0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c,
0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c,
},
{ // 0x22
0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09,
0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19,
0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29,
0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39,
},
{ // 0x23
0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16,
0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06,
0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36,
0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26,
},
{ // 0x24
0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33,
0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03,
0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13,
},
{ // 0x25
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
},
{ // 0x26
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
},
{ // 0x27
0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a,
0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a,
0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a,
},
{ // 0x28
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
},
{ // 0x29
0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04,
0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14,
0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24,
0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34,
},
{ // 0x2a
0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11,
0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01,
0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21,
},
{ // 0x2b
0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e,
0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e,
0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e,
0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
},
{ // 0x2c
0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b,
0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b,
0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b,
0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b,
},
{ // 0x2d
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
},
{ // 0x2e
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
},
{ // 0x2f
0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32,
0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22,
0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12,
0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02,
},
{ // 0x30
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
},
{ // 0x31
0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c,
0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c,
0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c,
0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
},
{ // 0x32
0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39,
0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29,
0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19,
0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09,
},
{ // 0x33
0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06,
0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16,
0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26,
0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36,
},
{ // 0x34
0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13,
0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03,
0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33,
0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
},
{ // 0x35
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
},
{ // 0x36
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
},
{ // 0x37
0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a,
0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a,
0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a,
0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
},
{ // 0x38
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
},
{ // 0x39
0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34,
0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24,
0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14,
0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04,
},
{ // 0x3a
0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01,
0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11,
0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21,
0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
},
{ // 0x3b
0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e,
0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e,
0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e,
},
{ // 0x3c
0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b,
0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b,
0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b,
0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b,
},
{ // 0x3d
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
},
{ // 0x3e
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
},
{ // 0x3f
0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22,
0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32,
0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02,
0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12,
},
};
#ifdef FFUZZYPP_STATIC_SANITY_CHECKS
template <uintmax_t i>
struct translate_check
{
template <uintmax_t j>
struct translate_check_2
{
static constexpr const bool value =
table_translate[i][j] == (context_hash::next_state(i, j) & 0x3f);
};
static constexpr const bool value =
static_assert_query::is_all<translate_check_2, 64>::value;
};
static_assert(static_assert_query::is_all<translate_check, 64>::value,
"table_translate is not equivalent to actual context_hash translation.");
#endif
private:
char h;
public:
void reset(void) noexcept
{
h = hash_init;
}
void update(unsigned char c) noexcept
{
h = table_translate[static_cast<unsigned char>(h)][c & 0x3f];
}
char sum_in_base64(void) const noexcept
{
// sum for Base64 (returns Base64 index)
return h;
}
public:
context_hash_fast(void) noexcept = default; // initialize to undefined state
};
#ifdef FFUZZYPP_DECLARATIONS
constexpr const char context_hash_fast::table_translate[64][64];
#endif
}
#endif

495
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest.hpp

@ -0,0 +1,495 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest.hpp
Fuzzy digest (wrapper with converters)
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_DIGEST_HPP
#define FFUZZYPP_DIGEST_HPP
#include <algorithm>
#include <functional>
#include <string>
#include <type_traits>
#include "digest_data.hpp"
#include "digest_base.hpp"
#include "utils/type_modifier.hpp"
namespace ffuzzy {
// Wrapper class
template <bool IsAlphabetRestricted, bool IsShort, bool IsNormalized> class digest;
// Digest (alphabet restricted; short; normalized)
template <>
class digest<true, true, true>
: public digest_base<true, true, true>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<true, true, true>(other) {}
explicit digest(const char* str) noexcept(false) : digest_base<true, true, true>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<true, true, true>::operator=(other);
return *this;
}
};
// Digest (alphabet restricted; short; unnormalized)
template <>
class digest<true, true, false>
: public digest_base<true, true, false>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<true, true, false>(other) {}
digest(const digest<true, true, true>& other) noexcept
{
digest_data<true, true>::operator=(other);
}
explicit digest(const char* str) noexcept(false) : digest_base<true, true, false>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<true, true, false>::operator=(other);
return *this;
}
const digest& operator=(const digest<true, true, true>& other) noexcept
{
digest_data<true, true>::operator=(other);
return *this;
}
};
// Digest (alphabet restricted; long; normalized)
template <>
class digest<true, false, true>
: public digest_base<true, false, true>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<true, false, true>(other) {}
digest(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
}
explicit digest(const char* str) noexcept(false) : digest_base<true, false, true>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<true, false, true>::operator=(other);
return *this;
}
const digest& operator=(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
return *this;
}
};
// Digest (alphabet restricted; long; unnormalized)
template <>
class digest<true, false, false>
: public digest_base<true, false, false>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<true, false, false>(other) {}
digest(const digest<true, false, true>& other) noexcept
{
digest_data<true, false>::operator=(other);
}
digest(const digest<true, true, false>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
}
digest(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
}
explicit digest(const char* str) noexcept(false) : digest_base<true, false, false>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<true, false, false>::operator=(other);
return *this;
}
const digest& operator=(const digest<true, false, true>& other) noexcept
{
digest_data<true, false>::operator=(other);
return *this;
}
const digest& operator=(const digest<true, true, false>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
return *this;
}
const digest& operator=(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
return *this;
}
};
// Digest (alphabet not restricted; short; normalized)
template <>
class digest<false, true, true>
: public digest_base<false, true, true>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<false, true, true>(other) {}
digest(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
}
explicit digest(const char* str) noexcept(false) : digest_base<false, true, true>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<false, true, true>::operator=(other);
return *this;
}
const digest& operator=(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
return *this;
}
};
// Digest (alphabet not restricted; short; unnormalized)
template <>
class digest<false, true, false>
: public digest_base<false, true, false>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<false, true, false>(other) {}
digest(const digest<false, true, true>& other) noexcept
{
digest_data<false, true>::operator=(other);
}
digest(const digest<true, true, false>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
}
digest(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
}
explicit digest(const char* str) noexcept(false) : digest_base<false, true, false>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<false, true, false>::operator=(other);
return *this;
}
const digest& operator=(const digest<false, true, true>& other) noexcept
{
digest_data<false, true>::operator=(other);
return *this;
}
const digest& operator=(const digest<true, true, false>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
return *this;
}
const digest& operator=(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
return *this;
}
};
// Digest (alphabet not restricted; long; normalized)
template <>
class digest<false, false, true>
: public digest_base<false, false, true>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<false, false, true>(other) {}
digest(const digest<false, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
}
digest(const digest<true, false, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
}
digest(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long_non_ra(*this, other);
}
explicit digest(const char* str) noexcept(false) : digest_base<false, false, true>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<false, false, true>::operator=(other);
return *this;
}
const digest& operator=(const digest<false, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
return *this;
}
const digest& operator=(const digest<true, false, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
return *this;
}
const digest& operator=(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long_non_ra(*this, other);
return *this;
}
};
// Digest (alphabet not restricted; long; unnormalized)
template <>
class digest<false, false, false>
: public digest_base<false, false, false>
{
public:
digest(void) noexcept = default; // initialize to undefined state
digest(const digest& other) noexcept : digest_base<false, false, false>(other) {}
digest(const digest<false, false, true>& other) noexcept
{
digest_data<false, false>::operator=(other);
}
digest(const digest<false, true, false>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
}
digest(const digest<false, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
}
digest(const digest<true, false, false>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
}
digest(const digest<true, false, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
}
digest(const digest<true, true, false>& other) noexcept
{
internal::digest_copy::copy_to_long_non_ra(*this, other);
}
digest(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long_non_ra(*this, other);
}
explicit digest(const char* str) noexcept(false) : digest_base<false, false, false>(str) {}
explicit digest(const std::string& str) : digest(str.c_str()) {}
const digest& operator=(const digest& other) noexcept
{
digest_base<false, false, false>::operator=(other);
return *this;
}
const digest& operator=(const digest<false, false, true>& other) noexcept
{
digest_data<false, false>::operator=(other);
return *this;
}
const digest& operator=(const digest<false, true, false>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
return *this;
}
const digest& operator=(const digest<false, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long(*this, other);
return *this;
}
const digest& operator=(const digest<true, false, false>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
return *this;
}
const digest& operator=(const digest<true, false, true>& other) noexcept
{
internal::digest_copy::copy_to_non_ra(*this, other);
return *this;
}
const digest& operator=(const digest<true, true, false>& other) noexcept
{
internal::digest_copy::copy_to_long_non_ra(*this, other);
return *this;
}
const digest& operator=(const digest<true, true, true>& other) noexcept
{
internal::digest_copy::copy_to_long_non_ra(*this, other);
return *this;
}
};
// Typedefs for digest specializations
typedef digest<false, true, true> digest_t;
typedef digest<false, true, false> digest_unorm_t;
typedef digest<false, false, true> digest_long_t;
typedef digest<false, false, false> digest_long_unorm_t;
typedef digest< true, true, true> digest_ra_t;
typedef digest< true, true, false> digest_ra_unorm_t;
typedef digest< true, false, true> digest_ra_long_t;
typedef digest< true, false, false> digest_ra_long_unorm_t;
/*
Type modifiers
*/
namespace internal
{
template <typename T>
struct digest_traits
{
static constexpr const bool is_valid = false;
};
template <bool IsAlphabetRestricted, bool IsShort, bool IsNormalized>
struct digest_traits<digest_base<IsAlphabetRestricted, IsShort, IsNormalized>>
{
static constexpr const bool is_valid = true;
typedef digest_base<IsAlphabetRestricted, IsShort, true> norm_type;
typedef digest_base<IsAlphabetRestricted, IsShort, false> unorm_type;
typedef digest_base<IsAlphabetRestricted, true, IsNormalized> short_type;
typedef digest_base<IsAlphabetRestricted, false, IsNormalized> long_type;
typedef digest_base< true, IsShort, IsNormalized> ra_type;
typedef digest_base<false, IsShort, IsNormalized> non_ra_type;
};
template <bool IsAlphabetRestricted, bool IsShort, bool IsNormalized>
struct digest_traits<digest<IsAlphabetRestricted, IsShort, IsNormalized>>
{
static constexpr const bool is_valid = true;
typedef digest<IsAlphabetRestricted, IsShort, true> norm_type;
typedef digest<IsAlphabetRestricted, IsShort, false> unorm_type;
typedef digest<IsAlphabetRestricted, true, IsNormalized> short_type;
typedef digest<IsAlphabetRestricted, false, IsNormalized> long_type;
typedef digest< true, IsShort, IsNormalized> ra_type;
typedef digest<false, IsShort, IsNormalized> non_ra_type;
};
template <typename T>
struct digest_alt_type_selector
{
private:
typedef digest_traits<typename std::remove_cv<T>::type> traits_type;
static_assert(traits_type::is_valid, "You must give correct type to retrieve alternative types.");
public:
typedef typename type_mod::cv_match<T, typename traits_type::norm_type>::type norm_type;
typedef typename type_mod::cv_match<T, typename traits_type::unorm_type>::type unorm_type;
typedef typename type_mod::cv_match<T, typename traits_type::short_type>::type short_type;
typedef typename type_mod::cv_match<T, typename traits_type::long_type>::type long_type;
typedef typename type_mod::cv_match<T, typename traits_type::ra_type>::type ra_type;
typedef typename type_mod::cv_match<T, typename traits_type::non_ra_type>::type non_ra_type;
};
}
template <typename T> using digest_to_unorm = typename internal::digest_alt_type_selector<T>::unorm_type;
template <typename T> using digest_to_norm = typename internal::digest_alt_type_selector<T>::norm_type;
template <typename T> using digest_to_short = typename internal::digest_alt_type_selector<T>::short_type;
template <typename T> using digest_to_long = typename internal::digest_alt_type_selector<T>::long_type;
template <typename T> using digest_to_ra = typename internal::digest_alt_type_selector<T>::ra_type;
template <typename T> using digest_to_non_ra = typename internal::digest_alt_type_selector<T>::non_ra_type;
/*
We expect following properties for each digest types:
* is a trivially default constructible type
* is a standard-layout type
Digest types are:
* digest_data<IsAlphabetRestricted, IsShort>
* digest<IsAlphabetRestricted, IsShort, true>
* digest<IsAlphabetRestricted, IsShort, false>
We also expect that these types are nearly equivalent.
*/
#ifdef FFUZZYPP_LOCAL_CHK
#error do not define FFUZZYPP_LOCAL_CHK
#endif
#ifdef FFUZZYPP_LOCAL_CHK1
#error do not define FFUZZYPP_LOCAL_CHK1
#endif
#define FFUZZYPP_LOCAL_CHK1(IsAlphabetRestricted, IsShort, IsNormalized) \
static_assert(std::is_trivially_default_constructible<digest<IsAlphabetRestricted, IsShort, IsNormalized>>::value, \
"digest<" #IsAlphabetRestricted ", " #IsShort ", " #IsNormalized "> must be a trivially default constructible type."); \
static_assert(std::is_standard_layout<digest<IsAlphabetRestricted, IsShort, IsNormalized>>::value, \
"digest<" #IsAlphabetRestricted ", " #IsShort ", " #IsNormalized "> must be a standard-layout type."); \
static_assert(std::is_base_of<digest_data<IsAlphabetRestricted, IsShort>, digest<IsAlphabetRestricted, IsShort, IsNormalized>>::value, \
"digest_data<" #IsAlphabetRestricted ", " #IsShort ">, digest<" #IsAlphabetRestricted ", " #IsShort ", true> and " \
"digest<" #IsAlphabetRestricted ", " #IsShort ", false> must be nearly equivalent."); \
static_assert(sizeof(digest_data<IsAlphabetRestricted, IsShort>) == sizeof(digest<IsAlphabetRestricted, IsShort, IsNormalized>), \
"digest_data<" #IsAlphabetRestricted ", " #IsShort ">, digest<" #IsAlphabetRestricted ", " #IsShort ", true> and " \
"digest<" #IsAlphabetRestricted ", " #IsShort ", false> must be nearly equivalent.")
#define FFUZZYPP_LOCAL_CHK(IsAlphabetRestricted, IsShort) \
static_assert(std::is_trivially_default_constructible<digest_data<IsAlphabetRestricted, IsShort>>::value, \
"digest_data<" #IsAlphabetRestricted ", " #IsShort "> must be a trivially default constructible type."); \
static_assert(std::is_standard_layout<digest_data<IsAlphabetRestricted, IsShort>>::value, \
"digest_data<" #IsAlphabetRestricted ", " #IsShort "> must be a standard-layout type."); \
FFUZZYPP_LOCAL_CHK1(IsAlphabetRestricted, IsShort, true); \
FFUZZYPP_LOCAL_CHK1(IsAlphabetRestricted, IsShort, false)
FFUZZYPP_LOCAL_CHK(true, true);
FFUZZYPP_LOCAL_CHK(true, false);
FFUZZYPP_LOCAL_CHK(false, true);
FFUZZYPP_LOCAL_CHK(false, false);
#undef FFUZZYPP_LOCAL_CHK
#undef FFUZZYPP_LOCAL_CHK1
}
// Specialization of standard hash and swap
namespace std
{
template <bool IsAlphabetRestricted, bool IsShort, bool IsNormalized>
struct hash<ffuzzy::digest<IsAlphabetRestricted, IsShort, IsNormalized>>
{
size_t operator()(const ffuzzy::digest<IsAlphabetRestricted, IsShort, IsNormalized>& value) const
{
return value.hash();
}
};
template <bool IsAlphabetRestricted, bool IsShort, bool IsNormalized>
inline void swap(
ffuzzy::digest<IsAlphabetRestricted, IsShort, IsNormalized>& a,
ffuzzy::digest<IsAlphabetRestricted, IsShort, IsNormalized>& b
) noexcept
{
ffuzzy::digest<IsAlphabetRestricted, IsShort, IsNormalized>::swap(a, b);
}
}
#endif

254
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_base.hpp

@ -0,0 +1,254 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest_base.hpp
Fuzzy digest (wrapper with comparison methods)
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_DIGEST_BASE_HPP
#define FFUZZYPP_DIGEST_BASE_HPP
#include <string>
#include "digest_blocksize.hpp"
#include "digest_data.hpp"
#include "digest_comparison.hpp"
#include "utils/type_modifier.hpp"
namespace ffuzzy {
template <bool IsAlphabetRestricted, bool IsShort, bool IsNormalized> class digest_base;
// Normalized form of digest (with specialized/fast comparison)
template <bool IsAlphabetRestricted, bool IsShort>
class digest_base<IsAlphabetRestricted, IsShort, true>
: public digest_data<IsAlphabetRestricted, IsShort>
{
public:
digest_base(void) noexcept = default; // initialize to undefined state
digest_base(const digest_base& other) noexcept : digest_data<IsAlphabetRestricted, IsShort>(other) {}
const digest_base& operator=(const digest_base& other) noexcept
{
digest_data<IsAlphabetRestricted, IsShort>::operator=(other);
return *this;
}
public:
explicit digest_base(const char* str) noexcept(false)
{
if (!digest_data<IsAlphabetRestricted, IsShort>::parse_normalized(*this, str))
throw digest_parse_error();
}
explicit digest_base(const std::string& str)
: digest_base(str.c_str()) {}
static bool parse_normalized(digest_base& digest, const char* str) noexcept
{
return digest_data<IsAlphabetRestricted, IsShort>::parse_normalized(digest, str);
}
static bool parse(digest_base& digest, const char* str) noexcept
{
return digest_data<IsAlphabetRestricted, IsShort>::parse_normalized(digest, str);
}
public:
bool is_valid(void) const noexcept
{
return digest_data<IsAlphabetRestricted, IsShort>::is_valid() && this->template is_normalized();
}
// Comparison
public:
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_identical(
const digest_base& value
) noexcept
{
return digest_comparison<Version>::compare_identical(value);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare_near(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_lt(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare_near_lt(a, b);
}
public:
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare(const digest_base& other) const noexcept
{
return compare<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_identical(void) const noexcept
{
return compare_identical<Version>(*this);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near(const digest_base& other) const noexcept
{
return compare_near<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_eq(const digest_base& other) const noexcept
{
return compare_near_eq<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_lt(const digest_base& other) const noexcept
{
return compare_near_lt<Version>(*this, other);
}
// Comparison (on different digests)
public:
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_diff(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_diff(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare_near_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq_diff(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq_diff(a, b);
}
public:
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_diff(const digest_base& other) const noexcept
{
return compare_diff<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_diff(const digest_base& other) const noexcept
{
return compare_near_diff<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_eq_diff(const digest_base& other) const noexcept
{
return compare_near_eq_diff<Version>(*this, other);
}
};
// Unnormalized form of digest (with normalization ability and slow comparison)
template <bool IsAlphabetRestricted, bool IsShort>
class digest_base<IsAlphabetRestricted, IsShort, false>
: public digest_data<IsAlphabetRestricted, IsShort>
{
public:
digest_base(void) noexcept = default; // initialize to undefined state
digest_base(const digest_base& other) noexcept : digest_data<IsAlphabetRestricted, IsShort>(other) {}
digest_base(const digest_base<IsAlphabetRestricted, IsShort, true>& other) noexcept : digest_data<IsAlphabetRestricted, IsShort>(other) {}
const digest_base& operator=(const digest_base& other) noexcept
{
digest_data<IsAlphabetRestricted, IsShort>::operator=(other);
return *this;
}
const digest_base& operator=(const digest_base<IsAlphabetRestricted, IsShort, true>& other) noexcept
{
digest_data<IsAlphabetRestricted, IsShort>::operator=(other);
return *this;
}
public:
explicit digest_base(const char* str) noexcept(false)
{
if (!digest_data<IsAlphabetRestricted, IsShort>::parse(*this, str))
throw digest_parse_error();
}
explicit digest_base(const std::string& str)
: digest_base(str.c_str()) {}
static bool parse_normalized(digest_base& digest, const char* str) noexcept
{
return digest_data<IsAlphabetRestricted, IsShort>::parse_normalized(digest, str);
}
static bool parse(digest_base& digest, const char* str) noexcept
{
return digest_data<IsAlphabetRestricted, IsShort>::parse(digest, str);
}
public:
digest_base<IsAlphabetRestricted, IsShort, true> to_normalized(void) const noexcept
{
return digest_data<IsAlphabetRestricted, IsShort>::
template normalize<digest_base<IsAlphabetRestricted, IsShort, true>>(*this);
}
explicit operator digest_base<IsAlphabetRestricted, IsShort, true>(void) const noexcept { return to_normalized(); }
public:
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare(
const digest_base& a,
const digest_base& b
) noexcept
{
return digest_comparison<Version>::compare_unnormalized(a, b);
}
public:
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare(const digest_base& other) const noexcept { return compare<Version>(*this, other); }
};
}
#endif

255
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_blocksize.hpp

@ -0,0 +1,255 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest_blocksize.hpp
Fuzzy digest block size utilities
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_DIGEST_BLOCKSIZE_HPP
#define FFUZZYPP_DIGEST_BLOCKSIZE_HPP
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <limits>
#include "utils/safe_int.hpp"
#include "utils/static_assert_query.hpp"
#include "utils/numeric_digits.hpp"
namespace ffuzzy {
// Block size type for fuzzy digest
typedef uint_least32_t digest_blocksize_t;
// Block size utilities
class digest_blocksize
{
static_assert(
safe_int::contracts::is_unsigned_integral_type<digest_blocksize_t>() &&
std::numeric_limits<digest_blocksize_t>::max() >= 0xfffffffful,
"digest_blocksize_t must be an unsigned integral type which can represent all 32-bit values."
);
private:
digest_blocksize(void) = delete;
digest_blocksize(const digest_blocksize&) = delete;
// Parameters
public:
static constexpr const unsigned number_of_blockhashes = 31;
static constexpr const digest_blocksize_t min_blocksize = 3;
static constexpr const digest_blocksize_t max_blocksize = min_blocksize << (number_of_blockhashes - 1);
static_assert(min_blocksize != 0, "min_blocksize must not be zero.");
static_assert(number_of_blockhashes != 0, "number_of_blockhashes must not be zero.");
static_assert(number_of_blockhashes <= 32, "number_of_blockhashes must be less than 32.");
static_assert(min_blocksize <= 0xfffffffful, "min_blocksize must be less than 2^32.");
static_assert(
safe_int::safe_lshift<
safe_int::uvalue<digest_blocksize_t, min_blocksize>,
safe_int::uvalue<unsigned, number_of_blockhashes - 1>
>::is_valid &&
(min_blocksize << (number_of_blockhashes - 1)) <= 0xfffffffful,
"(min_blocksize << (number_of_blockhashes - 1)) must be less than 2^32.");
// Maximum characters required to represent all "natural" block sizes
// (excluding '\0' character at the end)
public:
static constexpr const size_t max_natural_digits =
numeric_digits::in_decimal(max_blocksize);
// Block size naturality
// (whether this is possibly generated by ssdeep)
public:
static bool is_natural(digest_blocksize_t blocksize) noexcept
{
if (blocksize < min_blocksize)
return false;
if (blocksize > max_blocksize)
return false;
while (blocksize != min_blocksize)
{
if (blocksize % 2 != 0)
return false;
blocksize /= 2;
}
return true;
}
// Utility to prevent arithmetic overflow
public:
static constexpr bool is_safe_to_double(digest_blocksize_t value) noexcept
{
return value <= (std::numeric_limits<digest_blocksize_t>::max() / 2);
}
/*
"Near" relations
fuzzy digests are compared against other if their block sizes are "near".
There are three such cases (if there is no arithmetic overflow).
Case 1: a == b (eq)
Digest A : 3:xxxxxxx:yyyyyyy
Digest A : 3:xxxxxxx:yyyyyyy
| ~~~~~~~ ~~~~~~~
| (both block hashes are compared and the maximum score is chosen)
Case 2: a * 2 == b (implies a < b; lt)
Digest A : 3:xxxxxxx:yyyyyyy
Digest B : 6: yyyyyyy:zzzzzzz
| ~~~~~~~
| (block hash in common block size is compared)
Case 3: a == b * 2 (implies a > b; gt)
Digest A : 6: yyyyyyy:zzzzzzz
Digest B : 3:xxxxxxx:yyyyyyy
| ~~~~~~~
| (block hash in common block size is compared)
*/
public:
static constexpr bool is_near_eq(digest_blocksize_t a, digest_blocksize_t b) noexcept
{
return a == b;
}
static constexpr bool is_near_lt(digest_blocksize_t a, digest_blocksize_t b) noexcept
{
return a != b && is_safe_to_double(a) && a * 2 == b;
}
static constexpr bool is_near_gt(digest_blocksize_t a, digest_blocksize_t b) noexcept
{
return a != b && a % 2 == 0 && a / 2 == b;
}
static constexpr bool is_near_leq(digest_blocksize_t a, digest_blocksize_t b) noexcept
{
return is_near_eq(a, b) || is_near_lt(a, b);
}
static constexpr bool is_near(digest_blocksize_t a, digest_blocksize_t b) noexcept
{
return is_near_eq(a, b) || is_near_lt(a, b) || is_near_gt(a, b);
}
// Utility to convert block size index to a natural block size
public:
static constexpr digest_blocksize_t at(unsigned index) noexcept
{
return min_blocksize << index;
}
// Utility to convert natural block size to corresponding block size index
private:
template <bool UseMagic, typename Tdummy = void> class natural_to_index_impl;
// Implementation by magic table
// (not general [depends on ssdeep parameters] but possibly fast)
static constexpr const digest_blocksize_t nti_magic_mul = digest_blocksize_t(0x017713caul);
static constexpr const unsigned nti_magic_table[31] =
{
0x00, 0x01, 0x02, 0x06, 0x03, 0x0b, 0x07, 0x10,
0x04, 0x0e, 0x0c, 0x18, 0x08, 0x15, 0x11, 0x1a,
0x1e, 0x05, 0x0a, 0x0f, 0x0d, 0x17, 0x14, 0x19,
0x1d, 0x09, 0x16, 0x13, 0x1c, 0x12, 0x1b,
};
template <typename Tdummy>
class natural_to_index_impl<true, Tdummy>
{
public:
static constexpr unsigned natural_to_index_unsafe(digest_blocksize_t blocksize) noexcept
{
return nti_magic_table[((blocksize * nti_magic_mul) >> 27) & 0x1f];
}
private:
#ifdef FFUZZYPP_STATIC_SANITY_CHECKS
template <uintmax_t i>
struct seq_check
{
static constexpr const bool value =
natural_to_index_unsafe(min_blocksize << i) == i;
};
static_assert(static_assert_query::is_all<seq_check, number_of_blockhashes>::value,
"magic table is not constructed correctly.");
#endif
};
// Implementation by De Brujin sequence
// (general but requires a division to make index_from work)
static constexpr const digest_blocksize_t nti_debrujin_mul = digest_blocksize_t(0x077cb531ul);
static constexpr const unsigned nti_debrujin_table[32] =
{
0x00, 0x01, 0x1c, 0x02, 0x1d, 0x0e, 0x18, 0x03,
0x1e, 0x16, 0x14, 0x0f, 0x19, 0x11, 0x04, 0x08,
0x1f, 0x1b, 0x0d, 0x17, 0x15, 0x13, 0x10, 0x07,
0x1a, 0x0c, 0x12, 0x06, 0x0b, 0x05, 0x0a, 0x09,
};
template <typename Tdummy>
class natural_to_index_impl<false, Tdummy>
{
public:
static constexpr unsigned natural_to_index_unsafe(digest_blocksize_t blocksize) noexcept
{
return nti_debrujin_table[((blocksize / min_blocksize * nti_debrujin_mul) >> 27) & 0x1f];
}
private:
#ifdef FFUZZYPP_STATIC_SANITY_CHECKS
template <uintmax_t i>
struct seq_check
{
static constexpr const bool value =
natural_to_index_unsafe(min_blocksize << i) == i;
};
static_assert(static_assert_query::is_all<seq_check, number_of_blockhashes>::value,
"De Brujin sequence is not constructed correctly.");
#endif
};
static constexpr const bool nti_is_magic_available =
min_blocksize == 3 && number_of_blockhashes <= 31;
public:
template <bool UseDebrujin = false>
static constexpr unsigned natural_to_index_unsafe(digest_blocksize_t blocksize) noexcept
{
return natural_to_index_impl<
nti_is_magic_available && !UseDebrujin
>::natural_to_index_unsafe(blocksize);
}
template <bool UseDebrujin = false>
static unsigned natural_to_index(digest_blocksize_t blocksize) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(is_natural(blocksize));
#endif
return natural_to_index_unsafe<UseDebrujin>(blocksize);
}
};
#ifdef FFUZZYPP_DECLARATIONS
constexpr const unsigned digest_blocksize::nti_magic_table[31];
constexpr const unsigned digest_blocksize::nti_debrujin_table[32];
#endif
}
#endif

1167
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_comparison.hpp

File diff suppressed because it is too large

649
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_data.hpp

@ -0,0 +1,649 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest_data.hpp
Fuzzy digest (data and basic portions)
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_DIGEST_DATA_HPP
#define FFUZZYPP_DIGEST_DATA_HPP
#include <cassert>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <limits>
#include <string>
#include <type_traits>
#include <utility>
#include <errno.h>
#include "base64.hpp"
#include "digest_blocksize.hpp"
#include "strings/sequences.hpp"
#include "strings/nosequences.hpp"
#include "utils/safe_int.hpp"
#include "utils/numeric_digits.hpp"
namespace ffuzzy {
typedef size_t blockhash_len_t;
static_assert(
safe_int::contracts::is_unsigned_integral_type<blockhash_len_t>(),
"blockhash_len_t must be an unsigned integral type.");
struct digest_parse_error {};
class digest_params
{
private:
digest_params(void) = delete;
digest_params(const digest_params&) = delete;
// Common digest parameters (for both short and long forms)
public:
static constexpr const blockhash_len_t max_blockhash_len = 64;
static constexpr const blockhash_len_t max_blockhash_sequence = 3;
static_assert(max_blockhash_len >= 2, "max_blockhash_len must be 2 or greater.");
static_assert(max_blockhash_sequence != 0, "max_blockhash_sequence must not be zero.");
static_assert(safe_int::uvalue<size_t, max_blockhash_len>::is_valid,
"max_blockhash_len must be in range of size_t.");
static_assert(safe_int::uvalue<size_t, max_blockhash_sequence>::is_valid,
"max_blockhash_sequence must be in range of size_t.");
};
template <bool IsAlphabetRestricted> class digest_data_transformation;
template<>
class digest_data_transformation<true>
{
private:
digest_data_transformation(void) = delete;
digest_data_transformation(const digest_data_transformation&) = delete;
public:
typedef base64::transform_from_b64 input_type;
typedef base64::transform_to_b64 output_type;
};
template<>
class digest_data_transformation<false>
{
private:
digest_data_transformation(void) = delete;
digest_data_transformation(const digest_data_transformation&) = delete;
public:
typedef strings::default_char_transform input_type;
typedef strings::default_char_transform output_type;
};
// Friend classes for digest_data class
enum struct comparison_version;
namespace internal
{
template <comparison_version> class digest_comparison_base;
class digest_copy;
}
template <comparison_version> class digest_comparison;
template <bool> class digest_position_array_base;
// Data structure for fuzzy digest (as base class)
template <bool IsAlphabetRestricted, bool IsShort>
class digest_data
{
static_assert(digest_params::max_blockhash_len >= 4,
"max_blockhash_len must be at least 4 due to restrictions in this implementation.");
// Maximum lengths for each block hashes
public:
static constexpr const blockhash_len_t max_blockhash1_len = digest_params::max_blockhash_len;
static constexpr const blockhash_len_t max_blockhash2_len = IsShort
? digest_params::max_blockhash_len / 2
: digest_params::max_blockhash_len;
// Maximum characters required to pretty-print "natural" digests
public:
static_assert(safe_int::safe_mul<
safe_int::uvalue<blockhash_len_t, digest_params::max_blockhash_len>,
safe_int::uvalue<blockhash_len_t, 2>
>::is_valid,
"max_blockhash_len * 2 must be in range of blockhash_len_t.");
static_assert(
safe_int::safe_add<
safe_int::safe_add<
safe_int::uvalue<size_t, 3>,
safe_int::uvalue<size_t, digest_blocksize::max_natural_digits>
>,
safe_int::safe_mul<
safe_int::uvalue<size_t, digest_params::max_blockhash_len>,
safe_int::uvalue<size_t, 2>
>
>::is_valid,
"max_blockhash_len * 2 + max_natural_digits + 3 must be in range of size_t.");
static constexpr const size_t max_natural_chars =
max_blockhash1_len + max_blockhash2_len + // two block hashes
digest_blocksize::max_natural_digits + // block size
3; // two colons and '\0' as a terminator
// width == chars exclusing '\0' (== chars - 1)
static constexpr const size_t max_natural_width = max_natural_chars - 1;
static constexpr const size_t max_natural_width_digits =
numeric_digits::in_decimal<size_t>(max_natural_width);
static_assert(max_natural_width != 0, "sanity check for max_natural_width failed.");
// Data structure
private:
char digest[max_blockhash1_len + max_blockhash2_len];
blockhash_len_t blkhash1_len;
blockhash_len_t blkhash2_len;
digest_blocksize_t blksize;
public:
size_t blockhash1_len(void) const noexcept { return blkhash1_len; }
size_t blockhash2_len(void) const noexcept { return blkhash2_len; }
unsigned long blocksize(void) const noexcept { return blksize; }
size_t digest_size_used(void) const noexcept { return blkhash1_len + blkhash2_len; }
const char* digest_buffer(void) const noexcept { return digest; }
void copy_digest_buffer(char* buf) const noexcept { memcpy(buf, digest, digest_size_used()); }
// "Initialization" and assignment
public:
digest_data(void) noexcept = default; // initialize to undefined state
digest_data(const digest_data& other) noexcept
: blkhash1_len(other.blkhash1_len)
, blkhash2_len(other.blkhash2_len)
, blksize(other.blksize)
{
#ifdef FFUZZYPP_DEBUG
assert(other.is_valid());
#endif
if (digest != other.digest)
memcpy(digest, other.digest, blkhash1_len + blkhash2_len);
}
const digest_data& operator=(const digest_data& other) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(other.is_valid());
#endif
blkhash1_len = other.blkhash1_len;
blkhash2_len = other.blkhash2_len;
blksize = other.blksize;
if (digest != other.digest)
memcpy(digest, other.digest, blkhash1_len + blkhash2_len);
return *this;
}
static void swap(digest_data& a, digest_data& b) noexcept
{
std::swap(a.blksize, b.blksize);
std::swap(a.blkhash1_len, b.blkhash1_len);
std::swap(a.blkhash2_len, b.blkhash2_len);
std::swap(a.digest, b.digest); // C++11 version of swap
}
// Validators (for its validness and naturality)
public:
bool is_valid(void) const noexcept
{
if (blkhash1_len > max_blockhash1_len)
return false;
if (blkhash2_len > max_blockhash2_len)
return false;
if (blksize > 0xfffffffful)
return false;
if (IsAlphabetRestricted)
{
for (blockhash_len_t i = 0, l = blkhash1_len + blkhash2_len; i < l; i++)
if (digest[i] < char(0) || 64 <= digest[i])
return false;
}
return true;
}
bool is_natural(void) const noexcept
{
if (!is_valid())
return false;
if (blkhash1_len < blkhash2_len)
return false;
if (!digest_blocksize::is_natural(blksize))
return false;
if (!digest_blocksize::is_safe_to_double(blksize) && blkhash2_len >= 2)
return false;
if (!IsAlphabetRestricted)
{
for (blockhash_len_t i = 0, l = blkhash1_len + blkhash2_len; i < l; i++)
if (!base64::isbase64(digest[i]))
return false;
}
return true;
}
bool is_blocksize_natural(void) const noexcept
{
return digest_blocksize::is_natural(blksize);
}
bool is_normalized(void) const noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(is_valid());
#endif
return
!strings::sequences<digest_params::max_blockhash_sequence>
::has_sequences(digest, blkhash1_len) &&
!strings::sequences<digest_params::max_blockhash_sequence>
::has_sequences(digest+blkhash1_len, blkhash2_len);
}
bool has_valid_base64_data(void) const noexcept
{
if (blkhash1_len > max_blockhash1_len)
return false;
if (blkhash2_len > max_blockhash2_len)
return false;
if (IsAlphabetRestricted)
{
for (blockhash_len_t i = 0, l = blkhash1_len + blkhash2_len; i < l; i++)
if (digest[i] < char(0) || 64 <= digest[i])
return false;
}
else
{
for (blockhash_len_t i = 0, l = blkhash1_len + blkhash2_len; i < l; i++)
if (!base64::isbase64(digest[i]))
return false;
}
return true;
}
// Equality
private:
static bool is_eq_except_blocksize(const digest_data& a, const digest_data& b) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(a.is_valid());
assert(b.is_valid());
#endif
return
a.blkhash1_len == b.blkhash1_len &&
a.blkhash2_len == b.blkhash2_len &&
memcmp(a.digest, b.digest, a.digest_size_used()) == 0;
}
static bool is_eq(const digest_data& a, const digest_data& b) noexcept
{
return
digest_blocksize::is_near_eq(a.blksize, b.blksize) &&
is_eq_except_blocksize(a, b);
}
public:
friend bool operator==(const digest_data& a, const digest_data& b) noexcept { return is_eq(a, b); }
friend bool operator!=(const digest_data& a, const digest_data& b) noexcept { return !is_eq(a, b); }
// Default comparison for sorting (in "dictionary" order or whatever)
// Note that sort order differs depending on IsAlphabetRestricted.
public:
friend bool operator<(const digest_data& a, const digest_data& b) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(a.is_valid());
assert(b.is_valid());
#endif
if (a.blksize < b.blksize)
return true;
if (a.blksize > b.blksize)
return false;
if (a.blkhash1_len < b.blkhash1_len)
return true;
if (a.blkhash1_len > b.blkhash1_len)
return false;
if (a.blkhash2_len < b.blkhash2_len)
return true;
if (a.blkhash2_len > b.blkhash2_len)
return false;
if (memcmp(a.digest, b.digest, a.digest_size_used()) < 0)
return true;
return false;
}
friend bool operator>(const digest_data& a, const digest_data& b) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(a.is_valid());
assert(b.is_valid());
#endif
if (a.blksize > b.blksize)
return true;
if (a.blksize < b.blksize)
return false;
if (a.blkhash1_len > b.blkhash1_len)
return true;
if (a.blkhash1_len < b.blkhash1_len)
return false;
if (a.blkhash2_len > b.blkhash2_len)
return true;
if (a.blkhash2_len < b.blkhash2_len)
return false;
if (memcmp(a.digest, b.digest, a.digest_size_used()) > 0)
return true;
return false;
}
friend bool operator<=(const digest_data& a, const digest_data& b) noexcept { return !(a > b); }
friend bool operator>=(const digest_data& a, const digest_data& b) noexcept { return !(a < b); }
// Predicates (including non-standard comparison predicates for fast sorting)
public:
struct pred_equal_to
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept { return a == b; }
};
struct pred_not_equal_to
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept { return a != b; }
};
struct pred_less
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept { return a < b; }
};
struct pred_less_equal
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept { return a <= b; }
};
struct pred_greater
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept { return a > b; }
};
struct pred_greater_equal
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept { return a >= b; }
};
struct pred_less_blocksize
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept
{
return a.blksize < b.blksize;
}
};
struct pred_less_blocksize_natural
{
bool operator()(const digest_data& a, const digest_data& b) const noexcept
{
bool aN = digest_blocksize::is_natural(a.blksize);
bool bN = digest_blocksize::is_natural(b.blksize);
if (aN && !bN)
return false;
if (!aN && bN)
return true;
if (a.blksize < b.blksize)
return true;
return false;
}
};
// Hash (for sets and dictionaries)
public:
size_t hash(void) const noexcept
{
typedef typename std::conditional<
(std::numeric_limits<size_t>::max() >= 0xfffffffful),
size_t, uint_least32_t
>::type hash_t;
static constexpr const hash_t fnv_init = 2166136261ul;
static constexpr const hash_t fnv_prime = 16777619ul;
hash_t h = fnv_init;
h ^= hash_t(blksize); h *= fnv_prime;
h ^= hash_t(blkhash1_len); h *= fnv_prime;
h ^= hash_t(blkhash2_len); h *= fnv_prime;
for (blockhash_len_t i = 0, l = blkhash1_len + blkhash2_len; i < l; i++)
{
h ^= hash_t(static_cast<unsigned char>(digest[i]));
h *= fnv_prime;
}
if (std::numeric_limits<size_t>::max() < 0xfffffffful)
h ^= (h >> 16);
return size_t(h);
}
// Normalization
public:
static void normalize(digest_data& dest, const digest_data& source) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(source.is_valid());
#endif
dest.blksize = source.blksize;
blockhash_len_t orig_blkhash1_len = source.blkhash1_len;
dest.blkhash1_len = strings::sequences<digest_params::max_blockhash_sequence>
::copy_elim_sequences(dest.digest, source.digest, source.blkhash1_len);
dest.blkhash2_len = strings::sequences<digest_params::max_blockhash_sequence>
::copy_elim_sequences(dest.digest + dest.blkhash1_len, source.digest + orig_blkhash1_len, source.blkhash2_len);
#ifdef FFUZZYPP_DEBUG
assert(dest.is_valid());
assert(dest.is_normalized());
#endif
}
template <typename Treturn = digest_data>
static Treturn normalize(const digest_data& source) noexcept
{
Treturn dest;
digest_data::normalize(dest, source);
return dest;
}
void normalize(void) noexcept
{
normalize(*this, *this);
}
// Utility to parse digests
private:
template <template <char... terms> class Tstring_copy>
static bool parse_internal(digest_data& digest, const char* str) noexcept
{
const char* rem = str;
char* out = digest.digest;
errno = 0;
// size of unsigned long is at least 32-bit
unsigned long blksize = strtoul(str, const_cast<char**>(&rem), 10);
if (rem == str)
return false;
if (errno == ERANGE && blksize == std::numeric_limits<unsigned long>::max())
return false;
if (blksize > 0xfffffffful)
return false;
digest.blksize = digest_blocksize_t(blksize);
if (*rem++ != ':')
return false;
if (!Tstring_copy<':'>::copy_elim_sequences(out, max_blockhash1_len, rem))
return false;
digest.blkhash1_len = out - digest.digest;
char* outtmp = out;
if (*rem++ != ':')
return false;
#ifndef FFUZZYPP_BLOCKDIGEST2_TERMS
// default from ffuzzy++ 4.0
#define FFUZZYPP_BLOCKDIGEST2_TERMS ','
#endif
if (!Tstring_copy<FFUZZYPP_BLOCKDIGEST2_TERMS>::
copy_elim_sequences(out, max_blockhash2_len, rem))
return false;
digest.blkhash2_len = out - outtmp;
if (IsAlphabetRestricted)
{
for (blockhash_len_t i = 0; i < digest.blkhash1_len + digest.blkhash2_len; i++)
{
if (digest.digest[i] == base64::invalid_index)
return false;
}
}
return true;
}
protected:
static bool parse(digest_data& digest, const char* str) noexcept
{
return parse_internal<
strings::nosequences<typename digest_data_transformation<IsAlphabetRestricted>::input_type>::template string_copy
>(digest, str);
}
static bool parse(digest_data& digest, const std::string& str)
{
return parse(digest, str.c_str());
}
static bool parse_normalized(digest_data& digest, const char* str) noexcept
{
return parse_internal<
strings::sequences<digest_params::max_blockhash_sequence,
typename digest_data_transformation<IsAlphabetRestricted>::input_type>::template string_copy
>(digest, str);
}
static bool parse_normalized(digest_data& digest, const std::string& str)
{
return parse_normalized(digest, str.c_str());
}
// Pretty printing
public:
bool pretty_unsafe(char* out) const noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(is_valid());
#endif
int n = sprintf(out, "%lu:", static_cast<unsigned long>(blksize));
if (n < 0)
return false;
out += n;
strings::nosequences<typename digest_data_transformation<IsAlphabetRestricted>::output_type>::copy_raw(out, digest, blkhash1_len);
out += blkhash1_len;
*out++ = ':';
strings::nosequences<typename digest_data_transformation<IsAlphabetRestricted>::output_type>::copy_raw(out, digest+blkhash1_len, blkhash2_len);
out[blkhash2_len] = '\0';
return true;
}
bool pretty(char* out, size_t outsize) const noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(is_valid());
#endif
int n = snprintf(out, outsize, "%lu:", static_cast<unsigned long>(blksize));
if (n < 0)
return false;
if (size_t(n) == outsize)
return false;
outsize -= size_t(n);
out += n;
if (outsize < size_t(blkhash1_len) + size_t(blkhash2_len) + 2)
return false;
strings::nosequences<typename digest_data_transformation<IsAlphabetRestricted>::output_type>::copy_raw(out, digest, blkhash1_len);
out += blkhash1_len;
*out++ = ':';
strings::nosequences<typename digest_data_transformation<IsAlphabetRestricted>::output_type>::copy_raw(out, digest+blkhash1_len, blkhash2_len);
out[blkhash2_len] = '\0';
return true;
}
std::string pretty(void) const
{
#ifdef FFUZZYPP_DEBUG
assert(is_valid());
#endif
unsigned long bs(blksize);
std::string str(std::to_string(bs));
str.push_back(':');
for (blockhash_len_t i = 0; i < blkhash1_len; i++)
str.push_back(digest_data_transformation<IsAlphabetRestricted>::output_type::transform(digest[i]));
str.push_back(':');
for (blockhash_len_t i = 0; i < blkhash2_len; i++)
str.push_back(digest_data_transformation<IsAlphabetRestricted>::output_type::transform(digest[blkhash1_len + i]));
return str;
}
// Friend classes
template <comparison_version> friend class internal::digest_comparison_base;
template <comparison_version> friend class digest_comparison;
template <bool> friend class digest_position_array_base;
friend class digest_generator;
friend class internal::digest_copy;
};
namespace internal
{
// Utility to copy constrained digest data to non-constrained digest object
class digest_copy
{
private:
digest_copy(void) = delete;
digest_copy(const digest_copy&) = delete;
public:
template <bool IsAlphabetRestricted>
static void copy_to_long(
digest_data<IsAlphabetRestricted, false>& dest,
const digest_data<IsAlphabetRestricted, true>& src
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(src.is_valid());
#endif
dest.blkhash1_len = src.blkhash1_len;
dest.blkhash2_len = src.blkhash2_len;
dest.blksize = src.blksize;
memcpy(dest.digest, src.digest, src.blkhash1_len + src.blkhash2_len);
}
template <bool IsShort>
static void copy_to_non_ra(
digest_data<false, IsShort>& dest,
const digest_data<true, IsShort>& src
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(src.is_valid());
#endif
dest.blkhash1_len = src.blkhash1_len;
dest.blkhash2_len = src.blkhash2_len;
dest.blksize = src.blksize;
strings::nosequences<base64::transform_to_b64>::
copy_raw(dest.digest, src.digest, src.blkhash1_len + src.blkhash2_len);
}
static void copy_to_long_non_ra(
digest_data<false, false>& dest,
const digest_data<true, true>& src
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(src.is_valid());
#endif
dest.blkhash1_len = src.blkhash1_len;
dest.blkhash2_len = src.blkhash2_len;
dest.blksize = src.blksize;
strings::nosequences<base64::transform_to_b64>::
copy_raw(dest.digest, src.digest, src.blkhash1_len + src.blkhash2_len);
}
};
}
}
#endif

125
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_filesize.hpp

@ -0,0 +1,125 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest_filesize.hpp
File size utilities
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_DIGEST_FILESIZE_HPP
#define FFUZZYPP_DIGEST_FILESIZE_HPP
#include <cstddef>
#include <cstdint>
#include "digest_blocksize.hpp"
#include "digest_data.hpp"
#include "utils/safe_int.hpp"
namespace ffuzzy {
typedef uint_least64_t digest_filesize_t;
// File size utilities
class digest_filesize
{
static_assert(safe_int::contracts::is_unsigned_integral_type<digest_filesize_t>(),
"digest_filesize_t must be an unsigned integral type.");
private:
digest_filesize(void) = delete;
digest_filesize(const digest_filesize&) = delete;
// Minimum size (as supported by ssdeep)
private:
static constexpr const unsigned long u_min_supported_size = 4096 + 1;
public:
static_assert(u_min_supported_size <= 0xfffffffful,
"u_min_supported_size must be in range of 32-bit unsigned integer.");
static_assert(safe_int::uvalue<digest_filesize_t, u_min_supported_size>::is_valid,
"u_min_supported_size must be in range of digest_filesize_t.");
static constexpr const digest_filesize_t min_supported_size = u_min_supported_size;
// Maximum size (theoretical limit)
public:
static_assert(safe_int::safe_add<
safe_int::safe_mul<
safe_int::uvalue<digest_filesize_t, digest_blocksize::max_blocksize>,
safe_int::uvalue<digest_filesize_t, digest_params::max_blockhash_len>
>,
safe_int::uvalue<digest_filesize_t, 1>
>::is_valid,
"max_blocksize * max_blockhash_len + 1 (== max_size + 1) must be "
"in range of digest_filesize_t.");
static constexpr const digest_filesize_t max_size =
digest_filesize_t(digest_blocksize::max_blocksize) *
digest_filesize_t(digest_params::max_blockhash_len);
static constexpr const digest_filesize_t max_theoretical_size = max_size;
// Maximum portable size (with ssdeep 2.6-2.12)
public:
static_assert(safe_int::uvalue<digest_filesize_t, 0xfffffffful>::is_valid,
"digest_filesize_t must be able to represent all 32-bit unsigned integer values.");
static constexpr const digest_filesize_t max_portable_size =
minmax::min(max_size, digest_filesize_t(0xfffffffful));
static_assert(min_supported_size <= max_portable_size,
"min_supported_size must not exceed max_portable_size.");
// Predicates
public:
static constexpr bool is_portable(digest_filesize_t total_size) noexcept
{
/*
WARNING: Given size may not be "portable" on insane architectures.
Portability:
* ffuzzy++ (3.0)
* ssdeep (including 2.6-2.12)
Note:
Mr.Kornblum (the original author of ssdeep) considers
version 2.9 the "standard". Note that this release does not
support files equal to or larger than 4GiB.
*/
return total_size >= min_supported_size && total_size <= max_portable_size;
}
static constexpr bool is_supported_by_ssdeep_2_12(digest_filesize_t total_size) noexcept
{
return total_size >= min_supported_size && total_size <= max_portable_size;
}
static constexpr bool is_supported_by_ffuzzy_3_0(digest_filesize_t total_size) noexcept
{
return total_size <= max_theoretical_size;
}
static constexpr bool is_supported(digest_filesize_t total_size) noexcept
{
// whether supported by "this" version of ffuzzy++
return is_supported_by_ffuzzy_3_0(total_size);
}
// Predicate (equivalent to "not meaningful results" in ssdeep)
public:
static constexpr bool is_not_meaningful(digest_filesize_t total_size) noexcept
{
return total_size < min_supported_size;
}
};
}
#endif

544
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_generator.hpp

@ -0,0 +1,544 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest_generator.hpp
Fuzzy digest generator
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_DIGEST_GENERATOR_HPP
#define FFUZZYPP_DIGEST_GENERATOR_HPP
#include <cassert>
#include <cstdint>
#include <cstddef>
#include <algorithm>
#include <string>
#include "base64.hpp"
#include "context_hash.hpp"
#include "context_hash_fast.hpp"
#include "rolling_hash.hpp"
#include "rolling_hash_ssdeep.hpp"
#include "digest_blocksize.hpp"
#include "digest_data.hpp"
#include "digest_base.hpp"
#include "digest_filesize.hpp"
#include "utils/likely.hpp"
#include "utils/safe_int.hpp"
#include "strings/transform.hpp"
#include "strings/sequences.hpp"
#include "strings/nosequences.hpp"
namespace ffuzzy {
struct digest_generator_error {};
class digest_generator
{
// Digest characters and transformation for them
private:
/*
This type contains digest characters as Base64 indices.
To distinguish valid and invalid characters,
we need a "nil" value.
We transform Base64 indices to actual Base64 characters
when we are copying final digest value.
*/
typedef base64::transform_to_b64 digest_transform_t;
static constexpr const char digest_nil = 64;
static_assert(digest_nil < 0 || digest_nil > 63,
"digest_nil must be out of Base64 range.");
// Heuristics to guess maximum file size from block size (or its index)
public:
static constexpr digest_filesize_t guessed_filesize(digest_blocksize_t blocksize) noexcept
{
return digest_filesize_t(blocksize) * digest_params::max_blockhash_len;
}
static constexpr digest_filesize_t guessed_filesize_at(unsigned i) noexcept
{
return guessed_filesize(digest_blocksize::at(i));
}
// Heuristic to guess block size from file size
public:
static unsigned blockhash_index_guessed_by_filesize(digest_filesize_t size, unsigned start = 0) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(start < digest_blocksize::number_of_blockhashes);
assert(size <= digest_filesize::max_size);
#endif
unsigned bi = start;
digest_filesize_t bgs = guessed_filesize_at(bi);
while (bgs < size)
{
bi++;
bgs *= 2;
}
return bi;
}
// Data Structure
private:
typedef context_hash_fast context_hash_t;
struct blockhash_context
{
context_hash_t hfull;
context_hash_t hhalf;
char digest[digest_params::max_blockhash_len];
char digesth;
blockhash_len_t dindex;
};
blockhash_context bh[digest_blocksize::number_of_blockhashes];
digest_filesize_t totalsz;
digest_filesize_t totalsz_constant;
digest_filesize_t reduce_border;
rolling_hash roll;
unsigned bhstart;
unsigned bhend;
unsigned bhendlimit;
uint_least32_t rollmask;
context_hash_t hlast;
unsigned flags;
static constexpr const unsigned FLAG_LASTHASH = 0x1;
static constexpr const unsigned FLAG_SZCONSTANT = 0x2;
// Simple data structure manipulation
public:
bool is_total_size_clamped(void) const noexcept { return totalsz > digest_filesize::max_size; }
bool is_file_size_constant(void) const noexcept { return flags & FLAG_SZCONSTANT; }
unsigned blockhash_index_start(void) const noexcept { return bhstart; }
unsigned blockhash_index_end(void) const noexcept { return bhend; }
unsigned blockhash_index_end_limit(void) const noexcept { return bhendlimit; }
digest_filesize_t total_size(void) const noexcept { return totalsz; }
// constant file size (for fast ssdeep hashing)
digest_filesize_t get_file_size_constant(void) const noexcept { return totalsz_constant; }
bool set_file_size_constant(digest_filesize_t size) noexcept
{
if (is_file_size_constant() && totalsz_constant != size)
return false;
if (size > digest_filesize::max_size)
return false;
totalsz_constant = size;
bhendlimit = std::min(
digest_blocksize::number_of_blockhashes - 1,
blockhash_index_guessed_by_filesize(size) + 1
);
flags |= FLAG_SZCONSTANT;
return true;
}
public:
// Reset minimum context required
void reset(void) noexcept
{
bh[0].hfull.reset();
bh[0].hhalf.reset();
bh[0].digest[digest_params::max_blockhash_len - 1] = digest_nil;
bh[0].digesth = digest_nil;
bh[0].dindex = 0;
totalsz = 0;
reduce_border = guessed_filesize_at(0);
roll.reset();
bhstart = 0;
bhend = 1;
bhendlimit = digest_blocksize::number_of_blockhashes - 1;
rollmask = 0;
flags = 0;
}
// Update functions (by buffer or by character)
public:
void update(const unsigned char* buf, size_t len) noexcept
{
rolling_hash r = roll;
if (FFUZZYPP_UNLIKELY(len > digest_filesize::max_size
|| digest_filesize::max_size - digest_filesize_t(len) < totalsz))
{
totalsz = digest_filesize::max_size + 1;
}
else
{
totalsz += digest_filesize_t(len);
}
while (len--)
{
unsigned char c = *buf++;
r.update(c);
for (unsigned i = bhstart; i < bhend; i++)
{
bh[i].hfull.update(c);
bh[i].hhalf.update(c);
}
if (flags & FLAG_LASTHASH)
hlast.update(c);
uint_least32_t horg = (r.sum() + 1) & uint_least32_t(0xfffffffful);
uint_least32_t h = horg / uint_least32_t(digest_blocksize::min_blocksize);
if (0xfffffffful % digest_blocksize::min_blocksize != digest_blocksize::min_blocksize - 1 && !horg)
continue;
if (FFUZZYPP_LIKELY(h & rollmask))
continue;
if (horg % uint_least32_t(digest_blocksize::min_blocksize))
continue;
h >>= bhstart;
unsigned i = bhstart;
do
{
if (FFUZZYPP_UNLIKELY(bh[i].dindex == 0))
{
// fork to prepare larger block sizes
if (bhend > bhendlimit)
{
if (bhendlimit == digest_blocksize::number_of_blockhashes - 1
&& !(flags & FLAG_LASTHASH))
{
hlast = bh[i].hfull;
flags |= FLAG_LASTHASH;
}
}
else
{
bh[i+1].hfull = bh[i].hfull;
bh[i+1].hhalf = bh[i].hhalf;
bh[i+1].digest[digest_params::max_blockhash_len - 1] = digest_nil;
bh[i+1].digesth = digest_nil;
bh[i+1].dindex = 0;
bhend++;
}
}
bh[i].digest[bh[i].dindex] = bh[i].hfull.sum_in_base64();
bh[i].digesth = bh[i].hhalf.sum_in_base64();
if (bh[i].dindex < digest_params::max_blockhash_len - 1)
{
bh[i].dindex++;
bh[i].hfull.reset();
if (bh[i].dindex < digest_params::max_blockhash_len / 2)
{
bh[i].digesth = digest_nil;
bh[i].hhalf.reset();
}
}
// eliminate block sizes which will not be chosen
else if (FFUZZYPP_UNLIKELY(bhend - bhstart >= 2
&& reduce_border < (is_file_size_constant() ? totalsz_constant : totalsz)
&& bh[i+1].dindex >= digest_params::max_blockhash_len / 2))
{
bhstart++;
rollmask = rollmask * 2 + 1;
reduce_border *= 2;
}
if (h & 1)
break;
h >>= 1;
} while (++i < bhend);
}
roll = r;
}
void update(unsigned char c) noexcept
{
unsigned char C(c);
update(&C, 1);
}
// High-level update utilities
// (by file pointer or by file name; w/ or w/o internal buffer)
public:
static constexpr const size_t default_buffer_size = 4096;
template <size_t buffer_size = default_buffer_size>
bool update_by_stream(FILE* fp, unsigned char* tmpbuf) noexcept
{
static_assert(buffer_size != 0, "buffer_size must not be zero.");
if (!fp)
return false;
while (true)
{
size_t n = fread(tmpbuf, 1, buffer_size, fp);
if (n == 0)
break;
update(tmpbuf, n);
}
if (feof(fp))
return true;
return false;
}
template <size_t buffer_size = default_buffer_size>
bool update_by_stream(FILE* fp) noexcept
{
static_assert(buffer_size != 0, "buffer_size must not be zero.");
unsigned char buf[buffer_size];
return update_by_stream<buffer_size>(fp, buf);
}
template <size_t buffer_size = default_buffer_size>
bool update_by_file(const char* filename) noexcept
{
static_assert(buffer_size != 0, "buffer_size must not be zero.");
FILE* fp = fopen(filename, "rb");
if (!fp)
return false;
bool ret = update_by_stream<buffer_size>(fp);
fclose(fp);
return ret;
}
template <size_t buffer_size = default_buffer_size>
bool update_by_file(const char* filename, unsigned char* tmpbuf) noexcept
{
static_assert(buffer_size != 0, "buffer_size must not be zero.");
FILE* fp = fopen(filename, "rb");
if (!fp)
return false;
bool ret = update_by_stream<buffer_size>(fp, tmpbuf);
fclose(fp);
return ret;
}
// Digest finalization
private:
// Heuristic to guess block hash index to start from the current state
unsigned blockhash_index_guessed_to_start(void) const noexcept
{
unsigned bi = blockhash_index_guessed_by_filesize(totalsz, bhstart);
#ifdef FFUZZYPP_DEBUG
assert(bi < digest_blocksize::number_of_blockhashes);
#endif
bi = std::min(bi, bhend - 1);
while (bi > bhstart && bh[bi].dindex < digest_params::max_blockhash_len / 2)
bi--;
#ifdef FFUZZYPP_DEBUG
assert(bi >= bhstart && bi < bhend);
assert(bi == 0 || bh[bi].dindex >= digest_params::max_blockhash_len / 2);
#endif
return bi;
}
// Copy the final (resulting) digest
template <typename Tseq, bool IsAlphabetRestricted, bool IsShort, bool Shortened>
bool copy_digest_internal(digest_data<IsAlphabetRestricted, IsShort>& digest) noexcept
{
/*
This function is not exactly "const" but mostly constant.
You can call this function multiple times as you need.
*/
static_assert(Shortened == true || IsShort == false,
"copying long result to short digest_data structure is prohibited.");
if (is_total_size_clamped())
return false;
if (is_file_size_constant() && totalsz != totalsz_constant)
return false;
unsigned bi = blockhash_index_guessed_to_start();
digest.blksize = digest_blocksize::at(bi);
uint_least32_t rh = roll.sum();
// Copy first block hash (digest)
{
char chtmp = bh[bi].digest[digest_params::max_blockhash_len - 1];
size_t sz = bh[bi].dindex;
if (rh != 0)
bh[bi].digest[sz++] = bh[bi].hfull.sum_in_base64();
else if (chtmp != digest_nil)
sz++;
digest.blkhash1_len = Tseq::copy_elim_sequences(digest.digest, bh[bi].digest, sz);
bh[bi].digest[digest_params::max_blockhash_len - 1] = chtmp;
}
// Copy second block hash if we need
if (bi < bhend - 1)
{
size_t dindex = bh[bi+1].dindex;
if (Shortened)
dindex = std::min(dindex, size_t(digest_params::max_blockhash_len / 2 - 1));
char chtmp = bh[bi+1].digest[dindex];
size_t sz = dindex;
if (rh != 0)
{
bh[bi+1].digest[sz++] = Shortened
? bh[bi+1].hhalf.sum_in_base64()
: bh[bi+1].hfull.sum_in_base64();
}
else
{
if (Shortened)
{
if (bh[bi+1].digesth != digest_nil)
bh[bi+1].digest[sz++] = bh[bi+1].digesth;
}
else
{
if (dindex == digest_params::max_blockhash_len - 1 && chtmp != digest_nil)
sz++;
}
}
digest.blkhash2_len = Tseq::copy_elim_sequences(
digest.digest + digest.blkhash1_len, bh[bi+1].digest, sz);
bh[bi+1].digest[dindex] = chtmp;
}
else if (rh != 0)
{
#ifdef FFUZZYPP_DEBUG
assert(bi == 0 || bi == digest_blocksize::number_of_blockhashes - 1);
#endif
if (bi == 0)
digest.digest[digest.blkhash1_len] = bh[bi].hfull.sum_in_base64();
else
digest.digest[digest.blkhash1_len] = hlast.sum_in_base64();
digest.blkhash2_len = Tseq::copy_elim_sequences(
digest.digest + digest.blkhash1_len,
digest.digest + digest.blkhash1_len,
1);
}
else
{
digest.blkhash2_len = 0;
}
return true;
}
// Digest finalization (and copying) utilities
private:
template <bool IsAlphabetRestricted, bool IsShort, bool Shortened>
bool copy_digest_base(digest_data<IsAlphabetRestricted, IsShort>& digest) noexcept
{
return copy_digest_internal<
strings::nosequences<
typename digest_data_transformation<!IsAlphabetRestricted>::output_type
>,
IsAlphabetRestricted, IsShort, Shortened>(digest);
}
public:
template <bool IsAlphabetRestricted, bool IsShort, bool Shortened = true>
bool copy_digest_normalized(digest_data<IsAlphabetRestricted, IsShort>& digest) noexcept
{
return copy_digest_internal<
strings::sequences<
digest_params::max_blockhash_sequence,
typename digest_data_transformation<!IsAlphabetRestricted>::output_type
>, IsAlphabetRestricted, IsShort, Shortened
>(digest);
}
template <bool IsAlphabetRestricted, bool IsShort>
bool copy_digest(digest_base<IsAlphabetRestricted, IsShort, true>& digest) noexcept
{
return copy_digest_normalized<IsAlphabetRestricted, IsShort, true>(digest);
}
template <bool IsAlphabetRestricted, bool IsShort>
bool copy_digest(digest_base<IsAlphabetRestricted, IsShort, false>& digest) noexcept
{
return copy_digest_base<IsAlphabetRestricted, IsShort, true>(digest);
}
public:
template <bool IsAlphabetRestricted>
bool copy_digest_long_normalized(digest_base<IsAlphabetRestricted, false, true>& digest) noexcept
{
return copy_digest_normalized<IsAlphabetRestricted, false, false>(digest);
}
template <bool IsAlphabetRestricted>
bool copy_digest_long(digest_base<IsAlphabetRestricted, false, true>& digest) noexcept
{
return copy_digest_normalized<IsAlphabetRestricted, false, false>(digest);
}
template <bool IsAlphabetRestricted>
bool copy_digest_long(digest_base<IsAlphabetRestricted, false, false>& digest) noexcept
{
return copy_digest_base<IsAlphabetRestricted, false, false>(digest);
}
private:
template <typename T, bool IsAlphabetRestricted, bool IsShort, bool IsNormalized, bool Shortened = true>
T digest_in_type(void)
{
// This object to be erased by NRVO.
T d;
if (IsNormalized)
{
if (!copy_digest_normalized<IsAlphabetRestricted, IsShort, Shortened>(d))
throw digest_generator_error();
}
else
{
if (!copy_digest_base<IsAlphabetRestricted, IsShort, Shortened>(d))
throw digest_generator_error();
}
return d;
}
public:
digest_unorm_t digest(void)
{
// Default options as you need (unnormalized; short form)
return digest_in_type<digest_unorm_t, false, true, false>();
}
std::string digest_str(void)
{
return digest().pretty();
}
public:
template <bool Shortened = false>
digest_long_unorm_t digest_long(void)
{
return digest_in_type<digest_long_unorm_t, false, false, false, Shortened>();
}
digest_t digest_normalized(void)
{
return digest_in_type<digest_t, false, true, true>();
}
template <bool Shortened = false>
digest_long_t digest_long_normalized(void)
{
return digest_in_type<digest_long_t, false, false, true, Shortened>();
}
public:
digest_ra_unorm_t digest_ra(void)
{
return digest_in_type<digest_ra_unorm_t, true, true, false>();
}
template <bool Shortened = false>
digest_ra_long_unorm_t digest_ra_long(void)
{
return digest_in_type<digest_ra_long_unorm_t, true, false, false, Shortened>();
}
digest_ra_t digest_ra_normalized(void)
{
return digest_in_type<digest_ra_t, true, true, true>();
}
template <bool Shortened = false>
digest_ra_long_t digest_ra_long_normalized(void)
{
return digest_in_type<digest_ra_long_t, true, false, true, Shortened>();
}
// Constructors
public:
digest_generator(void) noexcept
{
reset();
}
digest_generator(const digest_generator&) noexcept = default;
};
}
#endif

425
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_position_array.hpp

@ -0,0 +1,425 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest_position_array.hpp
Fuzzy digest (position array representation)
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_DIGEST_POSITION_ARRAY_HPP
#define FFUZZYPP_DIGEST_POSITION_ARRAY_HPP
#include <algorithm>
#include <string>
#include "digest_base.hpp"
#include "digest_position_array_base.hpp"
#include "digest_comparison.hpp"
namespace ffuzzy {
template <bool IsAlphabetRestricted>
class digest_position_array
: public digest_position_array_base<IsAlphabetRestricted>
{
public:
static constexpr const bool is_alphabet_restricted = IsAlphabetRestricted;
public:
digest_position_array(void) noexcept = default; // initialize to undefined state
digest_position_array(const digest_position_array& other) noexcept
: digest_position_array_base<IsAlphabetRestricted>(other) {}
const digest_position_array& operator=(const digest_position_array& other) noexcept
{
digest_position_array_base<IsAlphabetRestricted>::operator=(other);
return *this;
}
// Initialization by digest
public:
template <bool IsShort>
digest_position_array(const digest_base<IsAlphabetRestricted, IsShort, true>& src) noexcept
{
digest_position_array_base<IsAlphabetRestricted>::construct(*this, src);
}
template <bool IsShort>
digest_position_array(const digest_base<IsAlphabetRestricted, IsShort, false>& src) noexcept
{
digest_position_array_base<IsAlphabetRestricted>::construct(*this, digest_data<IsAlphabetRestricted, IsShort>::normalize(src));
}
public:
template <bool IsShort>
static void construct(
digest_position_array& dest,
const digest_base<IsAlphabetRestricted, IsShort, true>& src
) noexcept
{
digest_position_array_base<IsAlphabetRestricted>::construct(dest, src);
}
template <bool IsShort>
static void construct(
digest_position_array& dest,
const digest_base<IsAlphabetRestricted, IsShort, false>& src
) noexcept
{
digest_position_array_base<IsAlphabetRestricted>::construct(dest, digest_data<IsAlphabetRestricted, IsShort>::normalize(src));
}
// Initialization by digest string
public:
explicit digest_position_array(const char* str) noexcept(false)
{
digest_base<IsAlphabetRestricted, false, true> digest(str);
construct(*this, digest);
}
explicit digest_position_array(const std::string& str)
: digest_position_array(str.c_str()) {}
// Comparison
public:
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, false, true>& b
) noexcept
{
return digest_comparison<Version>::compare(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, true, true>& b
) noexcept
{
return digest_comparison<Version>::compare(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare(
const digest_base<IsAlphabetRestricted, false, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare(
const digest_base<IsAlphabetRestricted, true, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, false, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, true, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near(
const digest_base<IsAlphabetRestricted, false, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near(
const digest_base<IsAlphabetRestricted, true, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, false, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, true, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq(
const digest_base<IsAlphabetRestricted, false, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq(
const digest_base<IsAlphabetRestricted, true, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_lt(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, false, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_lt(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_lt(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, true, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_lt(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_lt(
const digest_base<IsAlphabetRestricted, false, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_lt(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_lt(
const digest_base<IsAlphabetRestricted, true, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_lt(a, b);
}
public:
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare_near<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare_near<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_eq(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare_near_eq<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_eq(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare_near_eq<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_lt(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare_near_lt<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_lt(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare_near_lt<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_gt(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare_near_lt<Version>(other, *this);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_gt(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare_near_lt<Version>(other, *this);
}
// Comparison (on different digests)
public:
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_diff(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, false, true>& b
) noexcept
{
return digest_comparison<Version>::compare_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_diff(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, true, true>& b
) noexcept
{
return digest_comparison<Version>::compare_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_diff(
const digest_base<IsAlphabetRestricted, false, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_diff(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_diff(
const digest_base<IsAlphabetRestricted, true, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_diff(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_diff(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, false, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_diff(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, true, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_diff(
const digest_base<IsAlphabetRestricted, false, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_diff(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_diff(
const digest_base<IsAlphabetRestricted, true, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_diff(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq_diff(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, false, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq_diff(
const digest_position_array& a,
const digest_base<IsAlphabetRestricted, true, true>& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq_diff(a, b);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq_diff(
const digest_base<IsAlphabetRestricted, false, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq_diff(b, a);
}
template <comparison_version Version = comparison_version::latest>
static digest_comparison_score_t compare_near_eq_diff(
const digest_base<IsAlphabetRestricted, true, true>& a,
const digest_position_array& b
) noexcept
{
return digest_comparison<Version>::compare_near_eq_diff(b, a);
}
public:
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_diff(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare_diff<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_diff(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare_diff<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_diff(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare_near_diff<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_diff(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare_near_diff<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_eq_diff(const digest_base<IsAlphabetRestricted, false, true>& other) const noexcept
{
return compare_near_eq_diff<Version>(*this, other);
}
template <comparison_version Version = comparison_version::latest>
digest_comparison_score_t compare_near_eq_diff(const digest_base<IsAlphabetRestricted, true, true>& other) const noexcept
{
return compare_near_eq_diff<Version>(*this, other);
}
};
typedef digest_position_array< true> digest_position_array_t;
typedef digest_position_array<false> digest_position_array_non_ra_t;
}
// Specialization of standard swap
namespace std
{
template <bool IsAlphabetRestricted>
inline void swap(
ffuzzy::digest_position_array<IsAlphabetRestricted>& a,
ffuzzy::digest_position_array<IsAlphabetRestricted>& b
) noexcept
{
ffuzzy::digest_position_array<IsAlphabetRestricted>::swap(a, b);
}
}
#endif

379
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/digest_position_array_base.hpp

@ -0,0 +1,379 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
digest_position_array_base.hpp
Fuzzy digest (position array representation; base class)
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_DIGEST_POSITION_ARRAY_BASE_HPP
#define FFUZZYPP_DIGEST_POSITION_ARRAY_BASE_HPP
#include <cassert>
#include <cstddef>
#include <algorithm>
#include <limits>
#include "base64.hpp"
#include "digest_blocksize.hpp"
#include "digest_data.hpp"
#include "strings/position_array.hpp"
namespace ffuzzy {
template <bool IsAlphabetRestricted>
class digest_position_array_params
{
private:
digest_position_array_params(void) = delete;
digest_position_array_params(const digest_position_array_params&) = delete;
public:
static constexpr const char char_min =
IsAlphabetRestricted ? 0x00 : std::numeric_limits<char>::min();
static constexpr const char char_max =
IsAlphabetRestricted ? 0x3f : std::numeric_limits<char>::max();
static constexpr const bool is_available =
strings::is_auto_position_array_available<digest_params::max_blockhash_len, char, char_min, char_max>::value;
};
// Friend classes for digest_data class
enum struct comparison_version;
namespace internal
{
template <comparison_version> class digest_comparison_base;
}
template <comparison_version> class digest_comparison;
template <bool IsAlphabetRestricted>
class digest_position_array_base
{
public:
typedef strings::auto_position_array<
digest_params::max_blockhash_len, char,
digest_position_array_params<IsAlphabetRestricted>::char_min,
digest_position_array_params<IsAlphabetRestricted>::char_max
> traits_type;
typedef typename traits_type::type pa_type;
typedef typename traits_type::int_type int_type;
// Data structure
private:
pa_type blkhash1;
pa_type blkhash2;
blockhash_len_t blkhash1_len;
blockhash_len_t blkhash2_len;
digest_blocksize_t blksize;
public:
size_t blockhash1_len(void) const noexcept { return blkhash1_len; }
size_t blockhash2_len(void) const noexcept { return blkhash2_len; }
unsigned long blocksize(void) const noexcept { return blksize; }
const pa_type& blockhash1_array(void) const noexcept { return blkhash1; }
const pa_type& blockhash2_array(void) const noexcept { return blkhash2; }
bool is_short(void) const noexcept { return blkhash2_len <= digest_params::max_blockhash_len / 2; }
// "Initialization" and assignment
public:
digest_position_array_base(void) noexcept = default; // initialize to undefined state
digest_position_array_base(const digest_position_array_base& other) noexcept
: blkhash1(other.blkhash1)
, blkhash2(other.blkhash2)
, blkhash1_len(other.blkhash1_len)
, blkhash2_len(other.blkhash2_len)
, blksize(other.blksize)
{
#ifdef FFUZZYPP_DEBUG
assert(other.is_valid());
#endif
}
const digest_position_array_base& operator=(const digest_position_array_base& other) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(other.is_valid());
#endif
blkhash1 = other.blkhash1;
blkhash2 = other.blkhash2;
blkhash1_len = other.blkhash1_len;
blkhash2_len = other.blkhash2_len;
blksize = other.blksize;
return *this;
}
static void swap(digest_position_array_base& a, digest_position_array_base& b) noexcept
{
std::swap(a.blkhash1, b.blkhash1);
std::swap(a.blkhash2, b.blkhash2);
std::swap(a.blkhash1_len, b.blkhash1_len);
std::swap(a.blkhash2_len, b.blkhash2_len);
std::swap(a.blksize, b.blksize);
}
// Construction by digest
protected:
template <bool IsShort>
static void construct(
digest_position_array_base& dest,
const digest_data<IsAlphabetRestricted, IsShort>& src
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(src.is_valid());
#endif
dest.blkhash1.construct(src.digest, src.blkhash1_len);
dest.blkhash2.construct(src.digest+src.blkhash1_len, src.blkhash2_len);
dest.blkhash1_len = src.blkhash1_len;
dest.blkhash2_len = src.blkhash2_len;
dest.blksize = src.blksize;
}
template <bool IsShort>
digest_position_array_base(const digest_data<IsAlphabetRestricted, IsShort>& src) noexcept
{
construct(src);
}
// Validators (for its validness and naturality)
private:
bool is_valid_blockhash_position_array(const pa_type& parray, blockhash_len_t len) const noexcept
{
int_type mask, set_bits;
const int_type* data = parray.bitmap_data();
size_t array_size = parray.array_size;
if (len)
{
mask = int_type(1u) << (len - 1);
mask = mask ^ (-mask);
}
else
{
mask = -1;
}
set_bits = 0;
for (size_t i = 0; i < array_size; i++)
{
int_type D = data[i];
// check for invalid bits "above" length of the string
if (D & mask)
return false;
// check for duplicate bits (e.g. n-th character of the string is BOTH 'A' and 'B')
if (D & set_bits)
return false;
set_bits |= D;
// check for sequences
int_type tmp = D;
for (blockhash_len_t j = 0; j < digest_params::max_blockhash_sequence; j++)
{
tmp <<= 1;
tmp &= D;
}
if (tmp)
return false;
}
// check if set_bits is now "all valid bits"
if (len)
{
mask = int_type(1u) << (len - 1);
mask = mask | (mask - 1);
}
else
{
mask = 0;
}
if (mask != set_bits)
return false;
return true;
}
bool is_natural_blockhash_position_array(const pa_type& parray, blockhash_len_t len) const noexcept
{
if (!IsAlphabetRestricted)
{
// check only if IsAlphabetRestricted is false
// (represented by regular characters and non Base64 characters are possible)
int_type mask, set_bits;
if (len)
{
mask = int_type(1u) << (len - 1);
mask = mask | (mask - 1);
}
else
{
set_bits = 0;
}
for (size_t i = 0; i < 64; i++)
set_bits |= parray[base64::values[i]];
// check if all valid bits are set by valid Base64 chareacters
if (mask != set_bits)
return false;
}
return true;
}
public:
bool is_valid(void) const noexcept
{
if (blkhash1_len > digest_params::max_blockhash_len)
return false;
if (blkhash2_len > digest_params::max_blockhash_len)
return false;
if (blksize > 0xfffffffful)
return false;
// Note: digest_position_array_base::is_valid takes time.
if (!is_valid_blockhash_position_array(blkhash1, blkhash1_len))
return false;
if (!is_valid_blockhash_position_array(blkhash2, blkhash2_len))
return false;
return true;
}
bool is_natural(void) const noexcept
{
if (!is_valid())
return false;
if (blkhash1_len < blkhash2_len)
return false;
if (!digest_blocksize::is_natural(blksize))
return false;
if (!digest_blocksize::is_safe_to_double(blksize) && blkhash2_len >= 2)
return false;
// Note: digest_position_array_base::is_natural takes time.
if (!is_natural_blockhash_position_array(blkhash1, blkhash1_len))
return false;
if (!is_natural_blockhash_position_array(blkhash2, blkhash2_len))
return false;
return true;
}
bool is_blocksize_natural(void) const noexcept
{
return digest_blocksize::is_natural(blksize);
}
// Comparison
public:
static bool is_eq_except_blocksize(
const digest_position_array_base& a,
const digest_position_array_base& b
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(a.is_valid());
assert(b.is_valid());
#endif
if (a.blkhash1_len != b.blkhash1_len)
return false;
if (a.blkhash2_len != b.blkhash2_len)
return false;
int_type data_a = a.bitmap_data();
int_type data_b = b.bitmap_data();
for (size_t i = 0; i < pa_type::array_size; i++)
{
if (data_a[i] != data_b[i])
return false;
}
return true;
}
static bool is_eq(
const digest_position_array_base& a,
const digest_position_array_base& b
) noexcept
{
if (a.blksize != b.blksize)
return false;
return is_eq_except_blocksize(a, b);
}
template <bool IsShort>
static bool is_eq_except_blocksize(
const digest_position_array_base& a,
const digest_data<IsAlphabetRestricted, IsShort>& b
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(a.is_valid());
assert(b.is_valid());
#endif
if (a.blkhash1_len != b.blkhash1_len)
return false;
if (a.blkhash2_len != b.blkhash2_len)
return false;
if (a.blksize != b.blksize)
return false;
const char* p = b.digest;
for (blockhash_len_t i = 0; i < b.blkhash1_len; i++)
{
if (!(a.blkhash1[*p++] & (int_type(1u) << i)))
return false;
}
for (blockhash_len_t i = 0; i < b.blkhash2_len; i++)
{
if (!(a.blkhash2[*p++] & (int_type(1u) << i)))
return false;
}
return true;
}
template <bool IsShort>
static bool is_eq(
const digest_position_array_base& a,
const digest_data<IsAlphabetRestricted, IsShort>& b
) noexcept
{
if (a.blksize != b.blksize)
return false;
return is_eq_except_blocksize(a, b);
}
public:
friend bool operator==(const digest_position_array_base& a, const digest_position_array_base& b) noexcept { return is_eq(a, b); }
friend bool operator!=(const digest_position_array_base& a, const digest_position_array_base& b) noexcept { return !is_eq(a, b); }
public:
template <bool IsShort>
friend bool operator==(
const digest_position_array_base& a,
const digest_data<IsAlphabetRestricted, IsShort>& b
) noexcept
{
return is_eq(a, b);
}
template <bool IsShort>
friend bool operator!=(
const digest_position_array_base& a,
const digest_data<IsAlphabetRestricted, IsShort>& b
) noexcept
{
return !is_eq(a, b);
}
template <bool IsShort>
friend bool operator==(
const digest_data<IsAlphabetRestricted, IsShort>& a,
const digest_position_array_base& b
) noexcept
{
return is_eq(b, a);
}
template <bool IsShort>
friend bool operator!=(
const digest_data<IsAlphabetRestricted, IsShort>& a,
const digest_position_array_base& b
) noexcept
{
return !is_eq(b, a);
}
// Friend classes
template <comparison_version> friend class internal::digest_comparison_base;
template <comparison_version> friend class digest_comparison;
};
}
#endif

83
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/rolling_hash.hpp

@ -0,0 +1,83 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
rolling_hash.hpp
Rolling hash implementation (without known bugs)
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_ROLLING_HASH_HPP
#define FFUZZYPP_ROLLING_HASH_HPP
#include <cstddef>
#include <cstdint>
namespace ffuzzy {
class rolling_hash
{
public:
static constexpr const uint_least32_t window_size = 7;
static_assert(window_size != 0, "window_size must not be zero.");
protected:
uint_least32_t h1, h2, h3;
uint_least32_t n;
unsigned char window[window_size];
public:
void reset(void) noexcept
{
h1 = h2 = h3 = n = 0;
for (size_t i = 0; i < window_size; i++)
window[i] = 0;
}
void update(unsigned char c) noexcept
{
uint_least32_t C(c);
h2 = h2 - h1 + window_size * C;
h1 = h1 + C - window[n];
h3 = (h3 << 5) ^ C;
window[n] = c;
n++;
if (n == window_size)
n = 0;
}
uint_least32_t sum(void) const noexcept
{
return (h1 + h2 + h3) & uint_least32_t(0xfffffffful);
}
public:
rolling_hash(void) noexcept
{
reset();
}
};
}
#endif

87
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/rolling_hash_ssdeep.hpp

@ -0,0 +1,87 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
rolling_hash_ssdeep.hpp
Rolling hash implementation (with known bug in ssdeep)
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_ROLLING_HASH_SSDEEP_HPP
#define FFUZZYPP_ROLLING_HASH_SSDEEP_HPP
#include <cstddef>
#include <cstdint>
#include "rolling_hash.hpp"
namespace ffuzzy {
// rolling_hash with known rolling-hash bug on ssdeep
class rolling_hash_ssdeep
{
public:
static constexpr const uint_least32_t window_size = rolling_hash::window_size;
private:
uint_least32_t h1, h2, h3;
uint_least32_t n;
unsigned char window[window_size];
public:
void update(unsigned char c) noexcept
{
// emulate bug on ssdeep
uint_least32_t C(c);
h2 = h2 - h1 + window_size * C;
h1 = h1 + C - window[n % window_size];
h3 = (h3 << 5) ^ C;
window[n % window_size] = c;
n++;
if ((n & uint_least32_t(0xfffffffful)) == 0)
n = 0;
}
public:
void reset(void) noexcept
{
h1 = h2 = h3 = n = 0;
for (size_t i = 0; i < window_size; i++)
window[i] = 0;
}
uint_least32_t sum(void) const noexcept
{
return (h1 + h2 + h3) & uint_least32_t(0xfffffffful);
}
public:
rolling_hash_ssdeep(void) noexcept
{
reset();
}
};
}
#endif

345
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/strings/common_substr.hpp

@ -0,0 +1,345 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
strings/common_substr.hpp
Utility to find common substring in two strings
CREDITS OF ORIGINAL VERSION OF SSDEEP
Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2006 ManTech International Corporation
Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
CREDIT OF MODIFIED PORTIONS (HASHARRAY ALGORITHM)
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
CREDIT OF ADDED PORTIONS (BIT-PARALLEL ALGORITHM)
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
*/
#ifndef FFUZZYPP_STRINGS_COMMON_SUBSTR_HPP
#define FFUZZYPP_STRINGS_COMMON_SUBSTR_HPP
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <limits>
#include <type_traits>
#include "../rolling_hash.hpp"
#include "position_array.hpp"
namespace ffuzzy {
namespace strings {
namespace internal
{
template <size_t SubstrSize>
class common_substr_hasharray_impl
{
private:
common_substr_hasharray_impl(void) = delete;
common_substr_hasharray_impl(const common_substr_hasharray_impl&) = delete;
public:
static constexpr const size_t substr_size = SubstrSize;
static_assert(0 < substr_size, "substr_size must be nonzero.");
static_assert(substr_size >= rolling_hash::window_size,
"substr_size must be equal or greater than window_size.");
public:
static bool match_long_buf(
const char* s1, size_t s1len,
const char* s2, size_t s2len,
uint_least32_t* hashes_buf
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1);
assert(s2);
assert(s1len >= substr_size);
assert(s2len >= substr_size);
#endif
rolling_hash r;
// compute rolling hashes for each index of s1
for (size_t i = 0; i < substr_size - 1; i++)
r.update(static_cast<unsigned char>(s1[i]));
for (size_t i = substr_size - 1; i < s1len; i++)
{
r.update(static_cast<unsigned char>(s1[i]));
hashes_buf[i - (substr_size - 1)] = r.sum();
}
s1len -= (substr_size - 1);
// compute rolling hashes for each index of s2
r.reset();
for (size_t j = 0; j < substr_size - 1; j++)
r.update(static_cast<unsigned char>(s2[j]));
for (size_t j = 0; j < s2len - (substr_size - 1); j++)
{
r.update(static_cast<unsigned char>(s2[j + (substr_size - 1)]));
uint_least32_t h = r.sum();
for (size_t i = 0; i < s1len; i++)
{
// make sure we actually have common substring if hash matches
if (hashes_buf[i] == h && !memcmp(s1 + i, s2 + j, substr_size))
return true;
}
}
return false;
}
};
template <
size_t SubstrSize,
size_t MaxSize = std::numeric_limits<size_t>::max()
>
class common_substr_bitparallel_impl
{
private:
common_substr_bitparallel_impl(void) = delete;
common_substr_bitparallel_impl(const common_substr_bitparallel_impl&) = delete;
public:
static constexpr const size_t substr_size = SubstrSize;
static constexpr const size_t max_size = MaxSize;
static_assert(0 < substr_size, "substr_size must be nonzero.");
static_assert(0 < max_size, "max_size must be nonzero.");
public:
template <typename TBitmap, char CMin, char CMax>
static bool match(
const position_array<TBitmap, char, CMin, CMax>& s1,
const char* s2, size_t s2len
) noexcept
{
typedef position_array<TBitmap, char, CMin, CMax> pa_type;
#ifdef FFUZZYPP_DEBUG
assert(s2);
assert(s2len >= substr_size);
assert(s2len <= max_size);
#endif
// position array is too short to have such substrings
if (pa_type::max_strlen < substr_size)
return false;
size_t r = substr_size - 1;
while (true)
{
size_t l = r - (substr_size - 1);
// we must reverse s2 because bitmap of s1 is reversed.
const char* ch = &s2[s2len - 1 - r];
TBitmap D = s1[*ch];
while (D)
{
r--;
D = (D << 1) & s1[*++ch];
if (r == l && D)
return true;
}
// Boyer-Moore-like skipping
if (max_size - 1 <= std::numeric_limits<size_t>::max() - substr_size)
{
// (max_size - 1) + substr_size <= max(size_t)
r += substr_size;
if (r >= s2len)
break;
}
else
{
// (max_size - 1) + substr_size > max(size_t)
// which means we cannot safely perform r += substr_size first (very unlikely)
if (r >= s2len - substr_size)
break;
r += substr_size;
}
}
return false;
}
};
}
template <size_t MaxSize, size_t SubstrSize>
class common_substr_hasharray
{
private:
common_substr_hasharray(void) = delete;
common_substr_hasharray(const common_substr_hasharray&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static constexpr const size_t substr_size = SubstrSize;
static_assert(0 < substr_size, "substr_size must be nonzero.");
static_assert(substr_size <= max_size, "substring size must not be greater than the maximum size.");
public:
static bool match(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1);
assert(s2);
assert(s1len <= max_size);
#endif
uint_least32_t hashes[max_size - (substr_size - 1)];
if (s1len < substr_size)
return false;
if (s2len < substr_size)
return false;
return internal
::common_substr_hasharray_impl<substr_size>
::match_long_buf(s1, s1len, s2, s2len, hashes);
}
};
template <typename TBitmap, char CMin, char CMax, size_t MaxSize, size_t SubstrSize>
class common_substr_bitparallel
{
private:
common_substr_bitparallel(void) = delete;
common_substr_bitparallel(const common_substr_bitparallel&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static constexpr const size_t substr_size = SubstrSize;
static_assert(0 < substr_size, "substr_size must be nonzero.");
static_assert(substr_size <= max_size, "substring size must not be greater than the maximum size.");
static_assert(max_size <= position_array<TBitmap, char, CMin, CMax>::max_strlen,
"max_size must not be greater than max_strlen of corresponding position_matrix for efficiency.");
public:
static bool match(
const position_array<TBitmap, char, CMin, CMax>& s1,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s2);
assert(s2len <= max_size);
#endif
if (s2len < substr_size)
return false;
return internal
::common_substr_bitparallel_impl<substr_size, max_size>
::match(s1, s2, s2len);
}
};
template <typename TBitmap, char CMin, char CMax, size_t MaxSize, size_t SubstrSize>
class common_substr_bitparallel_wrapper
{
private:
common_substr_bitparallel_wrapper(void) = delete;
common_substr_bitparallel_wrapper(const common_substr_bitparallel_wrapper&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static constexpr const size_t substr_size = SubstrSize;
static_assert(0 < substr_size, "substr_size must be nonzero.");
static_assert(substr_size <= max_size, "substring size must not be greater than the maximum size.");
static_assert(max_size <= position_array<TBitmap, char, CMin, CMax>::max_strlen,
"max_size must not be greater than max_strlen of corresponding position_matrix for efficiency.");
public:
static bool match(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s2);
assert(s2len <= max_size);
#endif
if (s2len < substr_size)
return false;
position_array<TBitmap, char, CMin, CMax> parray(s1, s1len);
return internal
::common_substr_bitparallel_impl<substr_size, max_size>
::match(parray, s2, s2len);
}
};
namespace internal
{
template <char CMin, char CMax, size_t MaxSize, size_t SubstrSize, bool IsPositionArrayAvailable>
class common_substr_impl_selector;
template <char CMin, char CMax, size_t MaxSize, size_t SubstrSize>
class common_substr_impl_selector<CMin, CMax, MaxSize, SubstrSize, true>
{
private:
common_substr_impl_selector(void) = delete;
common_substr_impl_selector(const common_substr_impl_selector&) = delete;
public:
static bool match(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
typename auto_position_array<MaxSize, char, CMin, CMax>::type parray(s1, s1len);
return common_substr_bitparallel<typename decltype(parray)::bitmap_type,
CMin, CMax, MaxSize, SubstrSize>::match(parray, s2, s2len);
}
};
template <char CMin, char CMax, size_t MaxSize, size_t SubstrSize>
class common_substr_impl_selector<CMin, CMax, MaxSize, SubstrSize, false>
{
private:
common_substr_impl_selector(void) = delete;
common_substr_impl_selector(const common_substr_impl_selector&) = delete;
public:
static bool match(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
return common_substr_hasharray<MaxSize, SubstrSize>::match(s1, s1len, s2, s2len);
}
};
}
template <size_t MaxSize, size_t SubstrSize>
class common_substr_fast
{
private:
common_substr_fast(void) = delete;
common_substr_fast(const common_substr_fast&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static constexpr const size_t substr_size = SubstrSize;
public:
template <
char CMin = std::numeric_limits<char>::min(),
char CMax = std::numeric_limits<char>::max()
>
static bool match(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
return internal::common_substr_impl_selector<
CMin, CMax, max_size, substr_size,
is_auto_position_array_available<MaxSize, char, CMin, CMax>::value
>::match(s1, s1len, s2, s2len);
}
};
}}
#endif

521
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/strings/edit_dist.hpp

@ -0,0 +1,521 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
strings/edit_dist.hpp
Indel distance implementation
Copyright (C) 2014 kikairoya <kikairoya@gmail.com>
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
This program can be used, redistributed or modified under any of
Boost Software License 1.0, GPL v2 or GPL v3
*/
#ifndef FFUZZYPP_STRINGS_EDIT_DIST_HPP
#define FFUZZYPP_STRINGS_EDIT_DIST_HPP
#include <cassert>
#include <cstddef>
#include <algorithm>
#include <limits>
#include <utility>
#include "../utils/safe_int.hpp"
#include "position_array.hpp"
namespace ffuzzy {
namespace strings {
namespace internal
{
template <typename Tcost>
class edit_dist_dp_impl
{
private:
edit_dist_dp_impl(void) = delete;
edit_dist_dp_impl(const edit_dist_dp_impl&) = delete;
public:
typedef Tcost cost_type;
static_assert(
safe_int::contracts::is_unsigned_integral_type<cost_type>(),
"cost_type must be an unsigned integral type.");
private:
static void update_cost_inner(
const char* s1,
const char* s2, size_t s2len,
size_t i,
cost_type* &row1, cost_type* &row2
) noexcept
{
row2[0] = static_cast<cost_type>(i) + 1;
for (size_t j = 0; j < s2len; j++)
{
cost_type cost_a = row1[j+1] + 1;
cost_type cost_d = row2[j] + 1;
cost_type cost_r = row1[j] + (s1[i] == s2[j] ? 0 : 2);
row2[j+1] = std::min(std::min(cost_a, cost_d), cost_r);
}
std::swap(row1, row2);
}
public:
static cost_type cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len,
cost_type* row1, cost_type* row2
) noexcept
{
for (size_t j = 0; j <= s2len; j++)
row1[j] = static_cast<cost_type>(j);
for (size_t i = 0; i < s1len; i++)
update_cost_inner(s1, s2, s2len, i, row1, row2);
return row1[s2len];
}
static cost_type cost_nonempty(
const char* s1, size_t s1len,
const char* s2, size_t s2len,
cost_type* row1, cost_type* row2
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1len > 0);
assert(s2len > 0);
#endif
row1[0] = 1;
for (size_t j = 0; j < s2len; j++)
{
cost_type cost_d = row1[j] + 1;
cost_type cost_r = static_cast<cost_type>(j) + (s1[0] == s2[j] ? 0 : 2);
row1[j+1] = std::min(cost_d, cost_r);
}
for (size_t i = 1; i < s1len; i++)
update_cost_inner(s1, s2, s2len, i, row1, row2);
return row1[s2len];
}
};
template <typename Tcost, size_t MaxSize>
class edit_dist_bitparallel_impl
{
private:
edit_dist_bitparallel_impl(void) = delete;
edit_dist_bitparallel_impl(const edit_dist_bitparallel_impl&) = delete;
public:
typedef Tcost cost_type;
public:
template <typename TBitmap, char CMin, char CMax>
static cost_type cost_nonempty(
const position_array<TBitmap, char, CMin, CMax>& s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
cost_type cur = s1len;
TBitmap msb = TBitmap(1ull) << (s1len - 1);
TBitmap pv = -1;
TBitmap nv = 0;
for (size_t i = 0; i < s2len; i++)
{
TBitmap mt = s1[s2[i]];
TBitmap zd = (((mt & pv) + pv) ^ pv) | mt | nv;
TBitmap nh = pv & zd;
if (nh & msb)
--cur;
TBitmap x = nv | ~(pv | zd) | (pv & ~mt & TBitmap(1ull));
TBitmap y = (pv - nh) >> 1;
/*
i-th bit of ph does not depend on i-th bit of y
(only upper bits of ph are affected).
So, ph does not depend on invalid bit in y.
*/
TBitmap ph = (x + y) ^ y;
if (ph & msb)
++cur;
TBitmap t = (ph << 1) + TBitmap(1ull);
nv = t & zd;
pv = (nh << 1) | ~(t | zd) | (t & (pv - nh));
}
return cur;
}
template <typename TBitmap, char CMin, char CMax>
static cost_type cost(
const position_array<TBitmap, char, CMin, CMax>& s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
return s1len == 0
? s2len
: cost_nonempty(s1, s1len, s2, s2len);
}
};
}
template <typename Tcost, size_t MaxSize>
class edit_dist_dp
{
private:
edit_dist_dp(void) = delete;
edit_dist_dp(const edit_dist_dp&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static_assert(max_size > 0, "max_size must not be zero.");
static_assert(safe_int::safe_add<
safe_int::uvalue<size_t, max_size>,
safe_int::uvalue<size_t, 1>
>::is_valid,
"max_size + 1 must be in range of size_t.");
typedef Tcost cost_type;
static_assert(safe_int::safe_mul<
safe_int::uvalue<cost_type, max_size>,
safe_int::uvalue<cost_type, 2>
>::is_valid,
"max_size * 2 must be in range of cost_type.");
public:
static cost_type cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1len <= max_size);
assert(s2len <= max_size);
#endif
cost_type rows[2][max_size + 1];
return internal::edit_dist_dp_impl<cost_type>::cost(s1, s1len, s2, s2len, rows[0], rows[1]);
}
};
template <typename Tcost, size_t MaxSize>
class edit_dist_nonempty_dp
{
private:
edit_dist_nonempty_dp(void) = delete;
edit_dist_nonempty_dp(const edit_dist_nonempty_dp&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static_assert(max_size > 0, "max_size must not be zero.");
static_assert(safe_int::safe_add<
safe_int::uvalue<size_t, max_size>,
safe_int::uvalue<size_t, 1>
>::is_valid,
"max_size + 1 must be in range of size_t.");
typedef Tcost cost_type;
static_assert(safe_int::safe_mul<
safe_int::uvalue<cost_type, max_size>,
safe_int::uvalue<cost_type, 2>
>::is_valid,
"max_size * 2 must be in range of cost_type.");
public:
static cost_type cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1len <= max_size);
assert(s2len <= max_size);
#endif
cost_type rows[2][max_size + 1];
return internal::edit_dist_dp_impl<cost_type>::cost_nonempty(s1, s1len, s2, s2len, rows[0], rows[1]);
}
};
template <typename Tcost, typename TBitmap, char CMin, char CMax, size_t MaxSize>
class edit_dist_bitparallel
{
private:
edit_dist_bitparallel(void) = delete;
edit_dist_bitparallel(const edit_dist_bitparallel&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static_assert(max_size > 0, "max_size must not be zero.");
static_assert(safe_int::safe_add<
safe_int::uvalue<size_t, max_size>,
safe_int::uvalue<size_t, 1>
>::is_valid,
"max_size + 1 must be in range of size_t.");
typedef Tcost cost_type;
static_assert(safe_int::safe_mul<
safe_int::uvalue<cost_type, max_size>,
safe_int::uvalue<cost_type, 2>
>::is_valid,
"max_size * 2 must be in range of cost_type.");
public:
static cost_type cost(
const position_array<TBitmap, char, CMin, CMax>& s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1len <= max_size);
assert(s2len <= max_size);
#endif
return internal::edit_dist_bitparallel_impl<Tcost, MaxSize>::cost(s1, s1len, s2, s2len);
}
};
template <typename Tcost, typename TBitmap, char CMin, char CMax, size_t MaxSize>
class edit_dist_bitparallel_wrapper
{
private:
edit_dist_bitparallel_wrapper(void) = delete;
edit_dist_bitparallel_wrapper(const edit_dist_bitparallel_wrapper&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static_assert(max_size > 0, "max_size must not be zero.");
static_assert(safe_int::safe_add<
safe_int::uvalue<size_t, max_size>,
safe_int::uvalue<size_t, 1>
>::is_valid,
"max_size + 1 must be in range of size_t.");
typedef Tcost cost_type;
static_assert(safe_int::safe_mul<
safe_int::uvalue<cost_type, max_size>,
safe_int::uvalue<cost_type, 2>
>::is_valid,
"max_size * 2 must be in range of cost_type.");
public:
static cost_type cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1len <= max_size);
assert(s2len <= max_size);
#endif
position_array<TBitmap, char, CMin, CMax> parray(s1, s1len);
return internal::edit_dist_bitparallel_impl<Tcost, MaxSize>::cost(parray, s1len, s2, s2len);
}
};
template <typename Tcost, typename TBitmap, char CMin, char CMax, size_t MaxSize>
class edit_dist_nonempty_bitparallel
{
private:
edit_dist_nonempty_bitparallel(void) = delete;
edit_dist_nonempty_bitparallel(const edit_dist_nonempty_bitparallel&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static_assert(max_size > 0, "max_size must not be zero.");
static_assert(safe_int::safe_add<
safe_int::uvalue<size_t, max_size>,
safe_int::uvalue<size_t, 1>
>::is_valid,
"max_size + 1 must be in range of size_t.");
typedef Tcost cost_type;
static_assert(safe_int::safe_mul<
safe_int::uvalue<cost_type, max_size>,
safe_int::uvalue<cost_type, 2>
>::is_valid,
"max_size * 2 must be in range of cost_type.");
public:
static cost_type cost(
const position_array<TBitmap, char, CMin, CMax>& s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1len <= max_size);
assert(s2len <= max_size);
#endif
return internal::edit_dist_bitparallel_impl<Tcost, MaxSize>::cost_nonempty(s1, s1len, s2, s2len);
}
};
template <typename Tcost, typename TBitmap, char CMin, char CMax, size_t MaxSize>
class edit_dist_nonempty_bitparallel_wrapper
{
private:
edit_dist_nonempty_bitparallel_wrapper(void) = delete;
edit_dist_nonempty_bitparallel_wrapper(const edit_dist_nonempty_bitparallel_wrapper&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
static_assert(max_size > 0, "max_size must not be zero.");
static_assert(safe_int::safe_add<
safe_int::uvalue<size_t, max_size>,
safe_int::uvalue<size_t, 1>
>::is_valid,
"max_size + 1 must be in range of size_t.");
typedef Tcost cost_type;
static_assert(safe_int::safe_mul<
safe_int::uvalue<cost_type, max_size>,
safe_int::uvalue<cost_type, 2>
>::is_valid,
"max_size * 2 must be in range of cost_type.");
public:
static cost_type cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(s1len <= max_size);
assert(s2len <= max_size);
#endif
position_array<TBitmap, char, CMin, CMax> parray(s1, s1len);
return internal::edit_dist_bitparallel_impl<Tcost, MaxSize>::cost_nonempty(parray, s1len, s2, s2len);
}
};
namespace internal
{
template <typename Tcost, char CMin, char CMax, size_t MaxSize, bool IsPositionArrayAvailable>
class edit_dist_impl_selector;
template <typename Tcost, char CMin, char CMax, size_t MaxSize>
class edit_dist_impl_selector<Tcost, CMin, CMax, MaxSize, true>
{
private:
edit_dist_impl_selector(void) = delete;
edit_dist_impl_selector(const edit_dist_impl_selector&) = delete;
public:
static Tcost cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
typename auto_position_array<MaxSize, char, CMin, CMax>::type parray(s1, s1len);
return edit_dist_bitparallel<Tcost,
typename decltype(parray)::bitmap_type, CMin, CMax, MaxSize>::cost(parray, s1len, s2, s2len);
}
static Tcost cost_nonempty(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
typename auto_position_array<MaxSize, char, CMin, CMax>::type parray(s1, s1len);
return edit_dist_nonempty_bitparallel<Tcost,
typename decltype(parray)::bitmap_type, CMin, CMax, MaxSize>::cost(parray, s1len, s2, s2len);
}
};
template <typename Tcost, char CMin, char CMax, size_t MaxSize>
class edit_dist_impl_selector<Tcost, CMin, CMax, MaxSize, false>
{
private:
edit_dist_impl_selector(void) = delete;
edit_dist_impl_selector(const edit_dist_impl_selector&) = delete;
public:
static Tcost cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
return edit_dist_dp<Tcost, MaxSize>::cost(s1, s1len, s2, s2len);
}
static Tcost cost_nonempty(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
return edit_dist_nonempty_dp<Tcost, MaxSize>::cost(s1, s1len, s2, s2len);
}
};
}
template <typename Tcost, size_t MaxSize>
class edit_dist_fast
{
private:
edit_dist_fast(void) = delete;
edit_dist_fast(const edit_dist_fast&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
typedef Tcost cost_type;
public:
template <
char CMin = std::numeric_limits<char>::min(),
char CMax = std::numeric_limits<char>::max()
>
static Tcost cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
return internal::edit_dist_impl_selector<
cost_type, CMin, CMax, max_size,
is_auto_position_array_available<MaxSize, char, CMin, CMax>::value
>::cost(s1, s1len, s2, s2len);
}
};
template <typename Tcost, size_t MaxSize>
class edit_dist_nonempty_fast
{
private:
edit_dist_nonempty_fast(void) = delete;
edit_dist_nonempty_fast(const edit_dist_nonempty_fast&) = delete;
public:
static constexpr const size_t max_size = MaxSize;
typedef Tcost cost_type;
public:
template <
char CMin = std::numeric_limits<char>::min(),
char CMax = std::numeric_limits<char>::max()
>
static Tcost cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
return internal::edit_dist_impl_selector<
cost_type, CMin, CMax, max_size,
is_auto_position_array_available<MaxSize, char, CMin, CMax>::value
>::cost_nonempty(s1, s1len, s2, s2len);
}
};
template <typename Tedit_dist>
class edit_dist_norm
{
private:
edit_dist_norm(void) = delete;
edit_dist_norm(const edit_dist_norm&) = delete;
public:
typedef typename Tedit_dist::cost_type cost_type;
static cost_type cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
// Normalization: make s1 short for better effficiency
if (s1len <= s2len)
return Tedit_dist::cost(s1, s1len, s2, s2len);
else
return Tedit_dist::cost(s2, s2len, s1, s1len);
}
};
template <typename Tedit_dist>
class edit_dist_norm_rev
{
private:
edit_dist_norm_rev(void) = delete;
edit_dist_norm_rev(const edit_dist_norm_rev&) = delete;
public:
typedef typename Tedit_dist::cost_type cost_type;
static cost_type cost(
const char* s1, size_t s1len,
const char* s2, size_t s2len
) noexcept
{
// Reverse normalization: make s2 short for (possibly) worst effficiency
if (s1len <= s2len)
return Tedit_dist::cost(s2, s2len, s1, s1len);
else
return Tedit_dist::cost(s1, s1len, s2, s2len);
}
};
}}
#endif

82
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/strings/nosequences.hpp

@ -0,0 +1,82 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
strings/nosequences.hpp
String utilities with same interface as sequence utilities
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_STRINGS_NOSEQUENCES_HPP
#define FFUZZYPP_STRINGS_NOSEQUENCES_HPP
#include <cstddef>
#include "terminators.hpp"
#include "transform.hpp"
namespace ffuzzy {
namespace strings {
template <typename Ttransform = default_char_transform>
class nosequences
{
private:
nosequences(void) = delete;
nosequences(const nosequences&) = delete;
public:
static constexpr bool has_sequences(const char* buf, size_t size) noexcept
{
return false;
}
static void copy_raw(char* out, const char* in, size_t size) noexcept
{
while (size--)
*out++ = Ttransform::transform(*in++);
}
static size_t copy_elim_sequences(char* out, const char* in, size_t size) noexcept
{
copy_raw(out, in, size);
return size;
}
template <char... terms>
class string_copy
{
private:
string_copy(void) = delete;
string_copy(const string_copy&) = delete;
public:
static bool copy_elim_sequences(char*& out, size_t outsize, const char*& in) noexcept
{
while (outsize--)
{
char ch;
if (terminators<terms...>::isterm(ch = *in))
return true;
in++;
*out++ = Ttransform::transform(ch);
}
if (terminators<terms...>::isterm(*in))
return true;
return false;
}
};
};
}}
#endif

409
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/strings/position_array.hpp

@ -0,0 +1,409 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
strings/position_array.hpp
Position array (for bit-parallel algorithms)
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_STRINGS_POSITION_ARRAY_HPP
#define FFUZZYPP_STRINGS_POSITION_ARRAY_HPP
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <limits>
#include <type_traits>
namespace ffuzzy {
namespace strings {
namespace internal
{
template <typename T>
class digits_on_size
{
private:
digits_on_size(void) = delete;
digits_on_size(const digits_on_size&) = delete;
public:
static constexpr const size_t size =
std::numeric_limits<T>::digits <= std::numeric_limits<size_t>::max()
? std::numeric_limits<T>::digits
: std::numeric_limits<size_t>::max();
};
/*
Template to return guaranteed bit length on unsigned integral types:
General template works only for binary (radix==2) types and
specialized templates work for radix!=2 binary types.
*/
template <typename T>
class guaranteed_bitlen
{
private:
guaranteed_bitlen(void) = delete;
guaranteed_bitlen(const guaranteed_bitlen&) = delete;
private:
static_assert(std::is_integral<T>::value, "T must be an integral type.");
static_assert(std::is_unsigned<T>::value, "T must be an unsigned integral type.");
static_assert(std::numeric_limits<T>::radix == 2, "T must be a binary unsigned integral type.");
public:
static constexpr const size_t size = digits_on_size<T>::size;
};
template <>
class guaranteed_bitlen<unsigned>
{
private:
guaranteed_bitlen(void) = delete;
guaranteed_bitlen(const guaranteed_bitlen&) = delete;
private:
typedef std::numeric_limits<unsigned> limits_type;
public:
static constexpr const size_t size =
limits_type::radix == 2 && limits_type::digits < 16
? digits_on_size<unsigned>::size : 16;
};
template <>
class guaranteed_bitlen<unsigned long>
{
private:
guaranteed_bitlen(void) = delete;
guaranteed_bitlen(const guaranteed_bitlen&) = delete;
private:
typedef std::numeric_limits<unsigned long> limits_type;
public:
static constexpr const size_t size =
limits_type::radix == 2 && limits_type::digits < 32
? digits_on_size<unsigned long>::size : 32;
};
template <>
class guaranteed_bitlen<unsigned long long>
{
private:
guaranteed_bitlen(void) = delete;
guaranteed_bitlen(const guaranteed_bitlen&) = delete;
private:
typedef std::numeric_limits<unsigned long long> limits_type;
public:
static constexpr const size_t size =
limits_type::radix == 2 && limits_type::digits < 64
? digits_on_size<unsigned long long>::size : 64;
};
}
class position_array_params
{
private:
position_array_params(void) = delete;
position_array_params(const position_array_params&) = delete;
public:
#ifdef FFUZZYPP_DISABLE_POSITION_ARRAY
static constexpr const bool is_disabled_by_build = true;
#else
static constexpr const bool is_disabled_by_build = false;
#endif
static constexpr const size_t max_efficient_array_size = 1024;
};
static_assert(position_array_params::max_efficient_array_size >= 64,
"position_array_params::max_efficient_array_size must not be less than 64.");
template <
typename TBitmap,
typename TChar,
TChar CMin = std::numeric_limits<TChar>::min(),
TChar CMax = std::numeric_limits<TChar>::max()
>
class position_array_safety
{
private:
position_array_safety(void) = delete;
position_array_safety(const position_array_safety&) = delete;
public:
static constexpr const bool is_welldefined =
std::is_integral<TBitmap>::value &&
std::is_unsigned<TBitmap>::value &&
std::is_same<TBitmap, decltype(TBitmap(0u) | TBitmap(0u))>::value &&
std::is_integral<TChar>::value &&
(std::numeric_limits<TBitmap>::radix == 2 ||
std::is_same<TBitmap, unsigned>::value ||
std::is_same<TBitmap, unsigned long>::value ||
std::is_same<TBitmap, unsigned long long>::value
) &&
(CMin <= CMax) &&
(std::is_unsigned<TChar>::value
? CMax - CMin <= std::numeric_limits<size_t>::max()
: (0 <= CMin
? std::numeric_limits<intmax_t>::min() + intmax_t(CMin) <= intmax_t(CMax)
: intmax_t(CMax) <= std::numeric_limits<intmax_t>::max() + intmax_t(CMin)
) && intmax_t(CMax) - intmax_t(CMin) <= std::numeric_limits<size_t>::max()
) &&
(size_t(CMax) - size_t(CMin) < std::numeric_limits<size_t>::max()) &&
(sizeof(TBitmap) <= std::numeric_limits<size_t>::max() / (size_t(CMax) - size_t(CMin) + 1u));
public:
static constexpr const bool is_considered_efficient =
!position_array_params::is_disabled_by_build && is_welldefined &&
(size_t(CMax) - size_t(CMin) + 1u) <= position_array_params::max_efficient_array_size;
};
template <
typename TBitmap = unsigned long long,
typename TChar = char,
TChar CMin = std::numeric_limits<TChar>::min(),
TChar CMax = std::numeric_limits<TChar>::max()
>
class position_array
{
private:
static_assert(std::is_integral<TBitmap>::value, "TBitmap must be an integral type.");
static_assert(std::is_unsigned<TBitmap>::value, "TBitmap must be an unsigned integral type.");
static_assert(std::is_same<TBitmap, decltype(TBitmap(0u) | TBitmap(0u))>::value,
"TBitmap must preserve its type after integral promotion.");
static_assert(std::is_integral<TChar>::value, "TChar must be an integral type.");
static_assert(CMin <= CMax, "CMin must not be greater than CMax.");
static_assert(
/*
Because signed to unsigned conversion is well-defined,
this predicate also indicates whether size_t(CMax) - size_t(CMin) is valid.
Note that this predicate does not cover all the case where
char is signed and (CMin - CMax) is greater than the maximum value of intmax_t.
*/
std::is_unsigned<TChar>::value
? CMax - CMin <= std::numeric_limits<size_t>::max()
: (0 <= CMin
? std::numeric_limits<intmax_t>::min() + intmax_t(CMin) <= intmax_t(CMax)
: intmax_t(CMax) <= std::numeric_limits<intmax_t>::max() + intmax_t(CMin)
) && intmax_t(CMax) - intmax_t(CMin) <= std::numeric_limits<size_t>::max(),
"(CMax - CMin) must be in range of both size_t and the widest type with same signedness as TChar.");
static_assert(size_t(CMax) - size_t(CMin) < std::numeric_limits<size_t>::max(),
"(size_t(CMax) - size_t(CMin) + 1) must be in range of size_t.");
static_assert(sizeof(TBitmap) <= std::numeric_limits<size_t>::max() / (size_t(CMax) - size_t(CMin) + 1u),
"(array_size * sizeof(TBitmap)) must be in range of size_t.");
public:
static constexpr const size_t array_size = size_t(CMax) - size_t(CMin) + 1u;
static constexpr const size_t max_strlen = internal::guaranteed_bitlen<TBitmap>::size;
typedef TBitmap bitmap_type;
typedef TChar char_type;
static constexpr const char_type char_min = CMin;
static constexpr const char_type char_max = CMax;
private:
bitmap_type bitmap[array_size];
public:
void reset(void) noexcept
{
memset(bitmap, 0, sizeof(bitmap));
}
void construct_noinit(const char_type* str, size_t len) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(len <= max_strlen);
#endif
for (size_t i = 0; i < len; i++)
{
char_type ch = *str++;
#ifdef FFUZZYPP_DEBUG
assert(char_min <= ch && ch <= char_max);
#endif
bitmap[size_t(ch) - size_t(char_min)] |= bitmap_type(1u) << i;
}
}
void construct_noinit_safe(const char_type* str, size_t len) noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(len <= max_strlen);
#endif
for (size_t i = 0; i < len; i++)
{
char_type ch = *str++;
if (ch < char_min || char_max < ch)
continue;
bitmap[size_t(ch) - size_t(char_min)] |= bitmap_type(1u) << i;
}
}
void construct(const char_type* str, size_t len) noexcept
{
reset();
construct_noinit(str, len);
}
void construct_safe(const char_type* str, size_t len) noexcept
{
reset();
construct_noinit_safe(str, len);
}
public:
bitmap_type bitmap_for(char_type ch) const noexcept
{
#ifdef FFUZZYPP_DEBUG
assert(char_min <= ch && ch <= char_max);
#endif
return bitmap[size_t(ch) - size_t(char_min)];
}
bitmap_type bitmap_for_safe(char_type ch) const noexcept
{
if (ch < char_min || char_max < ch)
return bitmap_type(0u);
return bitmap[size_t(ch) - size_t(char_min)];
}
bitmap_type operator[](char_type ch) const noexcept
{
return bitmap_for(ch);
}
const bitmap_type* bitmap_data(void) const noexcept
{
return bitmap;
}
public:
position_array(void) noexcept = default; // initialize to undefined state
position_array(const position_array& other) noexcept
{
if (bitmap != other.bitmap)
memcpy(bitmap, other.bitmap, sizeof(bitmap));
}
const position_array& operator=(const position_array& other) noexcept
{
if (bitmap != other.bitmap)
memcpy(bitmap, other.bitmap, sizeof(bitmap));
return *this;
}
position_array(const char_type* str, size_t len) noexcept
{
construct(str, len);
}
position_array(const char_type* str, size_t len, bool safe) noexcept
{
if (safe)
construct_safe(str, len);
else
construct(str, len);
}
static void swap(position_array& a, position_array& b) noexcept
{
std::swap(a.bitmap, b.bitmap); // C++11 version of swap
}
};
namespace internal
{
template <size_t MaxSize, typename TChar, TChar CMin, TChar CMax, typename TEnabler = void>
class auto_position_array_internal;
template <size_t MaxSize, typename TChar, TChar CMin, TChar CMax>
class auto_position_array_internal<MaxSize, TChar, CMin, CMax, typename std::enable_if<(
MaxSize > 0 && MaxSize <= 16 && position_array_safety<unsigned, TChar, CMin, CMax>::is_considered_efficient
)>::type>
{
private:
auto_position_array_internal(void);
auto_position_array_internal(const auto_position_array_internal&) = delete;
public:
typedef unsigned int_type;
};
template <size_t MaxSize, typename TChar, TChar CMin, TChar CMax>
class auto_position_array_internal<MaxSize, TChar, CMin, CMax, typename std::enable_if<(
MaxSize > 16 && MaxSize <= 32 && position_array_safety<unsigned long, TChar, CMin, CMax>::is_considered_efficient
)>::type>
{
private:
auto_position_array_internal(void);
auto_position_array_internal(const auto_position_array_internal&) = delete;
public:
typedef unsigned long int_type;
};
template <size_t MaxSize, typename TChar, TChar CMin, TChar CMax>
class auto_position_array_internal<MaxSize, TChar, CMin, CMax, typename std::enable_if<(
MaxSize > 32 && MaxSize <= 64 && position_array_safety<unsigned long long, TChar, CMin, CMax>::is_considered_efficient
)>::type>
{
private:
auto_position_array_internal(void);
auto_position_array_internal(const auto_position_array_internal&) = delete;
public:
typedef unsigned long long int_type;
};
}
// Predicate to test if automatically-chosen position array available
template <
size_t MaxSize,
typename TChar = char,
TChar CMin = std::numeric_limits<TChar>::min(),
TChar CMax = std::numeric_limits<TChar>::max()
>
struct is_auto_position_array_available
: std::integral_constant<bool, (
(MaxSize > 0 && MaxSize <= 16 && position_array_safety<unsigned, TChar, CMin, CMax>::is_considered_efficient) ||
(MaxSize > 16 && MaxSize <= 32 && position_array_safety<unsigned long, TChar, CMin, CMax>::is_considered_efficient) ||
(MaxSize > 32 && MaxSize <= 64 && position_array_safety<unsigned long long, TChar, CMin, CMax>::is_considered_efficient)
)>
{ };
namespace internal
{
template <size_t MaxSize, typename TChar, TChar CMin, TChar CMax, bool>
class auto_position_array_impl;
template <size_t MaxSize, typename TChar, TChar CMin, TChar CMax>
class auto_position_array_impl<MaxSize, TChar, CMin, CMax, true>
{
private:
auto_position_array_impl(void) = delete;
auto_position_array_impl(const auto_position_array_impl&) = delete;
public:
typedef typename auto_position_array_internal<MaxSize, TChar, CMin, CMax>::int_type int_type;
typedef position_array<int_type, TChar, CMin, CMax> type;
};
template <size_t MaxSize, typename TChar, TChar CMin, TChar CMax>
class auto_position_array_impl<MaxSize, TChar, CMin, CMax, false>
{
private:
auto_position_array_impl(void) = delete;
auto_position_array_impl(const auto_position_array_impl&) = delete;
};
}
// Automatically-chosen position array
template <
size_t MaxSize,
typename TChar = char,
TChar CMin = std::numeric_limits<TChar>::min(),
TChar CMax = std::numeric_limits<TChar>::max()
>
class auto_position_array
: public internal::auto_position_array_impl<
MaxSize, TChar, CMin, CMax,
is_auto_position_array_available<MaxSize, TChar, CMin, CMax>::value
>
{
private:
auto_position_array(void) = delete;
auto_position_array(const auto_position_array&) = delete;
};
}}
#endif

154
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/strings/sequences.hpp

@ -0,0 +1,154 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
strings/sequences.hpp
Utilities to find/eliminate sequences of same characters
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_STRINGS_SEQUENCES_HPP
#define FFUZZYPP_STRINGS_SEQUENCES_HPP
#include <cstddef>
#include "terminators.hpp"
#include "transform.hpp"
#include "../utils/safe_int.hpp"
namespace ffuzzy {
namespace strings {
template <size_t MaxSequenceSize, typename Ttransform = default_char_transform>
class sequences
{
static_assert(safe_int::safe_add<
safe_int::uvalue<size_t, MaxSequenceSize>,
safe_int::uvalue<size_t, 1>
>::value,
"MaxSequenceSize + 1 must be in range of size_t.");
private:
sequences(void) = delete;
sequences(const sequences&) = delete;
public:
static constexpr const size_t max_sequence_size = MaxSequenceSize;
static_assert(max_sequence_size != 0, "max_sequence_size must not be zero.");
public:
static bool has_sequences(const char* buf, size_t size) noexcept
{
if (size <= max_sequence_size)
return false;
size_t seq = 0;
char prev = *buf++;
while (--size)
{
char curr = *buf++;
if (curr == prev)
{
if (++seq == max_sequence_size)
return true;
}
else
{
seq = 0;
prev = curr;
}
}
return false;
}
static size_t copy_elim_sequences(char* out, const char* in, size_t size) noexcept
{
if (size <= max_sequence_size)
{
for (size_t i = 0; i < size; i++)
*out++ = Ttransform::transform(*in++);
return size;
}
size_t csz = 1;
size_t seq = 0;
char prev = *in++;
*out++ = Ttransform::transform(prev);
while (--size)
{
char curr = *in++;
if (curr == prev)
{
if (++seq >= max_sequence_size)
{
seq = max_sequence_size;
continue;
}
*out++ = Ttransform::transform(curr); csz++;
}
else
{
*out++ = Ttransform::transform(curr); csz++;
seq = 0; prev = curr;
}
}
return csz;
}
template <char... terms>
class string_copy
{
private:
string_copy(void) = delete;
string_copy(const string_copy&) = delete;
public:
static bool copy_elim_sequences(char*& out, size_t outsize, const char*& in) noexcept
{
size_t seq = 0;
char prev = *in;
if (terminators<terms...>::isterm(prev))
return true;
if (outsize == 0)
return false;
*out++ = Ttransform::transform(prev); in++; outsize--;
while (true)
{
char curr = *in;
if (terminators<terms...>::isterm(curr))
return true;
in++;
if (curr == prev)
{
if (++seq >= max_sequence_size)
{
seq = max_sequence_size;
continue;
}
if (outsize == 0)
return false;
*out++ = Ttransform::transform(curr); outsize--;
}
else
{
if (outsize == 0)
return false;
*out++ = Ttransform::transform(curr); outsize--;
seq = 0; prev = curr;
}
}
// unreachable
return false;
}
};
};
}}
#endif

58
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/strings/terminators.hpp

@ -0,0 +1,58 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
strings/terminators.hpp
Terminator characters
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_STRINGS_TERMINATORS_HPP
#define FFUZZYPP_STRINGS_TERMINATORS_HPP
namespace ffuzzy {
namespace strings {
template <char...> class terminators;
template <>
class terminators<>
{
private:
terminators(void) = delete;
terminators(const terminators&) = delete;
public:
static bool isterm(char ch) noexcept
{
return !ch;
}
};
template <char c, char... rem>
class terminators<c, rem...>
{
private:
terminators(void) = delete;
terminators(const terminators&) = delete;
public:
static bool isterm(char ch) noexcept
{
return terminators<rem...>::isterm(ch) || ch == c;
}
};
}}
#endif

44
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/strings/transform.hpp

@ -0,0 +1,44 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hashing
strings/transform.hpp
String transformation (char-to-char mapping) utility
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_STRINGS_TRANSFORM_HPP
#define FFUZZYPP_STRINGS_TRANSFORM_HPP
namespace ffuzzy {
namespace strings {
class default_char_transform
{
private:
default_char_transform(void) = delete;
default_char_transform(const default_char_transform&) = delete;
public:
static constexpr char transform(char ch) noexcept
{
return ch;
}
};
}}
#endif

60
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/utils/likely.hpp

@ -0,0 +1,60 @@
/*
ffuzzy++ Helper Libraries
likely.hpp
Branch prediction control macros
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_UTILS_LIKELY_HPP
#define FFUZZYPP_UTILS_LIKELY_HPP
#define FFUZZYPP_LIKELY_PORTABLE(x) (!!(x))
#ifndef FFUZZYPP_DISABLE_COMPILER_BUILTINS
#if !defined(__GNUC__)
#define FFUZZYPP_DISABLE_COMPILER_BUILTINS 1
#elif __GNUC__ < 2
// DISABLE: GNU compiler version < 2.0
#define FFUZZYPP_DISABLE_COMPILER_BUILTINS 1
#elif __GNUC__ >= 3
// ENABLE: GNU compiler version >= 3.0
#elif !defined(__GNUC_MINOR__)
#define FFUZZYPP_DISABLE_COMPILER_BUILTINS 1
#elif __GNUC_MINOR__ <= 95
// DISABLE: GNU compiler version <= 2.95
#define FFUZZYPP_DISABLE_COMPILER_BUILTINS 1
#endif
#endif
#ifdef FFUZZYPP_LIKELY
#undef FFUZZYPP_LIKELY
#endif
#ifdef FFUZZYPP_UNLIKELY
#undef FFUZZYPP_UNLIKELY
#endif
#ifdef FFUZZYPP_DISABLE_COMPILER_BUILTINS
#define FFUZZYPP_LIKELY FFUZZYPP_LIKELY_PORTABLE
#define FFUZZYPP_UNLIKELY FFUZZYPP_LIKELY_PORTABLE
#else
#define FFUZZYPP_LIKELY(x) (__builtin_expect(!!(x), 1))
#define FFUZZYPP_UNLIKELY(x) (__builtin_expect(!!(x), 0))
#endif
#endif

67
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/utils/minmax.hpp

@ -0,0 +1,67 @@
/*
ffuzzy++ Helper Libraries
minmax.hpp
C++14-compatible minimum / maximum library
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_UTILS_MINMAX_HPP
#define FFUZZYPP_UTILS_MINMAX_HPP
/*
std::min and std::max in C++11 are not marked constexpr.
On the other hand, C++14's std::min and std::max are marked constexpr.
This library implements constexpr min and max in C++11
(but compatible with C++14).
However, we won't implement initializer_list variant of
min and max since we aren't using it.
*/
namespace ffuzzy {
namespace minmax {
template <class T>
inline constexpr const T& min(const T& a, const T& b)
{
return b < a ? b : a;
}
template <class T, class Compare>
inline constexpr const T& min(const T& a, const T& b, Compare comp)
{
return comp(b, a) ? b : a;
}
template <class T>
inline constexpr const T& max(const T& a, const T& b)
{
return a < b ? b : a;
}
template <class T, class Compare>
inline constexpr const T& max(const T& a, const T& b, Compare comp)
{
return comp(a, b) ? b : a;
}
}}
#endif

129
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/utils/numeric_digits.hpp

@ -0,0 +1,129 @@
/*
ffuzzy++ Helper Libraries
numeric_digits.hpp
Construction of numeric digits
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_UTILS_NUMERIC_DIGITS_HPP
#define FFUZZYPP_UTILS_NUMERIC_DIGITS_HPP
#include <cstddef>
#include <cstdint>
#include <limits>
#include "safe_int.hpp"
#include "static_assert_query.hpp"
namespace ffuzzy {
namespace numeric_digits {
template <typename T, size_t Base>
static constexpr size_t in_base(T value) noexcept
{
static_assert(
safe_int::contracts::is_unsigned_integral_type<T>(),
"T must be an unsigned integral type.");
static_assert(Base >= 2, "Base must be at least two.");
return (value < Base) ? 1 : 1 + in_base<T, Base>(value / Base);
}
template <typename T>
static constexpr size_t in_decimal(T value) noexcept
{
return in_base<T, 10>(value);
}
// Sanity checks
#ifdef FFUZZYPP_STATIC_SANITY_CHECKS
namespace internal
{
static constexpr uintmax_t expull(uintmax_t base, uintmax_t exponent) noexcept
{
return
exponent == 0 ? 1 :
base * expull(base, exponent-1);
}
static_assert(expull(10, 0) == 1ull, "sanity check for expull(10, 0) failed.");
static_assert(expull(10, 1) == 10ull, "sanity check for expull(10, 1) failed.");
static_assert(expull(10, 2) == 100ull, "sanity check for expull(10, 2) failed.");
static_assert(expull(10, 3) == 1000ull, "sanity check for expull(10, 3) failed.");
static_assert(expull(10, 4) == 10000ull, "sanity check for expull(10, 4) failed.");
static_assert(expull(10, 19) == 10000000000000000000ull, "sanity check for expull(10, 19) failed.");
template <typename T>
struct digits_in_decimal_check
{
private:
template <uintmax_t i>
struct case_digit1
{
static constexpr const bool value = in_decimal<T>(i) == 1;
};
template <uintmax_t i>
struct case_digit2
{
static constexpr const bool value = in_decimal<T>(i + 10u) == 2;
};
template <uintmax_t i>
struct case_many_borders
{
static constexpr const bool value0 =
std::numeric_limits<T>::max() < (expull(10, i+1) - 1)
|| in_decimal<T>(T(expull(10, i+1) - 1)) == i + 1;
static constexpr const bool value1 =
std::numeric_limits<T>::max() < expull(10, i+1)
|| in_decimal<T>(T(expull(10, i+1))) == i + 2;
static constexpr const bool value = value0 && value1;
};
public:
static constexpr const bool value =
static_assert_query::is_all<case_digit1, 10>::value &&
static_assert_query::is_all<case_digit2, 90>::value &&
static_assert_query::is_all<case_many_borders, 19>::value;
};
#ifdef FFUZZYPP_LOCAL_CHK
#error do not define FFUZZYPP_LOCAL_CHK
#endif
#define FFUZZYPP_LOCAL_CHK(typ) \
static_assert(digits_in_decimal_check<typ>::value, \
"sanity checks for digits_in_decimal failed for " #typ ".")
FFUZZYPP_LOCAL_CHK(unsigned char);
FFUZZYPP_LOCAL_CHK(unsigned short);
FFUZZYPP_LOCAL_CHK(unsigned int);
FFUZZYPP_LOCAL_CHK(unsigned long);
FFUZZYPP_LOCAL_CHK(unsigned long long);
FFUZZYPP_LOCAL_CHK(uint_least8_t);
FFUZZYPP_LOCAL_CHK(uint_least16_t);
FFUZZYPP_LOCAL_CHK(uint_least32_t);
FFUZZYPP_LOCAL_CHK(uint_least64_t);
FFUZZYPP_LOCAL_CHK(uint_fast8_t);
FFUZZYPP_LOCAL_CHK(uint_fast16_t);
FFUZZYPP_LOCAL_CHK(uint_fast32_t);
FFUZZYPP_LOCAL_CHK(uint_fast64_t);
FFUZZYPP_LOCAL_CHK(uintmax_t);
FFUZZYPP_LOCAL_CHK(size_t);
#undef FFUZZYPP_LOCAL_CHK
}
#endif
}}
#endif

116
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/utils/ranges.hpp

@ -0,0 +1,116 @@
/*
ffuzzy++ Helper Libraries
ranges.hpp
Value range library
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_UTILS_RANGES_HPP
#define FFUZZYPP_UTILS_RANGES_HPP
#include <limits>
namespace ffuzzy {
namespace ranges {
/*
Inclusive range ([a, b] where a <= b)
*/
template <typename T>
class inclusive
{
T v_begin;
T v_end;
public:
class iterator
{
private:
T value;
T value_end;
bool is_end;
private:
constexpr iterator(
T value,
T value_end,
bool is_end = false
) noexcept
: value(value)
, value_end(value_end)
, is_end(is_end)
{ }
friend class inclusive;
public:
constexpr iterator(const iterator&) noexcept = default;
constexpr T operator*(void) const noexcept
{
return value;
}
/* can be constexpr in C++14 */
#if __cpp_constexpr >= 201304L
constexpr
#endif
iterator& operator++(void) noexcept
{
if (!is_end)
{
if (value == value_end)
is_end = true;
else
++value;
}
return *this;
}
public:
constexpr bool operator==(
const iterator& other
) const noexcept
{
return
value == other.value &&
value_end == other.value_end &&
is_end == other.is_end;
}
constexpr bool operator!=(
const iterator& other
) const noexcept
{
return !(*this == other);
}
};
public:
constexpr iterator begin(void) const noexcept
{
return iterator(v_begin, v_end, false);
}
constexpr iterator end(void) const noexcept
{
return iterator(v_end, v_end, true);
}
public:
constexpr inclusive(T vbegin, T vend) noexcept
: v_begin(vbegin), v_end(vend) { }
constexpr inclusive(void) noexcept
: v_begin(std::numeric_limits<T>::min())
, v_end (std::numeric_limits<T>::max()) { }
};
}}
#endif

371
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/utils/safe_int.hpp

@ -0,0 +1,371 @@
/*
ffuzzy++ Helper Libraries
safe_int.hpp
Safe integer handling utilities
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_UTILS_SAFE_INT_HPP
#define FFUZZYPP_UTILS_SAFE_INT_HPP
#include <cstdint>
#include <limits>
#include <type_traits>
namespace ffuzzy {
namespace safe_int {
namespace contracts
{
template <typename T>
static inline constexpr bool is_integral_type(void) noexcept
{
return std::is_integral<T>::value;
}
template <typename T>
static inline constexpr bool is_signed_integral_type(void) noexcept
{
return is_integral_type<T>() &&
std::is_unsigned<T>::value == false &&
std::numeric_limits<T>::max() > 0 &&
std::numeric_limits<T>::min() < 0;
}
template <typename T>
static inline constexpr bool is_unsigned_integral_type(void) noexcept
{
return is_integral_type<T>() &&
std::is_unsigned<T>::value == true &&
std::numeric_limits<T>::min() == 0;
}
template <typename T>
static inline constexpr bool is_binary_integral_type(void) noexcept
{
return
std::numeric_limits<T>::radix == 2 &&
std::numeric_limits<T>::digits >= 0;
}
// Same implementation but copying for better diagnostics
template <typename T>
struct integral_type
{
static_assert(std::is_integral<T>::value,
"T must be an integral type.");
};
template <typename T>
struct signed_integral_type
: integral_type<T>
{
static_assert(std::is_unsigned<T>::value == false,
"T must be a signed integral type.");
static_assert(std::numeric_limits<T>::max() > 0,
"numeric_limits<T>::max() must be positive for signed integral type.");
static_assert(std::numeric_limits<T>::min() < 0,
"numeric_limits<T>::min() must be negative for signed integral type.");
};
template <typename T>
struct unsigned_integral_type
: integral_type<T>
{
static_assert(std::is_unsigned<T>::value == true,
"T must be an unsigned integral type.");
static_assert(std::numeric_limits<T>::min() == 0,
"numeric_limits<T>::min() must be zero for unsigned integral type.");
};
template <typename T>
struct binary_integral_type
: integral_type<T>
{
static_assert(std::numeric_limits<T>::radix == 2,
"numeric_limits<T>::radix must be 2 for binary integral type.");
static_assert(std::numeric_limits<T>::digits >= 0,
"numeric_limits<T>::digits must not be negative for binary integral type.");
};
}
namespace internal
{
template <typename T1, typename T2>
struct common_unsigned_integral_type
: contracts::unsigned_integral_type<T1>
, contracts::unsigned_integral_type<T2>
{
typedef typename std::conditional<
std::numeric_limits<T1>::max() < std::numeric_limits<T2>::max(),
T2, T1
>::type type;
};
template <typename T>
struct common_unsigned_integral_type<T, T>
{
typedef T type;
};
template <typename Tcommon, typename Tvalue, Tcommon Value, bool IsValid = true>
struct value_base
{
typedef Tcommon common_type;
typedef Tvalue value_type;
static constexpr const bool is_valid = IsValid
&& std::numeric_limits<Tvalue>::min() <= Value
&& std::numeric_limits<Tvalue>::max() >= Value;
static constexpr const Tcommon value_in_common = Value;
static constexpr const Tvalue value =
is_valid ? static_cast<Tvalue>(Value) : 0;
};
}
template <typename T, uintmax_t Value, bool IsValid = true>
struct uvalue
: contracts::unsigned_integral_type<T>
, public internal::value_base<uintmax_t, T, Value, IsValid>
{};
template <typename T, intmax_t Value, bool IsValid = true>
struct svalue
: contracts::signed_integral_type<T>
, public internal::value_base<intmax_t, T, Value, IsValid>
{};
namespace operations
{
template <typename TV1, typename TV2> struct safe_add;
template <typename T1, uintmax_t V1, bool B1, typename T2, uintmax_t V2, bool B2>
struct safe_add<uvalue<T1, V1, B1>, uvalue<T2, V2, B2>>
{
private:
typedef typename internal::common_unsigned_integral_type<T1, T2>::type common_type;
public:
typedef uvalue<common_type, V1 + V2, B1 && B2 && (
std::numeric_limits<common_type>::max() - V1 >= V2
)> type;
};
template <typename TV1, typename TV2> struct safe_sub;
template <typename T1, uintmax_t V1, bool B1, typename T2, uintmax_t V2, bool B2>
struct safe_sub<uvalue<T1, V1, B1>, uvalue<T2, V2, B2>>
{
private:
typedef typename internal::common_unsigned_integral_type<T1, T2>::type common_type;
public:
typedef uvalue<common_type, V1 - V2, B1 && B2 && V1 >= V2> type;
};
template <typename TV1, typename TV2> struct safe_mul;
template <typename T1, uintmax_t V1, bool B1, typename T2, uintmax_t V2, bool B2>
struct safe_mul<uvalue<T1, V1, B1>, uvalue<T2, V2, B2>>
{
private:
typedef typename internal::common_unsigned_integral_type<T1, T2>::type common_type;
public:
typedef uvalue<common_type, V1 * V2, B1 && B2 && (
V1 == 0 || V2 == 0 ||
std::numeric_limits<common_type>::max() / V2 > V1
)> type;
};
template <typename TV1, typename TV2> struct safe_div;
template <typename T1, uintmax_t V1, bool B1, typename T2, uintmax_t V2, bool B2>
struct safe_div<uvalue<T1, V1, B1>, uvalue<T2, V2, B2>>
{
private:
typedef typename internal::common_unsigned_integral_type<T1, T2>::type common_type;
public:
typedef uvalue<common_type, V2 ? V1 / V2 : 0, B1 && B2 && V2 != 0> type;
};
template <typename TVbase, typename TVshift> struct safe_lshift;
template <typename TB, uintmax_t VB, bool BB, typename TS, uintmax_t VS, bool BS>
struct safe_lshift<uvalue<TB, VB, BB>, uvalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
// Refer C++11 specification [3.9.1 p3] for reason that
// conversion to "unsigned" for non-negative "int" numbers is safe.
static constexpr const bool is_valid = BB && BS
&& VS < static_cast<unsigned>(std::numeric_limits<TB>::digits)
&& (std::numeric_limits<TB>::max() >> VS) >= VB;
public:
typedef uvalue<TB, is_valid ? (VB << VS) : 0, is_valid> type;
};
template <typename TB, uintmax_t VB, bool BB, typename TS, intmax_t VS, bool BS>
struct safe_lshift<uvalue<TB, VB, BB>, svalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
static constexpr const bool is_valid = BB && BS
&& VS >= 0
&& VS < std::numeric_limits<TB>::digits
&& (std::numeric_limits<TB>::max() >> VS) >= VB;
public:
typedef uvalue<TB, is_valid ? (VB << VS) : 0, is_valid> type;
};
template <typename TB, intmax_t VB, bool BB, typename TS, uintmax_t VS, bool BS>
struct safe_lshift<svalue<TB, VB, BB>, uvalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
static constexpr const bool is_valid = BB && BS
&& VS < static_cast<unsigned>(std::numeric_limits<TB>::digits)
&& (std::numeric_limits<TB>::max() >> VS) >= VB;
public:
typedef svalue<TB, is_valid ? (VB << VS) : 0, is_valid> type;
};
template <typename TB, intmax_t VB, bool BB, typename TS, intmax_t VS, bool BS>
struct safe_lshift<svalue<TB, VB, BB>, svalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
static constexpr const bool is_valid = BB && BS
&& VS >= 0
&& VS < std::numeric_limits<TB>::digits
&& (std::numeric_limits<TB>::max() >> VS) >= VB;
public:
typedef svalue<TB, is_valid ? (VB << VS) : 0, is_valid> type;
};
template <typename TVbase, typename TVshift> struct safe_rshift;
template <typename TB, uintmax_t VB, bool BB, typename TS, uintmax_t VS, bool BS>
struct safe_rshift<uvalue<TB, VB, BB>, uvalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
static constexpr const bool is_valid = BB && BS
&& VS < static_cast<unsigned>(std::numeric_limits<TB>::digits);
public:
typedef uvalue<TB, is_valid ? (VB >> VS) : 0, is_valid> type;
};
template <typename TB, uintmax_t VB, bool BB, typename TS, intmax_t VS, bool BS>
struct safe_rshift<uvalue<TB, VB, BB>, svalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
static constexpr const bool is_valid = BB && BS
&& VS >= 0
&& VS < std::numeric_limits<TB>::digits;
public:
typedef uvalue<TB, is_valid ? (VB >> VS) : 0, is_valid> type;
};
template <typename TB, intmax_t VB, bool BB, typename TS, uintmax_t VS, bool BS>
struct safe_rshift<svalue<TB, VB, BB>, uvalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
static constexpr const bool is_valid = BB && BS
&& VS < static_cast<unsigned>(std::numeric_limits<TB>::digits);
public:
typedef svalue<TB, is_valid ? (VB >> VS) : 0, is_valid> type;
};
template <typename TB, intmax_t VB, bool BB, typename TS, intmax_t VS, bool BS>
struct safe_rshift<svalue<TB, VB, BB>, svalue<TS, VS, BS>>
: contracts::binary_integral_type<TB>
{
private:
static constexpr const bool is_valid = BB && BS
&& VS >= 0
&& VS < std::numeric_limits<TB>::digits;
public:
typedef svalue<TB, is_valid ? (VB >> VS) : 0, is_valid> type;
};
namespace internal
{
// internal::value_base performs some required tests
template <typename Tnew, typename TV> struct safe_cast_to_u;
template <typename Tnew, typename Told, uintmax_t V, bool B>
struct safe_cast_to_u<Tnew, uvalue<Told, V, B>>
{
typedef uvalue<Tnew, V, B> type;
};
template <typename Tnew, typename Told, intmax_t V, bool B>
struct safe_cast_to_u<Tnew, svalue<Told, V, B>>
{
private:
static constexpr const bool is_valid = B && V >= 0;
public:
typedef uvalue<Tnew,
is_valid ? static_cast<uintmax_t>(V) : 0,
is_valid> type;
};
template <typename Tnew, typename TV> struct safe_cast_to_s;
template <typename Tnew, typename Told, intmax_t V, bool B>
struct safe_cast_to_s<Tnew, svalue<Told, V, B>>
{
typedef svalue<Tnew, V, B> type;
};
template <typename Tnew, typename Told, uintmax_t V, bool B>
struct safe_cast_to_s<Tnew, uvalue<Told, V, B>>
{
private:
static constexpr const bool is_valid = B
&& V <= static_cast<uintmax_t>(std::numeric_limits<intmax_t>::max());
public:
typedef svalue<Tnew,
is_valid ? static_cast<intmax_t>(V) : 0,
is_valid> type;
};
}
template <typename Tnew, typename TV>
struct safe_cast
: public std::conditional<
contracts::is_unsigned_integral_type<Tnew>(),
internal::safe_cast_to_u<Tnew, TV>,
typename std::conditional<
contracts::is_signed_integral_type<Tnew>(),
internal::safe_cast_to_s<Tnew, TV>, void
>::type
>::type {};
}
template <typename TV1, typename TV2>
using safe_add = typename operations::safe_add<TV1, TV2>::type;
template <typename TV1, typename TV2>
using safe_sub = typename operations::safe_sub<TV1, TV2>::type;
template <typename TV1, typename TV2>
using safe_mul = typename operations::safe_mul<TV1, TV2>::type;
template <typename TV1, typename TV2>
using safe_div = typename operations::safe_div<TV1, TV2>::type;
template <typename TVbase, typename TVshift>
using safe_lshift = typename operations::safe_lshift<TVbase, TVshift>::type;
template <typename TVbase, typename TVshift>
using safe_rshift = typename operations::safe_rshift<TVbase, TVshift>::type;
template <typename Tnew, typename TV>
using safe_cast = typename operations::safe_cast<Tnew, TV>::type;
}}
#endif

97
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/utils/static_assert_query.hpp

@ -0,0 +1,97 @@
/*
ffuzzy++ Helper Libraries
static_assert_query.hpp
Basic queries for static assertions
Copyright (C) 2014 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_UTILS_STATIC_ASSERT_QUERY_HPP
#define FFUZZYPP_UTILS_STATIC_ASSERT_QUERY_HPP
#include <cstdint>
namespace ffuzzy {
namespace static_assert_query {
namespace internal
{
template <template <uintmax_t> class T, uintmax_t a, uintmax_t b>
struct is_all_bounds
{
static_assert(a <= b, "bounds must be valid (a must not exceed b).");
/*
For unsigned types,
a/2 + b/2 + ((a%2)+(b%2))/2
is a remplacement of
(a+b)/2
while preventing arithmetic overflow of (a+b).
*/
static constexpr const bool value =
a > b ? false :
is_all_bounds<T, a, a / 2 + b / 2 + ((a % 2) + (b % 2)) / 2>::value &&
is_all_bounds<T, a / 2 + b / 2 + ((a % 2) + (b % 2)) / 2 + 1, b>::value;
};
template <template <uintmax_t> class T, uintmax_t a>
struct is_all_bounds<T, a, a>
{
static constexpr const bool value = T<a>::value;
};
template <template <uintmax_t> class T, uintmax_t a, uintmax_t b>
struct is_any_bounds
{
static_assert(a <= b, "bounds must be valid (a must not exceed b).");
static constexpr const bool value =
a > b ? false :
is_any_bounds<T, a, a / 2 + b / 2 + ((a % 2) + (b % 2)) / 2>::value ||
is_any_bounds<T, a / 2 + b / 2 + ((a % 2) + (b % 2)) / 2 + 1, b>::value;
};
template <template <uintmax_t> class T, uintmax_t a>
struct is_any_bounds<T, a, a>
{
static constexpr const bool value = T<a>::value;
};
}
template <template <uintmax_t> class T, uintmax_t n>
struct is_all
{
static constexpr const bool value = internal::is_all_bounds<T, 0, n-1>::value;
};
template <template <uintmax_t> class T>
struct is_all<T, 0>
{
static constexpr const bool value = true;
};
template <template <uintmax_t> class T, uintmax_t n>
struct is_any
{
static constexpr const bool value = internal::is_any_bounds<T, 0, n-1>::value;
};
template <template <uintmax_t> class T>
struct is_any<T, 0>
{
static constexpr const bool value = false;
};
}}
#endif

67
src/lib/ffuzzypp-release-4.0.1/ffuzzypp/utils/type_modifier.hpp

@ -0,0 +1,67 @@
/*
ffuzzy++ Helper Libraries
type_modifier.hpp
C++11 type modifier utilities
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_UTILS_TYPE_MODIFIER_HPP
#define FFUZZYPP_UTILS_TYPE_MODIFIER_HPP
#include <type_traits>
namespace ffuzzy {
namespace type_mod {
template <typename T, bool IsConst, bool IsVolatile>
struct cv_selector;
template <typename T>
struct cv_selector<T, false, false>
{
typedef T type;
};
template <typename T>
struct cv_selector<T, true, false>
{
typedef const T type;
};
template <typename T>
struct cv_selector<T, false, true>
{
typedef volatile T type;
};
template <typename T>
struct cv_selector<T, true, true>
{
typedef const volatile T type;
};
template <
typename T,
typename Tmatch,
bool IsConst = std::is_const<T>::value,
bool IsVolatile = std::is_volatile<T>::value
>
struct cv_match
{
typedef typename cv_selector<Tmatch, IsConst, IsVolatile>::type type;
};
}}
#endif

7
src/lib/ffuzzypp-release-4.0.1/tests/.gitignore

@ -0,0 +1,7 @@
*
!.gitignore
!Makefile.am
!/*.cpp
!/cases/
!/cases/**/
!/cases/**/*.hpp

76
src/lib/ffuzzypp-release-4.0.1/tests/Makefile.am

@ -0,0 +1,76 @@
#
#
# ffuzzy++ : C++ implementation of fast fuzzy hashing
#
# tests/Makefile.am
# Makefile template for tests
#
# Copyright (C) 2014 Tsukasa OI.
#
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all copies.
#
# 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.
#
#
AM_CPPFLAGS = -I$(top_srcdir)
LIBS = -lgtest -lgtest_main
if ENABLE_TESTS
noinst_PROGRAMS = test-precond test-small
test_precond_SOURCES = test_precond.cpp
test_small_SOURCES = test_small.cpp
if ENABLE_COMPATIBILITY_TESTS
noinst_PROGRAMS += test-compatibility-small test-compatibility-large
test_compatibility_small_SOURCES = test_compatibility_small.cpp
test_compatibility_large_SOURCES = test_compatibility_large.cpp
endif
endif
EXTRA_DIST = \
.gitignore \
cases/precond/digest.hpp \
cases/precond/digest_filesize.hpp \
cases/precond/digest_position_array_base.hpp \
cases/precond/position_array.hpp \
cases/precond/utils/minmax.hpp \
cases/precond/utils/static_assert_query.hpp \
cases/precond/utils/type_modifier.hpp \
cases/compatibility/common/blockhash_comparison_min_matching.hpp \
cases/compatibility/large/blockhash_comparison_min_matching.hpp \
cases/compatibility/small/blockhash_comparison_max_matching.hpp \
cases/compatibility/small/blockhash_comparison_min_matching.hpp \
cases/compatibility/small/digest_comparison_identical.hpp \
cases/compatibility/small/digest_comparison_identical_2_9_1.hpp \
cases/compatibility/small/digest_comparison_identical_2_9_2.hpp \
cases/compatibility/small/digest_data_naturality.hpp \
cases/compatibility/small/digest_generator_forms.hpp \
cases/compatibility/small/digest_generator_initial_guess.hpp \
cases/compatibility/small/digest_generator_nil.hpp \
cases/compatibility/small/digest_generator_rolling_hash_overflow.hpp \
cases/compatibility/small/digest_normalization.hpp \
cases/compatibility/small/digest_position_array_usage.hpp \
cases/compatibility/small/digest_usage.hpp \
cases/small/base64.hpp \
cases/small/common_substr.hpp \
cases/small/context_hash.hpp \
cases/small/digest_blocksize.hpp \
cases/small/digest_comparison_score_cap.hpp \
cases/small/digest_generator.hpp \
cases/small/edit_dist.hpp \
cases/small/nosequences.hpp \
cases/small/position_array.hpp \
cases/small/rolling_hash.hpp \
cases/small/sequences.hpp \
cases/small/terminators.hpp \
cases/small/transform.hpp \
cases/small/utils/minmax.hpp \
cases/small/utils/ranges.hpp

98
src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/common/blockhash_comparison_min_matching.hpp

@ -0,0 +1,98 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hasing
tests/cases/compatibility/common/blockhash_comparison_min_matching.hpp
Tests for minimum matching scores (common parts)
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_TESTCASES_COMPATIBILITY_COMMON_BLOCKHASH_COMPARISON_MIN_MATCHING_HPP
#define FFUZZYPP_TESTCASES_COMPATIBILITY_COMMON_BLOCKHASH_COMPARISON_MIN_MATCHING_HPP
#include <cassert>
#include <string>
class BlockhashComparisonMinMatchingTests : public ::testing::Test
{
protected:
const string s1template;
const string s2template;
const string filler;
private:
static string construct_template(
string::size_type len,
const char c1,
const char c2
)
{
string str;
for (string::size_type i = 0; i < len; i++)
str.append(1, (i & 1) ? c2 : c1);
return str;
}
public:
BlockhashComparisonMinMatchingTests(void)
: ::testing::Test()
, s1template(construct_template(digest_params::max_blockhash_len, '0', '1'))
, s2template(construct_template(digest_params::max_blockhash_len, '2', '3'))
, filler("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
{
}
private:
static string construct_from_template(
const string& template_str,
const string& filler_str,
const string::size_type total_length,
const string::size_type filler_length,
const string::size_type filler_index
)
{
assert(template_str.size() != 0);
assert(template_str.size() >= total_length);
assert(filler_str.size() != 0);
assert(filler_length + filler_index <= total_length);
string str = template_str.substr(0, total_length);
for (string::size_type i = 0; i < filler_length; i++)
str[filler_index + i] = filler_str[i % filler_str.size()];
return str;
}
protected:
string MinMatchingTemplate1(
blockhash_len_t len,
blockhash_len_t index
)
{
return construct_from_template(
s1template, filler,
len, blockhash_comparison_params::min_match_len, index
);
}
string MinMatchingTemplate2(
blockhash_len_t len,
blockhash_len_t index
)
{
return construct_from_template(
s2template, filler,
len, blockhash_comparison_params::min_match_len, index
);
}
};
#endif

70
src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/large/blockhash_comparison_min_matching.hpp

@ -0,0 +1,70 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hasing
tests/cases/compatibility/large/blockhash_comparison_min_matching.hpp
Tests for minimum matching scores (large)
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_TESTCASES_COMPATIBILITY_LARGE_BLOCKHASH_COMPARISON_MIN_MATCHING_HPP
#define FFUZZYPP_TESTCASES_COMPATIBILITY_LARGE_BLOCKHASH_COMPARISON_MIN_MATCHING_HPP
#include <cassert>
#include <algorithm>
#include <string>
#include "../common/blockhash_comparison_min_matching.hpp"
class BlockhashComparisonMinMatchingTestsWithBlocksizeIndex
: public BlockhashComparisonMinMatchingTests
, public ::testing::WithParamInterface<unsigned>
{
};
TEST_P(BlockhashComparisonMinMatchingTestsWithBlocksizeIndex, MinMatchingScore)
{
for (blockhash_len_t s1len = blockhash_comparison_params::min_match_len;
s1len <= digest_params::max_blockhash_len; s1len++)
{
for (blockhash_len_t s1idx = 0; s1idx <= s1len - blockhash_comparison_params::min_match_len; s1idx++)
{
string s1 = MinMatchingTemplate1(s1len, s1idx);
for (blockhash_len_t s2len = blockhash_comparison_params::min_match_len;
s2len <= digest_params::max_blockhash_len; s2len++)
{
for (blockhash_len_t s2idx = 0; s2idx <= s2len - blockhash_comparison_params::min_match_len; s2idx++)
{
string s2 = MinMatchingTemplate2(s2len, s2idx);
unsigned bi = GetParam();
digest_blocksize_t bs = digest_blocksize::at(bi);
ASSERT_EQ(
blockhash_comparison<>::min_matching_score(bs, s1len, s2len),
blockhash_comparison<>::score(s1.data(), s1len, s2.data(), s2len, bs)
);
}
}
}
}
}
INSTANTIATE_TEST_CASE_P(BlocksizeCases, BlockhashComparisonMinMatchingTestsWithBlocksizeIndex,
::testing::Range<unsigned>(0u, digest_blocksize::number_of_blockhashes));
#endif

183
src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/blockhash_comparison_max_matching.hpp

@ -0,0 +1,183 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hasing
tests/cases/compatibility/small/blockhash_comparison_max_matching.hpp
Tests for maximum matching scores
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_BLOCKHASH_COMPARISON_MAX_MATCHING_HPP
#define FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_BLOCKHASH_COMPARISON_MAX_MATCHING_HPP
#include <cassert>
#include <string>
class BlockhashComparisonMaxMatchingTests : public ::testing::Test
{
protected:
const string template_str;
public:
BlockhashComparisonMaxMatchingTests(void)
: ::testing::Test()
, template_str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
{
}
protected:
string MaxMatchingTemplate(blockhash_len_t len)
{
return template_str.substr(0, len);
}
string MaxMatchingTemplateSubstring(
blockhash_len_t len_max,
blockhash_len_t len_min,
blockhash_len_t index
)
{
assert(len_max > len_min);
assert(index <= len_max - len_min);
return template_str.substr(index, len_min);
}
};
TEST_F(BlockhashComparisonMaxMatchingTests, TemplateSanity)
{
EXPECT_EQ("A", MaxMatchingTemplate(1));
EXPECT_EQ("AB", MaxMatchingTemplate(2));
EXPECT_EQ("ABC", MaxMatchingTemplate(3));
EXPECT_EQ("ABCD", MaxMatchingTemplate(4));
EXPECT_EQ("ABCDE", MaxMatchingTemplate(5));
EXPECT_EQ("ABCDEF", MaxMatchingTemplate(6));
EXPECT_EQ("ABCDEFG", MaxMatchingTemplate(7));
EXPECT_EQ("ABCDEFGH", MaxMatchingTemplate(8));
EXPECT_EQ("ABCDEFGHI", MaxMatchingTemplate(9));
EXPECT_EQ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", MaxMatchingTemplate(64));
EXPECT_EQ("AB", MaxMatchingTemplateSubstring(3, 2, 0));
EXPECT_EQ("BC", MaxMatchingTemplateSubstring(3, 2, 1));
EXPECT_EQ("ABC", MaxMatchingTemplateSubstring(7, 3, 0));
EXPECT_EQ("BCD", MaxMatchingTemplateSubstring(7, 3, 1));
EXPECT_EQ("CDE", MaxMatchingTemplateSubstring(7, 3, 2));
EXPECT_EQ("DEF", MaxMatchingTemplateSubstring(7, 3, 3));
EXPECT_EQ("EFG", MaxMatchingTemplateSubstring(7, 3, 4));
}
TEST_F(BlockhashComparisonMaxMatchingTests, CommutativeProperty)
{
for (blockhash_len_t s1len = blockhash_comparison_params::min_match_len;
s1len <= digest_params::max_blockhash_len; s1len++)
{
for (blockhash_len_t s2len = blockhash_comparison_params::min_match_len;
s2len <= digest_params::max_blockhash_len; s2len++)
{
ASSERT_EQ(
blockhash_comparison<>::uncapped_max_matching_score(s1len, s2len),
blockhash_comparison<>::uncapped_max_matching_score(s2len, s1len)
);
for (unsigned bi = 0; bi < digest_blocksize::number_of_blockhashes; bi++)
{
digest_blocksize_t bs = digest_blocksize::at(bi);
ASSERT_EQ(
blockhash_comparison<>::capped_max_matching_score(bs, s1len, s2len),
blockhash_comparison<>::capped_max_matching_score(bs, s2len, s1len)
);
ASSERT_EQ(
blockhash_comparison<>::max_matching_score(bs, s1len, s2len),
blockhash_comparison<>::max_matching_score(bs, s2len, s1len)
);
}
}
}
}
TEST_F(BlockhashComparisonMaxMatchingTests, MaxMatchingScoreNotEq)
{
for (blockhash_len_t s1len = blockhash_comparison_params::min_match_len;
s1len <= digest_params::max_blockhash_len; s1len++)
{
string s1 = MaxMatchingTemplate(s1len);
for (blockhash_len_t s2len = blockhash_comparison_params::min_match_len; s2len < s1len; s2len++)
{
ASSERT_NE(s1len, s2len);
ASSERT_EQ(
blockhash_comparison<>::uncapped_max_matching_score_le(s2len, s1len),
blockhash_comparison<>::uncapped_max_matching_score(s2len, s1len)
);
for (blockhash_len_t index = 0; index <= s1len - s2len; index++)
{
string s2 = MaxMatchingTemplateSubstring(s1len, s2len, index);
ASSERT_EQ(
blockhash_comparison<>::uncapped_max_matching_score_le(s2len, s1len),
blockhash_comparison<>::uncapped_score(s1.data(), s1len, s2.data(), s2len)
);
for (unsigned bi = 0; bi < digest_blocksize::number_of_blockhashes; bi++)
{
digest_blocksize_t bs = digest_blocksize::at(bi);
ASSERT_EQ(
blockhash_comparison<>::capped_max_matching_score_le(bs, s2len, s1len),
blockhash_comparison<>::capped_max_matching_score(bs, s2len, s1len)
);
ASSERT_EQ(
blockhash_comparison<>::max_matching_score_le(bs, s2len, s1len),
blockhash_comparison<>::max_matching_score(bs, s2len, s1len)
);
ASSERT_EQ(
blockhash_comparison<>::max_matching_score_le(bs, s2len, s1len),
blockhash_comparison<>::score(s1.data(), s1len, s2.data(), s2len, bs)
);
ASSERT_EQ(
blockhash_comparison<>::max_matching_score_le(bs, s2len, s1len),
blockhash_comparison<>::capped_max_matching_score_le(bs, s2len, s1len)
);
}
}
}
}
}
TEST_F(BlockhashComparisonMaxMatchingTests, MaxMatchingScoreEq)
{
for (blockhash_len_t slen = blockhash_comparison_params::min_match_len;
slen <= digest_params::max_blockhash_len; slen++)
{
ASSERT_EQ(
blockhash_comparison<>::uncapped_max_matching_score_le(slen, slen),
blockhash_comparison<>::uncapped_max_matching_score(slen, slen)
);
string s = MaxMatchingTemplate(slen);
ASSERT_EQ(
blockhash_comparison<>::uncapped_max_matching_score_le(slen, slen),
blockhash_comparison<>::uncapped_score(s.data(), slen, s.data(), slen)
);
for (unsigned bi = 0; bi < digest_blocksize::number_of_blockhashes; bi++)
{
digest_blocksize_t bs = digest_blocksize::at(bi);
ASSERT_EQ(
blockhash_comparison<>::capped_max_matching_score_le(bs, slen, slen),
blockhash_comparison<>::score(s.data(), slen, s.data(), slen, bs)
);
ASSERT_EQ(
blockhash_comparison<>::max_matching_score_le(bs, slen, slen),
blockhash_comparison<>::score_identical(slen, bs)
);
}
}
}
#endif

144
src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/blockhash_comparison_min_matching.hpp

@ -0,0 +1,144 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hasing
tests/cases/compatibility/small/blockhash_comparison_min_matching.hpp
Tests for minimum matching scores (small)
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_BLOCKHASH_COMPARISON_MIN_MATCHING_HPP
#define FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_BLOCKHASH_COMPARISON_MIN_MATCHING_HPP
#include <cassert>
#include <algorithm>
#include <string>
#include "../common/blockhash_comparison_min_matching.hpp"
TEST_F(BlockhashComparisonMinMatchingTests, TemplateSanity)
{
if (s1template.size() >= 2)
{
EXPECT_EQ("01", s1template.substr(0, 2));
EXPECT_EQ("23", s2template.substr(0, 2));
}
if (s1template.size() >= 8)
{
EXPECT_EQ("01010101", s1template.substr(0, 8));
EXPECT_EQ("23232323", s2template.substr(0, 8));
}
EXPECT_EQ("ABCDEFG", MinMatchingTemplate1(7, 0));
EXPECT_EQ("ABCDEFG", MinMatchingTemplate2(7, 0));
EXPECT_EQ("ABCDEFG1010101010101", MinMatchingTemplate1(20, 0));
EXPECT_EQ("0ABCDEFG010101010101", MinMatchingTemplate1(20, 1));
EXPECT_EQ("01ABCDEFG10101010101", MinMatchingTemplate1(20, 2));
EXPECT_EQ("010ABCDEFG0101010101", MinMatchingTemplate1(20, 3));
EXPECT_EQ("0101ABCDEFG101010101", MinMatchingTemplate1(20, 4));
EXPECT_EQ("01010ABCDEFG01010101", MinMatchingTemplate1(20, 5));
EXPECT_EQ("010101ABCDEFG1010101", MinMatchingTemplate1(20, 6));
EXPECT_EQ("0101010ABCDEFG010101", MinMatchingTemplate1(20, 7));
EXPECT_EQ("01010101ABCDEFG10101", MinMatchingTemplate1(20, 8));
EXPECT_EQ("010101010ABCDEFG0101", MinMatchingTemplate1(20, 9));
EXPECT_EQ("0101010101ABCDEFG101", MinMatchingTemplate1(20, 10));
EXPECT_EQ("01010101010ABCDEFG01", MinMatchingTemplate1(20, 11));
EXPECT_EQ("010101010101ABCDEFG1", MinMatchingTemplate1(20, 12));
EXPECT_EQ("0101010101010ABCDEFG", MinMatchingTemplate1(20, 13));
EXPECT_EQ("ABCDEFG3232323232323", MinMatchingTemplate2(20, 0));
EXPECT_EQ("2ABCDEFG232323232323", MinMatchingTemplate2(20, 1));
EXPECT_EQ("23ABCDEFG32323232323", MinMatchingTemplate2(20, 2));
EXPECT_EQ("232ABCDEFG2323232323", MinMatchingTemplate2(20, 3));
EXPECT_EQ("2323ABCDEFG323232323", MinMatchingTemplate2(20, 4));
EXPECT_EQ("23232ABCDEFG23232323", MinMatchingTemplate2(20, 5));
EXPECT_EQ("232323ABCDEFG3232323", MinMatchingTemplate2(20, 6));
EXPECT_EQ("2323232ABCDEFG232323", MinMatchingTemplate2(20, 7));
EXPECT_EQ("23232323ABCDEFG32323", MinMatchingTemplate2(20, 8));
EXPECT_EQ("232323232ABCDEFG2323", MinMatchingTemplate2(20, 9));
EXPECT_EQ("2323232323ABCDEFG323", MinMatchingTemplate2(20, 10));
EXPECT_EQ("23232323232ABCDEFG23", MinMatchingTemplate2(20, 11));
EXPECT_EQ("232323232323ABCDEFG3", MinMatchingTemplate2(20, 12));
EXPECT_EQ("2323232323232ABCDEFG", MinMatchingTemplate2(20, 13));
EXPECT_EQ("ABCDEFG101010101010101010101010101010101010101010101010101010101", MinMatchingTemplate1(64, 0));
EXPECT_EQ("010101010101010101010101010101010101010101010101010101010ABCDEFG", MinMatchingTemplate1(64, 57));
EXPECT_EQ("ABCDEFG323232323232323232323232323232323232323232323232323232323", MinMatchingTemplate2(64, 0));
EXPECT_EQ("232323232323232323232323232323232323232323232323232323232ABCDEFG", MinMatchingTemplate2(64, 57));
}
TEST_F(BlockhashComparisonMinMatchingTests, MinMatchingScoreSmall)
{
for (blockhash_len_t s1len = blockhash_comparison_params::min_match_len;
s1len <= digest_params::max_blockhash_len; s1len++)
{
string s1 = MinMatchingTemplate1(s1len, 0);
for (blockhash_len_t s2len = blockhash_comparison_params::min_match_len;
s2len <= digest_params::max_blockhash_len; s2len++)
{
string s2 = MinMatchingTemplate2(s2len, s2len - blockhash_comparison_params::min_match_len);
for (unsigned bi = 0; bi < digest_blocksize::number_of_blockhashes; bi++)
{
digest_blocksize_t bs = digest_blocksize::at(bi);
ASSERT_EQ(
blockhash_comparison<>::uncapped_min_matching_score(s1len, s2len),
blockhash_comparison<>::uncapped_score(s1.data(), s1len, s2.data(), s2len)
);
ASSERT_EQ(
blockhash_comparison<>::min_matching_score(bs, s1len, s2len),
blockhash_comparison<>::score(s1.data(), s1len, s2.data(), s2len, bs)
);
ASSERT_EQ(
blockhash_comparison<>::min_matching_score(bs, s1len, s2len),
std::min(
blockhash_comparison<>::uncapped_min_matching_score(s1len, s2len),
blockhash_comparison<>::score_cap(bs, s1len, s2len)
)
);
}
}
}
}
TEST_F(BlockhashComparisonMinMatchingTests, MinMatchingScoreLargeSubset)
{
for (blockhash_len_t s1len = blockhash_comparison_params::min_match_len;
s1len <= digest_params::max_blockhash_len; s1len++)
{
for (blockhash_len_t s1idx = 0; s1idx <= s1len - blockhash_comparison_params::min_match_len; s1idx++)
{
string s1 = MinMatchingTemplate1(s1len, s1idx);
for (blockhash_len_t s2len = blockhash_comparison_params::min_match_len;
s2len <= digest_params::max_blockhash_len; s2len++)
{
for (blockhash_len_t s2idx = 0; s2idx <= s2len - blockhash_comparison_params::min_match_len; s2idx++)
{
string s2 = MinMatchingTemplate2(s2len, s2idx);
ASSERT_EQ(
blockhash_comparison<>::uncapped_min_matching_score(s1len, s2len),
blockhash_comparison<>::uncapped_score(s1.data(), s1len, s2.data(), s2len)
);
}
}
}
}
}
#endif

47
src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_comparison_identical.hpp

@ -0,0 +1,47 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hasing
tests/cases/compatibility/small/digest_comparison_identical.hpp
Tests for identical digest comparison (compare with version 2.12)
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_DIGEST_COMPARISON_IDENTICAL_HPP
#define FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_DIGEST_COMPARISON_IDENTICAL_HPP
#include <string>
// Data used in tests are retrieved partially from ssdeep and others from ssdeep 2.9, x86_64
// (because ssdeep 2.12 currently has a critical bug regarding identical digest comparison).
TEST(DigestComparisonIdenticalTests, NormalizationComparisonTest)
{
EXPECT_EQ(100, digest_comparison<>::compare("3:AAAAAAA:", "3:AAAAAAAAAAAAAA:"));
EXPECT_EQ(100, digest_comparison<>::compare("3::AAAAAAA", "3::AAAAAAAAAAAAAA"));
EXPECT_EQ(100, digest_comparison<>::compare("3:AAAAAABCCCCCC:", "3:AAABCCC:"));
EXPECT_EQ( 7, digest_comparison<>::compare("3:AAAAAABCCCCCC:D", "3:AAABCCC:E"));
EXPECT_EQ(100, digest_comparison<>::compare("3::AAAAAABCCCCCC", "3::AAABCCC"));
EXPECT_EQ( 14, digest_comparison<>::compare("3:D:AAAAAABCCCCCC", "3:E:AAABCCC"));
EXPECT_EQ(100, digest_comparison<>::compare(
"3:aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh01234567:",
"3:aaabbbcccdddeeefffggghhh01234567:"
));
}
#endif

2149
src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_comparison_identical_2_9_1.hpp

File diff suppressed because it is too large

46
src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_comparison_identical_2_9_2.hpp

@ -0,0 +1,46 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hasing
tests/cases/compatibility/small/digest_comparison_identical_2_9_2.hpp
Tests for identical digest comparison (compare with version 2.9; part 2)
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_DIGEST_COMPARISON_IDENTICAL_2_9_2_HPP
#define FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_DIGEST_COMPARISON_IDENTICAL_2_9_2_HPP
#include <string>
// Data used in tests are retrieved from ssdeep 2.9, x86_64
TEST_F(DigestComparisonIdenticalTests_2_9, MinimumNormalizationComparisonTest)
{
EXPECT_EQ( 0, digest_comparison<comparison_version::v2_9>::compare("3:AAAAAAA:", "3:AAAAAAAAAAAAAA:"));
EXPECT_EQ( 0, digest_comparison<comparison_version::v2_9>::compare("3::AAAAAAA", "3::AAAAAAAAAAAAAA"));
EXPECT_EQ( 7, digest_comparison<comparison_version::v2_9>::compare("3:AAAAAABCCCCCC:", "3:AAABCCC:"));
EXPECT_EQ( 7, digest_comparison<comparison_version::v2_9>::compare("3:AAAAAABCCCCCC:D", "3:AAABCCC:E"));
EXPECT_EQ( 14, digest_comparison<comparison_version::v2_9>::compare("3::AAAAAABCCCCCC", "3::AAABCCC"));
EXPECT_EQ( 14, digest_comparison<comparison_version::v2_9>::compare("3:D:AAAAAABCCCCCC", "3:E:AAABCCC"));
EXPECT_EQ( 32, digest_comparison<comparison_version::v2_9>::compare(
"3:aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh01234567:",
"3:aaabbbcccdddeeefffggghhh01234567:"
));
}
#endif

47
src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_data_naturality.hpp

@ -0,0 +1,47 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hasing
tests/cases/compatibility/small/digest_data_naturality.hpp
Tests for digest data naturality
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_DIGEST_DATA_NATURALITY_HPP
#define FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_DIGEST_DATA_NATURALITY_HPP
#include <string>
TEST(DigestDataNaturalityTests, NaturalCases)
{
EXPECT_TRUE(digest_t("3::").is_natural());
EXPECT_TRUE(digest_t("3:AA:A").is_natural());
}
TEST(DigestDataNaturalityTests, UnnaturalCases)
{
// block size 4 is not natural
EXPECT_FALSE(digest_t("4::").is_natural());
// second block hash must not be longer than the first one
EXPECT_FALSE(digest_t("3:A:AA").is_natural());
// non-Base64 character may not be included.
EXPECT_FALSE(digest_t("3:*:A").is_natural());
EXPECT_FALSE(digest_t("3:A:*").is_natural());
}
#endif

128
src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_generator_forms.hpp

@ -0,0 +1,128 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hasing
tests/cases/compatibility/small/digest_generator_forms.hpp
Tests for digest generator (result forms)
Copyright (C) 2017 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_DIGEST_GENERATOR_FORMS_HPP
#define FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_DIGEST_GENERATOR_FORMS_HPP
#include <string>
#include "digest_generator_initial_guess.hpp"
TEST(DigestGeneratorResultFormTests, DigestReturningVariantsTest)
{
digest_generator gen;
DigestGeneratorInitialGuessTests::fill_seq(gen, 64, 1536);
EXPECT_EQ("24"
":0000000000000000000000000000000000000000000000000000000000000000"
":0000000000000000000000000000000U",
gen.digest_str()
);
EXPECT_EQ("24"
":0000000000000000000000000000000000000000000000000000000000000000"
":0000000000000000000000000000000U",
gen.digest().pretty()
);
EXPECT_EQ("24:000:000U", gen.digest_normalized().pretty());
// expect digest_long to return non-shortened form
EXPECT_EQ("24"
":0000000000000000000000000000000000000000000000000000000000000000"
":0000000000000000000000000000000000000000000000000000000000000000",
gen.digest_long().pretty()
);
// expect no 'U' at the tail
EXPECT_EQ("24:000:000", gen.digest_long_normalized().pretty());
}
TEST(DigestGeneratorResultFormTests, CopyDigestTest)
{
digest_generator gen;
DigestGeneratorInitialGuessTests::fill_seq(gen, 64, 1536);
digest_t dsn;
digest_unorm_t dsu;
digest_long_t dln;
digest_long_unorm_t dlu;
EXPECT_TRUE(gen.copy_digest(dsn));
EXPECT_EQ("24:000:000U", dsn.pretty());
EXPECT_TRUE(gen.copy_digest(dsu));
EXPECT_EQ("24"
":0000000000000000000000000000000000000000000000000000000000000000"
":0000000000000000000000000000000U",
dsu.pretty()
);
// expect copy_digest to return shortened form
EXPECT_TRUE(gen.copy_digest(dln));
EXPECT_EQ("24:000:000U", dln.pretty());
EXPECT_TRUE(gen.copy_digest(dlu));
EXPECT_EQ("24"
":0000000000000000000000000000000000000000000000000000000000000000"
":0000000000000000000000000000000U",
dlu.pretty()
);
}
TEST(DigestGeneratorResultFormTests, CopyDigestLongNormalizedTest)
{
digest_generator gen;
DigestGeneratorInitialGuessTests::fill_seq(gen, 64, 1536);
digest_long_t dln;
// expect copy_digest_long_normalized to return non-shortened form
EXPECT_TRUE(gen.copy_digest_long_normalized(dln));
EXPECT_EQ("24:000:000", dln.pretty());
}
TEST(DigestGeneratorResultFormTests, CopyDigestLongTest)
{
digest_generator gen;
DigestGeneratorInitialGuessTests::fill_seq(gen, 64, 1536);
digest_long_t dln;
digest_long_unorm_t dlu;
// expect copy_digest_long to return non-shortened form
EXPECT_TRUE(gen.copy_digest_long(dln));
EXPECT_EQ("24:000:000", dln.pretty());
EXPECT_TRUE(gen.copy_digest_long(dlu));
EXPECT_EQ("24"
":0000000000000000000000000000000000000000000000000000000000000000"
":0000000000000000000000000000000000000000000000000000000000000000",
dlu.pretty()
);
}
TEST(DigestGeneratorResultFormTests, CopyDigestNormalizedTest)
{
digest_generator gen;
DigestGeneratorInitialGuessTests::fill_seq(gen, 64, 1536);
digest_unorm_t ds;
digest_long_unorm_t dl;
EXPECT_TRUE((gen.copy_digest_normalized<false, true>(ds)));
EXPECT_EQ("24:000:000U", ds.pretty());
EXPECT_TRUE((gen.copy_digest_normalized<false, false>(dl)));
EXPECT_EQ("24:000:000U", dl.pretty());
EXPECT_TRUE((gen.copy_digest_normalized<false, false, true>(dl)));
EXPECT_EQ("24:000:000U", dl.pretty());
// expect no 'U' at the tail
EXPECT_TRUE((gen.copy_digest_normalized<false, false, false>(dl)));
EXPECT_EQ("24:000:000", dl.pretty());
}
#endif

187
src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_generator_initial_guess.hpp

@ -0,0 +1,187 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hasing
tests/cases/compatibility/small/digest_generator_initial_guess.hpp
Tests for digest generator (regarding initial guess of block size)
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_DIGEST_GENERATOR_INITIAL_GUESS_HPP
#define FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_DIGEST_GENERATOR_INITIAL_GUESS_HPP
#include <string>
class DigestGeneratorInitialGuessTests : public ::testing::Test
{
public:
static void fill_seq(
digest_generator& generator,
unsigned initial_repetition,
size_t size_to_fill
)
{
static const unsigned char zerobuf[4096] = {0};
static const unsigned char seq30[] = { 0xfc, 0x5d, 0x5d, 0x5d, 0x5d, 0xeb, 0xf0 };
for (unsigned i = 0; i < initial_repetition; i++)
generator.update(seq30, sizeof(seq30));
if (size_to_fill < generator.total_size())
FAIL() << "size_to_fill must be equal to or greater than initial fill size.";
digest_filesize_t remaining = size_to_fill - generator.total_size();
while (remaining >= sizeof(zerobuf))
{
generator.update(zerobuf, sizeof(zerobuf));
remaining -= sizeof(zerobuf);
}
generator.update(zerobuf, remaining);
}
};
TEST_F(DigestGeneratorInitialGuessTests, BlockHashIndexGuessedByFilesizeBelowBorder)
{
for (unsigned i = 0; i < digest_blocksize::number_of_blockhashes; i++)
{
EXPECT_EQ(i, digest_generator::blockhash_index_guessed_by_filesize(
digest_generator::guessed_filesize_at(i)
)) << "guessed index for guessed file size at " << i << " should be same as " << i << ".";
}
}
TEST_F(DigestGeneratorInitialGuessTests, BlockHashIndexGuessedByFilesizeAboveBorder)
{
for (unsigned i = 0; i < digest_blocksize::number_of_blockhashes - 1; i++)
{
EXPECT_EQ(i + 1, digest_generator::blockhash_index_guessed_by_filesize(
digest_generator::guessed_filesize_at(i) + 1
)) << "guessed file size must be maximum file size for block size index " << i << ".";
}
}
TEST_F(DigestGeneratorInitialGuessTests, BlockHashIndexGuessedByFilesizeBelowBorderWithStart)
{
for (unsigned j = 0; j < digest_blocksize::number_of_blockhashes; j++)
{
for (unsigned i = 0; i < digest_blocksize::number_of_blockhashes; i++)
{
EXPECT_EQ(std::max(i, j), digest_generator::blockhash_index_guessed_by_filesize(
digest_generator::guessed_filesize_at(i), j))
<< "guessed index for guessed file size at " << i
<< " and start index of" << j << " should be same as "
<< std::max(i, j) << ".";
}
}
}
TEST_F(DigestGeneratorInitialGuessTests, BlockHashIndexGuessedByFilesizeAboveBorderWithStart)
{
for (unsigned j = 0; j < digest_blocksize::number_of_blockhashes; j++)
{
for (unsigned i = 0; i < digest_blocksize::number_of_blockhashes - 1; i++)
{
EXPECT_EQ(std::max(i + 1, j), digest_generator::blockhash_index_guessed_by_filesize(
digest_generator::guessed_filesize_at(i) + 1, j))
<< "guessed file size must be maximum size for block size index " << i
<< " and still guessed block size index must not be less than " << j << ".";
}
}
}
TEST_F(DigestGeneratorInitialGuessTests, InitialBlocksizeGuessFalseTest)
{
digest_generator gen;
for (unsigned index = 2; index < 18; index++)
{
digest_filesize_t sz;
// maximum size for specific block size estimate
sz = digest_generator::guessed_filesize_at(index);
gen.reset();
gen.set_file_size_constant(sz);
fill_seq(gen, 31, sz);
ASSERT_EQ(sz, gen.total_size());
EXPECT_EQ(
string("3:0000000000000000000000000000000:0000000000000000000000000000000"),
gen.digest_str()
);
// ... plus one (next block size? no, for this test)
sz++;
gen.reset();
gen.set_file_size_constant(sz);
fill_seq(gen, 31, sz);
ASSERT_EQ(sz, gen.total_size());
EXPECT_EQ(
string("3:0000000000000000000000000000000:0000000000000000000000000000000"),
gen.digest_str()
);
}
}
TEST_F(DigestGeneratorInitialGuessTests, InitialBlocksizeGuessTrueTest)
{
digest_generator gen;
ASSERT_EQ(12, digest_blocksize::at(2));
ASSERT_EQ(768, digest_generator::guessed_filesize_at(2));
for (unsigned index = 2; index < 18; index++)
{
digest_filesize_t sz;
// maximum size for specific block size estimate
sz = digest_generator::guessed_filesize_at(index);
gen.reset();
gen.set_file_size_constant(sz);
fill_seq(gen, 32, sz);
ASSERT_EQ(sz, gen.total_size());
EXPECT_EQ(
to_string(static_cast<unsigned long>(digest_blocksize::at(index))) +
":00000000000000000000000000000000:00000000000000000000000000000000",
gen.digest_str()
);
gen.reset();
gen.set_file_size_constant(sz);
fill_seq(gen, 64, sz);
ASSERT_EQ(sz, gen.total_size());
EXPECT_EQ(
to_string(static_cast<unsigned long>(digest_blocksize::at(index))) +
":0000000000000000000000000000000000000000000000000000000000000000"
":0000000000000000000000000000000U",
gen.digest_str()
);
// ... plus one (next block size estimate!)
sz++;
gen.reset();
gen.set_file_size_constant(sz);
fill_seq(gen, 32, sz);
ASSERT_EQ(sz, gen.total_size());
EXPECT_EQ(
to_string(static_cast<unsigned long>(digest_blocksize::at(index + 1))) +
":00000000000000000000000000000000:00000000000000000000000000000000",
gen.digest_str()
);
gen.reset();
gen.set_file_size_constant(sz);
fill_seq(gen, 64, sz);
ASSERT_EQ(sz, gen.total_size());
EXPECT_EQ(
to_string(static_cast<unsigned long>(digest_blocksize::at(index + 1))) +
":0000000000000000000000000000000000000000000000000000000000000000"
":0000000000000000000000000000000U",
gen.digest_str()
);
}
}
#endif

38
src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_generator_nil.hpp

@ -0,0 +1,38 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hasing
tests/cases/compatibility/small/digest_generator_nil.hpp
Tests for digest generator (for empty file)
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_DIGEST_GENERATOR_NIL_HPP
#define FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_DIGEST_GENERATOR_NIL_HPP
#include <string>
TEST(DigestGeneratorTests, NilTest)
{
digest_generator gen;
EXPECT_EQ("3::", gen.digest_str());
gen.reset();
EXPECT_EQ("3::", gen.digest_str());
}
#endif

83
src/lib/ffuzzypp-release-4.0.1/tests/cases/compatibility/small/digest_generator_rolling_hash_overflow.hpp

@ -0,0 +1,83 @@
/*
ffuzzy++ : C++ implementation of fast fuzzy hasing
tests/cases/compatibility/small/digest_generator_rolling_hash_overflow.hpp
Tests for digest generator (regarding rolling_hash overflow)
Copyright (C) 2015 Tsukasa OI <floss_ssdeep@irq.a4lg.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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 FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_DIGEST_GENERATOR_ROLLING_HASH_OVERFLOW_HPP
#define FFUZZYPP_TESTCASES_COMPATIBILITY_SMALL_DIGEST_GENERATOR_ROLLING_HASH_OVERFLOW_HPP
#include <string>
// This test case is inspired by fail case from Digest::ssdeep 0.9.3, x86_64.
TEST(DigestGeneratorTests, RollingHashOverflowTest)
{
digest_generator gen;
// if no mod 2^32 on final hash addition, it makes 0x100000004 (blocksize 3)
static const unsigned char ovf1[] = {0x78, 0xfa, 0xb8, 0xfd, 0x22, 0x00};
// if no mod 2^32 on final hash addition, it makes 0x100000001 (blocksize 6)
static const unsigned char ovf2[] = {0xf9, 0xdf, 0x1d, 0x5a, 0xcb, 0x00};
// if no mod 2^32 on final hash addition and XOR-SHIFT hash, it makes a blocksize 3 match
static const unsigned char ovf3[] = {0xb2, 0xe9, 0x10, 0x5b, 0x38, 0x00};
// if no mod 2^32 on final hash addition and XOR-SHIFT hash, it makes a blocksize 3 match
static const unsigned char ovf4[] = {0xff, 0x00, 0x30, 0x43, 0x7a, 0x27, 0x00};
// 6-bytes to wipe rolling hash (7 bytes requied but I chose sequences with last byte zero)
static const unsigned char nil6[6] = {0};
gen.reset();
gen.update(ovf1, sizeof(ovf1));
EXPECT_EQ("3:2:2", gen.digest_str());
gen.reset();
gen.update(ovf1, sizeof(ovf1));
gen.update(nil6, sizeof(nil6));
EXPECT_EQ("3::", gen.digest_str());
gen.reset();
gen.update(ovf2, sizeof(ovf2));
EXPECT_EQ("3:D:D", gen.digest_str());
gen.reset();
gen.update(ovf2, sizeof(ovf2));
gen.update(nil6, sizeof(nil6));
EXPECT_EQ("3::", gen.digest_str());
gen.reset();
gen.update(ovf3, sizeof(ovf3));
EXPECT_EQ("3:3:3", gen.digest_str());
gen.reset();
gen.update(ovf3, sizeof(ovf3));
gen.update(nil6, sizeof(nil6));
EXPECT_EQ("3::", gen.digest_str());
gen.reset();
gen.update(ovf4, sizeof(ovf4));
EXPECT_EQ("3:Q:Q", gen.digest_str());
gen.reset();
gen.update(ovf4, sizeof(ovf4));
gen.update(nil6, sizeof(nil6));
EXPECT_EQ("3::", gen.digest_str());
}
#endif

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save