Project import generated by Copybara.
GitOrigin-RevId: f6a90d367769dbf40a9e332d5262725bd16f0140
diff --git a/.ccmalloc b/.ccmalloc
new file mode 100644
index 0000000..6be9926
--- /dev/null
+++ b/.ccmalloc
@@ -0,0 +1,348 @@
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %%%% generic configureation file for %%%%
+ %%%% the ccmalloc memory profiler %%%%
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ %-----------------------------------------------------------------%
+ % COPY THIS FILE TO `.ccmalloc' in your project or home directory %
+ %-----------------------------------------------------------------%
+
+##############################################################################
+## (C) 1997-1998 Armin Biere, 1998 Johannes Keukelaar
+##############################################################################
+
+%%% `%' and `#' are comments !!!!!!!
+
+% This file must be called `.ccmalloc' and is searched for in the
+% current directory and in the home directory of the user. If it
+% does not exist then the default values mentioned below are used.
+
+% It is also the currently only available user manual ;-) So here
+% is a reading hint. First have a look at the short one line
+% descriptions of each option ...
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% with `file' the executable is specified [a.out]
+% ----------------------------------------------------------------------
+% This should not be necessary for Linux and Solaris because the proc
+% file system can be used to find argv[0].
+%
+% (the rest of this comment only applies to other OS)
+%
+% For other OS you should use this option unless the executable is
+% in the current directory or its name is `a.out'.
+%
+% If you do not specify this then ccmalloc tries to find an executable
+% in the current directory that matches the running program starting
+% with `a.out'. For this process it must call `nm' on each executable
+% file in the directory which may be time consuming. With this option
+% you can speed up this process.
+%
+% You can also specify absolute or relative path names. This is
+% necessary if you do not start your program from the current directory.
+% But you can also simply link or name your program to `a.out'.
+
+%file FILE
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `log' specify the logfile [stderr]
+% ----------------------------------------------------------------------
+% The default is to use stderr. The argument to `log' is the name of
+% the file you want to write to. It can also be `stdout' or `-' which
+% sets stdout as logfile. If the logfile is stdout or stderr and is
+% connected to a terminal then the output is slightly different.
+%
+% For big programs the logfile can be really big. To reduce the size
+% you can use a small chain length (see `chain-length' below). The other
+% possibility is to use compressed logfiles. This can be done by
+% specifying a logfile name with a `.gz' (or a `.Z') suffix. This means
+% that gnuzip (resp. compress) is used to compress the output.
+
+%log FILE
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `logpid' specify the logfile
+% ----------------------------------------------------------------------
+% Can be used alternatively to the `log' command if you want to use
+% ccmalloc for debugging parallel applications where several copies of
+% the program you are debugging must be run simoultaneously. In this
+% case you can not use `log' because you do not want to write to the same
+% log file. Using `logpid' uses a file name ending with the <pid> of
+% the process which means the name is unique even if several copies of
+% your program are run simoultaneously.
+%
+% If you use the compressing suffixes then the <pid> is inserted before
+% the suffix (e.g. `logpid ccmalloc.log.gz' uses `ccmalloc.log.<pid>.gz'
+% as the name for the log file).
+
+%logpid FILE
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `dont-log-chain' skip info about certain chains []
+% ----------------------------------------------------------------------
+% This command may be repeated any number of times. The argument to this
+% command is a comma-separated list of function-or-file-and-line
+% specifications. Garbage allocated from a callchain that contains this
+% subchain anywhere will _not_ be logged.
+%
+% The comma-separated list should not contain any spaces. E.g. not:
+% main, foo, bar
+% but:
+% main,foo,bar
+% A function-or-file-and-line specification is a string followed by an
+% optional colon and number, for example: main or main:14 or main.c or
+% main.c:15. Note that the string is compared with both the function and
+% the file name, if available. If main.c happens to be a function name,
+% that will cause a match (for that string at least).
+% Not specifying a line number will match any line number. If line number
+% information is not available, anything will match!
+% Not specifying a name (e.g. ,,,) will match an unknown function name.
+% Not giving any parameters at all, will match a chain containing at least
+% one unknown function.
+%
+% Note that if you say
+% dont-log-chain wrapper.c
+% _nothing_ will be logged...
+
+%dont-log-chain
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `only-log-chain' skip info about other chains []
+% ----------------------------------------------------------------------
+% The obvious counterpart to dont-log-chain. In this case, only matching
+% chains will be reported. Non-matching chains will not be reported.
+% Can be repeated any number of times; if the chain matches any of the
+% instances, it will be reported.
+
+%only-log-chain
+
+########################################################################
+# #
+# This is the `flag' section #
+# #
+# `set FLAG' is the same as `set FLAG 1' #
+# #
+# The default values are those set below. If `silent' is disabled #
+# then you will find the banner in the log file (or it is listed on #
+# stdout or stderr). The banner describes the current settings of all #
+# these flags. #
+# #
+########################################################################
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% with `only-count' ccmalloc only counts garbage - no call chains [0]
+% ----------------------------------------------------------------------
+% If only-count is set to one then only one additional pointer for
+% each allocated data is used and no call chain is generated. This is
+% the fasted and most space efficient mode ccmalloc can operate
+% in. In this mode you get at least the size of garbage produced.
+%
+% Note that `check-free-space' does not work at all with `only-count'
+% set and over writes (`check-overwrites') are only checked when
+% calling free.
+
+%set only-count 0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `load-dynlibs' load dynamic linked libraries into gdb [0]
+% ----------------------------------------------------------------------
+% If your program is linked with dynamic libraries, function and file
+% name information is not available for addresses in those libraries,
+% unless you set `load-dynlibs' to 1.
+
+%set load-dynlibs 0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `keep-deallocated-data' does not recycle deallocated data [0]
+% ----------------------------------------------------------------------
+% If you enable keep-deallocated-data then all data deallocated with
+% `free' (or `delete' in C++) is not given back to the free store
+% but stays associated with the call chain of its allocation. This is
+% very useful if your program does multiple deallocation of the
+% same data.
+
+%set keep-deallocated-data 0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `check-overwrites' detect overwrites [0]
+% ----------------------------------------------------------------------
+% If you want to detect `off by n bytes' errors you should set
+% `checking-overwrites' to n/4 (on 32-Bit machines).
+%
+% ccmalloc inserts a boundary above allocated data. This boundary
+% consists of `check-overwrites' words. If your program writes to
+% this area then ccmalloc can detect this (see also check-start
+% and check-interval). `ccmalloc' also does checking for overwrites
+% at non word boundaries (e.g. strcpy(malloc(strlen("hello")),"hello");)
+
+%set check-overwrites 0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `check-underwrites' detect overwrites [0]
+% ----------------------------------------------------------------------
+% same with writes below allocated data. You do not have to set this
+% option if you only want detect `off (below) by one' errors because
+% ccmalloc keeps a magic value just before the user data.
+
+%set check-overwrites 0
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `check-free-space' can be used to find dangling pointers. [0]
+% ----------------------------------------------------------------------
+% A very serious type of bug is to write on data that has already been
+% freed. If this happens the free space management of malloc is in
+% trouble and you will perhaps encounter non deterministic behaviour of
+% your program. To test this first enable `keep-deallocated-data' and
+% restart your program. If the problem goes away and ccmalloc does not
+% report anything then you should *also* enable `check-free-space'. Now
+% ccmalloc checks already deallocated data for corruption.
+%
+% Note that to perform this check `keep-deallocated-data' also must
+% be enabled and `only-count' disabled.
+
+%set check-free-space 0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `check-interval' can be used to speed up checks [0]
+% ----------------------------------------------------------------------
+% If check-overwrite, check-underwrites or check-free-space is set then
+% the default is to do `write checks' when data is deallocated and
+% to do `free space checks' when reporting together with
+% `write checks' for garbage. When you want these checks to be
+% performed more often then you should set `check-interval' to a
+% positive number. This number is the interval between the number of
+% calls to free or malloc without performing the checks.
+
+%set check-interval 0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `check-start' can be used to speed up checks [0]
+% ----------------------------------------------------------------------
+% The flag `check-start' delays the start of checks until the given
+% number of calls to free and malloc have occured. Together with
+% `check-interval' you can use a binary search to find an aproximation
+% when a corruption occured! If you simply set check-interval to 1 and
+% check-start to 0 then this will slow done your program too much.
+
+%set check-start 0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `silent' disables banner [0]
+% ----------------------------------------------------------------------
+% If you don't want to see the banner of ccmalloc then set
+% `silent' to 1 (f.e. when logging to stderr)
+
+%set silent
+set silent 1
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `file-info' en/disables file and line number information [1]
+% ----------------------------------------------------------------------
+% If your program was compiled with debugging information (-g) then
+% ccmalloc can generate line number and file info for call chains opening
+% a pipe to gdb. For very big programs this method is slow. In this case
+% you can set `file-info' to zero and you will only get the function
+% names. For SunOS 4.3.1 `nm' does not `demangle' C++ identifiers
+% very well. So gdb is called instead but only if `file-info' is
+% not set to 0.
+
+%set file-info 1
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `continue' if ccmalloc aborts when something weired happened [0]
+% ----------------------------------------------------------------------
+% If the free function of ccmalloc is called with an argument that does
+% not make sense to ccmalloc or that has already been freed then you
+% probably want the program to stop at this point. This is also
+% the default behaviour. But you can force ccmalloc also to ignore
+% this if you set `continue' to 1. This flag also controls the behaviour
+% of ccmalloc when free space is found to be corrupted or a write
+% boundary has been overwritten.
+
+%set continue 0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `chain-length' is the length of the maximal call chain [0 = infinite]
+% ----------------------------------------------------------------------
+% You can restrict the length of call chains by setting `chain-length'
+% to a number greater than zero. If `chain-length' is zero (the default)
+% then chains are as long as possible (on a non x86 system only call
+% chains with a finite maximal length can be generated). For big
+% programs especially if keep-deallocated-data is enabled this can
+% reduce the size of the log file from over 100MB to several MB!
+
+%set chain-length 0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `print-addresses' of data [0]
+% ----------------------------------------------------------------------
+% If you want to see the addresses of the allocated data (and
+% deallocated data if keep-deallocated-data is set to 1) set
+% `print-addresses' to 1.
+
+%set print-addresses 0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `print-on-one-line' shortens log file [0]
+% ----------------------------------------------------------------------
+% The default is to print function names and file/line number info
+% on separate lines. With `print-on-one-line' set 1 all are printed
+% on one line.
+
+set print-on-one-line 1
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `additional-line' enlarges readability [1]
+% ----------------------------------------------------------------------
+% When printing call chains an empty line is printed between to
+% call points. Set `additional-line' to 0 to disable this feature.
+
+set additional-line 0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% `statistics' enables more accurate profiling [0]
+% ----------------------------------------------------------------------
+% Calculate number of allocations and deallocations and bytes also on
+% a per call chain basis. This uses 4 additional pointers for each
+% call chain.
+
+set statistics 0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% set order for sorting of call chains [1] [1]
+% ----------------------------------------------------------------------
+% When printing the report to the log file the call chains are sorted by
+% default with respect to the largest accumulated garbage produced by
+% that call chain. This can be changed with setting `sort-by-wasted'
+% to 0. In this case they are sorted by the number of allocated bytes.
+% If you want the number of allocations (only possible if `statistics'
+% is enabled) as sorting criteria instead then set `sort-by-size' to 0.
+
+%set sort-by-wasted 1
+%set sort-by-size 1
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% report library chains [0]
+% ----------------------------------------------------------------------
+% Some external libraries (like libg++) have memory leaks. On some
+% systems even a call to printf produces a leak. ccmalloc tries to
+% detect this (only heuristically!) and with this flag you can control
+% if leaks produced by such library calls are reported.
+%
+% Since version 0.2.1 some similar effect can be achieved by using
+% `dont-log-chain' with no argument.
+
+%set library-chains 0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% print debugging information [X] (compile time dependend)
+% ----------------------------------------------------------------------
+
+%set debug X
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% align memory on 8 byte boundary [0] (no effect on SunOS or Solaris)
+% ----------------------------------------------------------------------
+
+%set align-8-byte 0
diff --git a/.gdbinit b/.gdbinit
new file mode 100644
index 0000000..d1b715f
--- /dev/null
+++ b/.gdbinit
@@ -0,0 +1 @@
+set print pretty
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c5f9c86
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,74 @@
+rdiff
+*.o
+CMakeCache.txt
+CTestTestfile.cmake
+config.h
+*.cbp
+librsync.so*
+librsync.a
+librsync*.dylib
+Makefile
+CMakeFiles
+*.lo
+.libs
+librsync.la
+librsync-[0-9]*tar.gz
+librsync-[0-9]*/
+/m4/
+tags
+*.dylib
+cmake_install.cmake
+*.la
+doc/Doxyfile
+tests/isprefix.driver
+html
+latex
+Testing
+*.user
+
+# CMake generated Doxygen files
+CMakeDoxyfile.in
+CMakeDoxygenDefaults.cmake
+
+# Editor temp files
+.sw?
+.*.sw?
+*~
+
+# OSX build outputs
+*.dSYM
+
+# Test binaries
+*_test
+*_test.exe
+*_test.exe.manifest
+
+# Performance benchmark binaries
+*_perf
+*_perf.exe
+*_perf.exe.manifest
+
+*.bak
+
+*.tmp
+
+# for rtags
+compile_commands.json
+
+# Cache sometimes leftover by Doxygen,
+# similar to https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=758975
+doxygen_sqlite3.db
+
+# Coverage reports
+*.gcov
+
+# Optional build using http://build-ninja.org
+.ninja_deps
+.ninja_log
+build.ninja
+rules.ninja
+
+# Microsoft Visual Studio build files
+*.sln
+*.vcxproj
+*.vcxproj.filters
diff --git a/.lclintrc b/.lclintrc
new file mode 100644
index 0000000..c6569c9
--- /dev/null
+++ b/.lclintrc
@@ -0,0 +1 @@
+-type +posixlib -predboolint +boolint
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..78e2f9e
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,53 @@
+# "It took the night to believe"
+
+language: c
+
+before_script:
+ - cmake --help
+ - cmake $CMAKE_OPTIONS $CMAKE_GENERATOR .
+
+env:
+ - CTEST_OUTPUT_ON_FAILURE=1
+
+addons:
+ apt:
+ packages:
+ - cmake
+ - libpopt-dev
+ - doxygen
+ - ninja-build
+ homebrew:
+ packages:
+ - popt
+ update: true
+
+script:
+ - cmake --build . --target check
+
+matrix:
+ include:
+ - os: windows
+
+ - os: osx
+ compiler: clang
+
+ - os: linux
+ compiler: gcc
+
+ - os: linux
+ compiler: clang
+
+ - os: linux
+ compiler: clang
+ env: CMAKE_GENERATOR="-G Ninja"
+ script: ninja check doc
+
+ - os: linux
+ compiler: gcc
+ env: CMAKE_OPTIONS="-D BUILD_SHARED_LIBS=OFF"
+
+ - os: linux
+ compiler: gcc
+ env: CMAKE_OPTIONS="-D BUILD_RDIFF=OFF"
+
+# vim: shiftwidth=2 expandtab
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..eaf74e9
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,4 @@
+Martin Pool <mbp@sourcefrog.net>
+Andrew Tridgell <tridge@samba.org>
+Donovan Baarda <abo@minkirri.apana.org.au>
+Adam Schubert <adam.schubert@sg1-game.net>
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..eef942b
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,437 @@
+# Copyright (C) 2015 Adam Schubert <adam.schubert@sg1-game.net>
+# Copyright 2016 Martin Pool
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+project(librsync C)
+cmake_minimum_required(VERSION 3.6)
+
+INCLUDE(CMakeDependentOption)
+include(GNUInstallDirs)
+
+set(LIBRSYNC_MAJOR_VERSION 2)
+set(LIBRSYNC_MINOR_VERSION 3)
+set(LIBRSYNC_PATCH_VERSION 2)
+
+set(LIBRSYNC_VERSION
+ ${LIBRSYNC_MAJOR_VERSION}.${LIBRSYNC_MINOR_VERSION}.${LIBRSYNC_PATCH_VERSION})
+
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+
+if (NOT CMAKE_SYSTEM_PROCESSOR)
+ message(FATAL_ERROR "No target CPU architecture set")
+endif()
+
+if (NOT CMAKE_SYSTEM_NAME)
+ message(FATAL_ERROR "No target OS set")
+endif()
+
+option(BUILD_SHARED_LIBS "Build librsync as a shared library." ON)
+
+set(DO_RS_TRACE 0)
+option(ENABLE_TRACE "Compile in detailed trace messages" OFF)
+if (ENABLE_TRACE)
+ set(DO_RS_TRACE 1)
+endif (ENABLE_TRACE)
+message(STATUS "DO_RS_TRACE=${DO_RS_TRACE}")
+
+# Add an option to include compression support
+option(ENABLE_COMPRESSION "Whether or not to build with compression support" OFF)
+# TODO: Remove this warning when compression is implemented.
+# Consider turning compression ON by default.
+if (ENABLE_COMPRESSION)
+ message(WARNING "Compression support is not functional. See issue #8.")
+endif (ENABLE_COMPRESSION)
+
+include ( CheckIncludeFiles )
+check_include_files ( sys/file.h HAVE_SYS_FILE_H )
+check_include_files ( sys/stat.h HAVE_SYS_STAT_H )
+check_include_files ( sys/types.h HAVE_SYS_TYPES_H )
+check_include_files ( unistd.h HAVE_UNISTD_H )
+check_include_files ( io.h HAVE_IO_H )
+check_include_files ( fcntl.h HAVE_FCNTL_H )
+check_include_files ( mcheck.h HAVE_MCHECK_H )
+check_include_files ( zlib.h HAVE_ZLIB_H )
+check_include_files ( bzlib.h HAVE_BZLIB_H )
+
+# Remove compression support if not needed
+if (NOT ENABLE_COMPRESSION)
+ SET(HAVE_BZLIB_H 0)
+ SET(HAVE_ZLIB_H 0)
+endif (NOT ENABLE_COMPRESSION)
+
+include ( CheckSymbolExists )
+check_symbol_exists ( __func__ "" HAVE___FUNC__ )
+check_symbol_exists ( __FUNCTION__ "" HAVE___FUNCTION__ )
+
+include ( CheckFunctionExists )
+check_function_exists ( fseeko HAVE_FSEEKO )
+check_function_exists ( fseeko64 HAVE_FSEEKO64 )
+check_function_exists ( _fseeki64 HAVE__FSEEKI64 )
+check_function_exists ( fstat64 HAVE_FSTAT64 )
+check_function_exists ( _fstati64 HAVE__FSTATI64 )
+check_function_exists ( fileno HAVE_FILENO )
+check_function_exists ( _fileno HAVE__FILENO )
+
+include(CheckTypeSize)
+check_type_size ( "long" SIZEOF_LONG )
+check_type_size ( "long long" SIZEOF_LONG_LONG )
+check_type_size ( "off_t" SIZEOF_OFF_T )
+check_type_size ( "off64_t" SIZEOF_OFF64_T )
+check_type_size ( "size_t" SIZEOF_SIZE_T )
+check_type_size ( "unsigned int" SIZEOF_UNSIGNED_INT )
+check_type_size ( "unsigned long" SIZEOF_UNSIGNED_LONG )
+check_type_size ( "unsigned short" SIZEOF_UNSIGNED_SHORT )
+
+# Check for printf "%zu" size_t formatting support.
+if(WIN32)
+ # CheckCSourceRuns checking for "%zu" succeeds but still gives warnings on win32.
+ set(HAVE_PRINTF_Z OFF)
+ # Not using unsupported %zu generates warnings about using %I64 with MinGW.
+ # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format")
+ message (STATUS "Compiling to Win32 - printf \"%zu\" size_t formatting support disabled")
+elseif(CMAKE_CROSSCOMPILING)
+ # CheckCSourceRuns doesn't work when cross-compiling; assume C99 compliant support.
+ set(HAVE_PRINTF_Z ON)
+ message (STATUS "Cross compiling - assuming printf \"%zu\" size_t formatting support")
+else()
+ include(CheckCSourceRuns)
+ check_c_source_runs("#include <stdio.h>\nint main(){char o[8];sprintf(o, \"%zu\", (size_t)7);return o[0] != '7';}" HAVE_PRINTF_Z)
+endif()
+
+include (TestBigEndian)
+TEST_BIG_ENDIAN(WORDS_BIGENDIAN)
+if (WORDS_BIGENDIAN)
+ message(STATUS "System is big-endian.")
+else (WORDS_BIGENDIAN)
+ message(STATUS "System is little-endian.")
+endif (WORDS_BIGENDIAN)
+
+# OS X
+if(APPLE)
+ set(CMAKE_MACOSX_RPATH ON)
+ set(CMAKE_SKIP_BUILD_RPATH FALSE)
+ set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
+ set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
+ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+ list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" isSystemDir)
+ if("${isSystemDir}" STREQUAL "-1")
+ set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
+ endif()
+endif()
+
+if (CMAKE_C_COMPILER_ID MATCHES "(Clang|Gnu|GNU)")
+ # TODO: Set -Werror when the build is clean.
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -std=c99 -pedantic")
+ if (CMAKE_C_COMPILER_ID MATCHES "Clang")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sign-conversion")
+ endif()
+elseif(CMAKE_C_COMPILER_ID MATCHES "MSVC")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D_CRT_SECURE_NO_WARNINGS")
+endif()
+
+site_name(BUILD_HOSTNAME)
+
+message (STATUS "PROJECT_NAME = ${PROJECT_NAME}")
+message (STATUS "BUILD_HOSTNAME = ${BUILD_HOSTNAME}")
+message (STATUS "CMAKE_SYSTEM = ${CMAKE_SYSTEM}")
+
+# Find POPT
+find_package(POPT)
+if (POPT_FOUND)
+ message (STATUS "POPT_INCLUDE_DIRS = ${POPT_INCLUDE_DIRS}")
+ message (STATUS "POPT_LIBRARIES = ${POPT_LIBRARIES}")
+ include_directories(${POPT_INCLUDE_DIRS})
+endif (POPT_FOUND)
+
+# Add an option to exclude rdiff executable from build
+# This is useful, because it allows to remove POPT dependency if a user is interested only in the
+# rsync library itself and not in the rdiff executable
+cmake_dependent_option(BUILD_RDIFF "Whether or not to build rdiff executable" ON "POPT_FOUND" OFF)
+
+# Find BZIP
+find_package (BZip2)
+if (BZIP2_FOUND)
+ message (STATUS "BZIP2_INCLUDE_DIRS = ${BZIP2_INCLUDE_DIRS}")
+ message (STATUS "BZIP2_LIBRARIES = ${BZIP2_LIBRARIES}")
+ include_directories(${BZIP2_INCLUDE_DIRS})
+endif (BZIP2_FOUND)
+
+# Find ZLIB
+find_package (ZLIB)
+if (ZLIB_FOUND)
+ message (STATUS "ZLIB_INCLUDE_DIRS = ${ZLIB_INCLUDE_DIRS}")
+ message (STATUS "ZLIB_LIBRARIES = ${ZLIB_LIBRARIES}")
+ include_directories(${ZLIB_INCLUDE_DIRS})
+endif (ZLIB_FOUND)
+
+# Find libb2
+find_package(libb2)
+if (LIBB2_FOUND)
+ message (STATUS "LIBB2_INCLUDE_DIRS = ${LIBB2_INCLUDE_DIRS}")
+ message (STATUS "LIBB2_LIBRARIES = ${LIBB2_LIBRARIES}")
+endif (LIBB2_FOUND)
+
+# Add an option to use LIBB2 if found. It defaults to off because the
+# reference implementation is currently faster.
+cmake_dependent_option(USE_LIBB2 "Use the libb2 blake2 implementation." OFF "LIBB2_FOUND" OFF)
+
+if (USE_LIBB2)
+ message (STATUS "Using libb2 blake2 implementation.")
+ include_directories(${LIBB2_INCLUDE_DIRS})
+ set(blake2_LIBS ${LIBB2_LIBRARIES})
+else (USE_LIBB2)
+ message (STATUS "Using included blake2 implementation.")
+ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/blake2)
+ set(blake2_SRCS src/blake2/blake2b-ref.c)
+endif (USE_LIBB2)
+
+# Doxygen doc generator.
+find_package(Doxygen)
+if(DOXYGEN_FOUND)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile @ONLY)
+ add_custom_target(doc
+ ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Generating API documentation with Doxygen" VERBATIM
+ )
+endif(DOXYGEN_FOUND)
+
+# Code tidy target to reformat code with indent.
+file(GLOB tidy_SRCS src/*.[ch] tests/*.[ch])
+set(TYPE_RE "(\\w+_t)")
+set(CAST_RE "(\\(${TYPE_RE}( \\*+)?\\))")
+add_custom_target(tidy
+ COMMENT "Reformatting all code to preferred coding style."
+ # Note indent requires all userdefined types to be specified with '-T <type>' args to
+ # format them correctly. Rather than do that, we just postprocess with sed.
+ #
+ # Hide the enclosing 'extern "C" {...}' block for indenting in librsync.h
+ COMMAND sed -r -i "s:^(extern \"C\") \\{:\\1;:; s:^\\}(\\s+/\\* extern \"C\" \\*/):;\\1:" src/librsync.h
+ # Linux format with no tabs, indent 4, preproc indent 2, 80 columns, swallow blank lines.
+ COMMAND indent -linux -nut -i4 -ppi2 -l80 -lc80 -fc1 -sob -T FILE -T Rollsum -T rs_result ${tidy_SRCS}
+ # Remove space between * or & and identifier after userdefined types,
+ # remove space after type cast for userdefined types like indent -ncs,
+ # and remove trailing whitespace.
+ COMMAND sed -r -i "s:((${TYPE_RE}|${CAST_RE}) (&|\\*+)) :\\1:g; s:(${CAST_RE}) :\\1:g; s:\\s+$::" ${tidy_SRCS}
+ # Restore the enclosing 'extern "C" {...}' block in librsync.h
+ COMMAND sed -r -i "s:^(extern \"C\");:\\1 {:; s:^;(\\s+/\\* extern \"C\" \\*/):}\\1:" src/librsync.h
+ VERBATIM
+)
+# Code tidyc target to reformat all code and comments with https://github.com/dbaarda/tidyc.
+add_custom_target(tidyc
+ COMMENT "Reformatting all code and comments to preferred coding style."
+ # Recomended format, reformat linebreaks, reformat comments, 80 columns.
+ COMMAND tidyc -R -C -l80 -T FILE -T Rollsum -T rs_result ${tidy_SRCS}
+ VERBATIM
+)
+
+# Testing
+
+add_executable(isprefix_test
+ tests/isprefix_test.c src/isprefix.c)
+add_test(NAME isprefix_test COMMAND isprefix_test)
+
+add_executable(netint_test
+ tests/netint_test.c src/netint.c src/util.c src/trace.c src/tube.c
+ src/scoop.c)
+target_compile_options(netint_test PRIVATE -DLIBRSYNC_STATIC_DEFINE)
+add_test(NAME netint_test COMMAND netint_test)
+
+add_executable(rollsum_test
+ tests/rollsum_test.c src/rollsum.c)
+add_test(NAME rollsum_test COMMAND rollsum_test)
+
+add_executable(rabinkarp_test
+ tests/rabinkarp_test.c src/rabinkarp.c)
+add_test(NAME rabinkarp_test COMMAND rabinkarp_test)
+add_executable(rabinkarp_perf
+ tests/rabinkarp_perf.c src/rabinkarp.c)
+
+add_executable(hashtable_test
+ tests/hashtable_test.c src/hashtable.c)
+add_test(NAME hashtable_test COMMAND hashtable_test)
+
+add_executable(checksum_test
+ tests/checksum_test.c src/checksum.c src/rollsum.c src/rabinkarp.c src/mdfour.c ${blake2_SRCS})
+target_compile_options(checksum_test PRIVATE -DLIBRSYNC_STATIC_DEFINE)
+target_link_libraries(checksum_test ${blake2_LIBS})
+add_test(NAME checksum_test COMMAND checksum_test)
+
+add_executable(sumset_test
+ tests/sumset_test.c src/sumset.c src/util.c src/trace.c src/hex.c
+ src/checksum.c src/rollsum.c src/rabinkarp.c src/mdfour.c src/hashtable.c ${blake2_SRCS})
+target_compile_options(sumset_test PRIVATE -DLIBRSYNC_STATIC_DEFINE)
+target_link_libraries(sumset_test ${blake2_LIBS})
+add_test(NAME sumset_test COMMAND sumset_test)
+
+# Disable rdiff specific tests
+if (BUILD_RDIFF)
+ add_test(NAME rdiff_bad_option
+ COMMAND rdiff_bad_option.sh ${CMAKE_CURRENT_BINARY_DIR}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests)
+
+ add_test(NAME Help COMMAND help.test ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests)
+
+ add_test(NAME Mutate COMMAND mutate.test ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests)
+ add_test(NAME Signature COMMAND signature.test ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests)
+ add_test(NAME Sources COMMAND sources.test ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests)
+ add_test(NAME Triple COMMAND triple.test ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests)
+ add_test(NAME Delta COMMAND delta.test ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests)
+ add_test(NAME Changes COMMAND changes.test ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests)
+endif (BUILD_RDIFF)
+
+
+# `make check` that will build everything and then run the tests.
+# See https://cmake.org/Wiki/CMakeEmulateMakeCheck and
+# https://github.com/librsync/librsync/issues/49
+if (BUILD_RDIFF)
+ set(LAST_TARGET rdiff)
+else (BUILD_RDIFF)
+ set(LAST_TARGET rsync)
+endif (BUILD_RDIFF)
+add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} -C Debug)
+add_dependencies(check ${LAST_TARGET}
+ isprefix_test
+ netint_test
+ rollsum_test
+ rabinkarp_test
+ hashtable_test
+ checksum_test
+ sumset_test)
+
+enable_testing()
+
+# Create conf files
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/src/config.h)
+
+# We need to be able to #include "file" from a few places,
+# * The original source dir
+# * The generated source dir
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/src)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
+
+
+########### next target ###############
+
+# Only list the .c files that need to be compiled
+# (Don't list .h files)
+
+set(rsync_LIB_SRCS
+ src/prototab.c
+ src/base64.c
+ src/buf.c
+ src/checksum.c
+ src/command.c
+ src/delta.c
+ src/emit.c
+ src/fileutil.c
+ src/hashtable.c
+ src/hex.c
+ src/job.c
+ src/mdfour.c
+ src/mksum.c
+ src/msg.c
+ src/netint.c
+ src/patch.c
+ src/readsums.c
+ src/rollsum.c
+ src/rabinkarp.c
+ src/scoop.c
+ src/stats.c
+ src/sumset.c
+ src/trace.c
+ src/tube.c
+ src/util.c
+ src/version.c
+ src/whole.c
+ ${blake2_SRCS})
+
+add_library(rsync ${rsync_LIB_SRCS})
+# TODO: Enable this when GenerateExportHeader works more widely.
+# include(GenerateExportHeader)
+# generate_export_header(rsync BASE_NAME librsync
+# EXPORT_FILE_NAME ${CMAKE_SOURCE_DIR}/src/librsync_export.h)
+target_link_libraries(rsync ${blake2_LIBS})
+
+# Optionally link zlib and bzip2 if
+# - compression is enabled
+# - and libraries are found
+if (ENABLE_COMPRESSION)
+ if (ZLIB_FOUND AND BZIP2_FOUND)
+ target_link_libraries(rsync ${ZLIB_LIBRARIES} ${BZIP2_LIBRARIES})
+ else (ZLIB_FOUND AND BZIP2_FOUND)
+ message (WARNING "zlib and bzip2 librares are required to enable compression")
+ endif (ZLIB_FOUND AND BZIP2_FOUND)
+endif (ENABLE_COMPRESSION)
+
+# Set properties/options for shared vs static library.
+if (BUILD_SHARED_LIBS)
+ set_target_properties(rsync PROPERTIES C_VISIBILITY_PRESET hidden)
+else (BUILD_SHARED_LIBS)
+ target_compile_options(rsync PUBLIC -DLIBRSYNC_STATIC_DEFINE)
+endif (BUILD_SHARED_LIBS)
+
+set_target_properties(rsync PROPERTIES
+ VERSION ${LIBRSYNC_VERSION}
+ SOVERSION ${LIBRSYNC_MAJOR_VERSION})
+install(TARGETS rsync ${INSTALL_TARGETS_DEFAULT_ARGS}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+
+########### next target ###############
+
+if (BUILD_RDIFF)
+ set(rdiff_SRCS
+ src/rdiff.c
+ src/isprefix.c)
+
+ add_executable(rdiff ${rdiff_SRCS})
+ if (POPT_FOUND)
+ target_link_libraries(rdiff rsync ${POPT_LIBRARIES})
+ else (POPT_FOUND)
+ message (WARNING "Popt library is required for rdiff target")
+ endif (POPT_FOUND)
+
+ install(TARGETS rdiff ${INSTALL_TARGETS_DEFAULT_ARGS}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ )
+endif (BUILD_RDIFF)
+
+
+########### install files ###############
+
+install(FILES
+ src/librsync.h
+ src/librsync_export.h
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+message (STATUS "CMAKE_C_FLAGS = ${CMAKE_C_FLAGS}")
+
+install(FILES
+ doc/librsync.3
+ DESTINATION ${CMAKE_INSTALL_MANDIR}/man3)
+install(FILES
+ doc/rdiff.1
+ DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
+
+# vim: shiftwidth=4 expandtab
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..9ccb188
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,128 @@
+# Contributing to librsync {#page_contributing}
+
+Instructions and conventions for people wanting to work on librsync. Please
+consider these guidelines even if you're doing your own fork.
+
+## Code Style
+
+The prefered style for code is equivalent to using GNU indent with the
+following arguments;
+
+```Shell
+$ indent -linux -nut -i4 -ppi2 -l80 -lc80 -fc1 -fca -sob
+```
+
+The preferred style for non-docbook comments are as follows;
+
+```C
+
+ /*=
+ | A short poem that
+ | shall never ever be
+ | reformated or reindented
+ */
+
+ /* Single line comment indented to match code indenting. */
+
+ /* Blank line delimited paragraph multi-line comments.
+
+ Without leading stars, or blank line comment delimiters. */
+
+ int a; /* code line comments */
+```
+
+The preferred style for docbook comments is javadoc with autobrief as
+follows;
+
+```C
+/** /file file.c
+ * Brief summary paragraph.
+ *
+ * With blank line paragraph delimiters and leading stars.
+ *
+ * /param foo parameter descriptions...
+ *
+ * /param bar ...in separate blank-line delimited paragraphs.
+ *
+ * Example:/code
+ * code blocks that will never be reformated.
+ * /endcode
+ *
+ * Without blank-line comment delimiters. */
+
+ int a; /**< brief attribute description */
+ int b; /**< multiline attribute description
+ *
+ * With blank line delimited paragraphs.*/
+```
+
+There is a `make tidy` target that will use GNU indent to reformat all
+code and non-docbook comments, doing some pre/post processing with sed
+to handle some corner cases indent doesn't handle well.
+
+There is also a `make tidyc` target that will reformat all code and
+comments with https://github.com/dbaarda/tidyc. This will also
+correctly reformat all docbook comments, equivalent to running tidyc
+with the following arguments;
+
+```Shell
+$ tidyc -R -C -l80
+```
+
+## Pull requests
+
+Fixes or improvements in pull requests are welcome. Please:
+
+- [ ] Send small PRs that address one issues each.
+
+- [ ] Update `NEWS.md` to say what you changed.
+
+- [ ] Add a test as a self-contained C file in `tests/` that passes or fails,
+ and is hooked into `CMakeLists.txt`.
+
+- [ ] Keep the code style consistent with what's already there, especially in
+ keeping symbols with an `rs_` prefix.
+
+
+## NEWS
+
+[NEWS.md](NEWS.md) contains a list of user-visible changes in the library between
+releases version. This includes changes to the way it's packaged,
+bug fixes, portability notes, changes to the API, and so on.
+
+Add
+and update items under a "Changes in X.Y.Z" heading at the top of
+the file. Do this as you go along, so that we don't need to work
+out what happened when it's time for a release.
+
+## Tests
+
+Please try to update docs and tests in parallel with code changes.
+
+## Releasing
+
+If you are making a new tarball release of librsync, follow this checklist:
+
+* NEWS.md - make sure the top "Changes in X.Y.Z" is correct, and the date is
+ correct. Make sure the changes since the last release are documented.
+
+* `CMakeLists.txt` - version is correct.
+
+* `librsync.spec` - make sure version and URL are right.
+
+* Run `make all doc check` in a clean checkout of the release tag. Also check
+ the travis-cl check status of the last commit on github.
+
+* Draft a new release on github, typing in the release details including an
+ overview, included changes, and known issues. The overview should give an
+ indication of the magnitude of the changes and their impact, and the
+ relative urgency to upgrade. The included changes should come from the
+ NEWS.md for the release. It's probably easiest to copy and edit the previous
+ release.
+
+* After creating the release, download the tar.gz version, edit the release,
+ and re-upload it. This ensures that the release includes a stable tarball
+ (See https://github.com/librsync/librsync/issues/146 for details).
+
+Test results for builds of public github branches are at
+https://travis-ci.org/librsync/librsync.
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..c4792dd
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,515 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+ When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+^L
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+^L
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, 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 library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+ 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 Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+^L
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+ If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+^L
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be 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.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+^L
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+ 9. 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 Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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 with
+this License.
+^L
+ 11. 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 Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+^L
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+^L
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library.
+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 library's name and a brief idea of what it
+does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper
+mail.
+
+You should also get your employer (if you work as a programmer) or
+your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James
+Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..49884b5
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,524 @@
+Copyright 1999-2016 Martin Pool and other contributors.
+
+librsync is distributed under the GNU LGPL v2.1, which basically
+means that you can dynamically link librsync into non-GPL programs,
+but you must redistribute the librsync source, with any modifications
+you have made.
+
+librsync contains the BLAKE2 hash algorithm, written by Samuel Neves
+and released under the CC0 public domain dedication.
+
+
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+ When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+^L
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+^L
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, 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 library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+ 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 Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+^L
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+ If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+^L
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be 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.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+^L
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+ 9. 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 Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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 with
+this License.
+^L
+ 11. 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 Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+^L
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+^L
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library.
+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 library's name and a brief idea of what it
+does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper
+mail.
+
+You should also get your employer (if you work as a programmer) or
+your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James
+Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
\ No newline at end of file
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..f80e828
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,17 @@
+name: "librsync"
+description: "Remote delta-compression library"
+
+third_party {
+ url {
+ type: GIT
+ value: "https://github.com/librsync/librsync"
+ }
+ url {
+ type: HOMEPAGE
+ value: "https://librsync.github.io/"
+ }
+ license_type: RESTRICTED
+ version: "v2.3.2"
+ last_upgrade_date { year: 2020 month: 09 day: 24 }
+ local_modifications: "None"
+}
diff --git a/NEWS.md b/NEWS.md
new file mode 100644
index 0000000..f00d9e4
--- /dev/null
+++ b/NEWS.md
@@ -0,0 +1,582 @@
+# librsync NEWS
+
+## librsync 2.3.2
+
+NOT RELEASED YET
+
+ * Add Travis Windows checks and improve compatibility. Turn on `-Wconversion
+ -Wno-sign-conversion` warnings for clang. Add MSVC compiler flags to turn
+ off posix warnings. Make all code compile clean with no warnings on all
+ Travis platforms. Added cmake config checking for windows `io.h` and
+ improve `fileutil.c` for MSVC. Fix broken error handling in
+ `rs_file_copy_cb()`. Improved trace output, making it less spamy and more
+ consistent. Add patch checking for invalid literal lengths. Improve
+ internal variable and argument types. Add explicit type conversions.
+ (dbaarda, https://github.com/librsync/librsync/pull/208)
+
+ * Fix a bug so patch will now fail returning RS_CORRUPT on encountering a
+ zero length copy command instead of hanging. Make copy_cb() copying more
+ data than requested an assert-fail on debug builds, and a log-warning for
+ release builds. Make trace output a little less spammy about copy_cb()
+ return values. (dbaarda, https://github.com/librsync/librsync/pull/206)
+
+## librsync 2.3.1
+
+Released 2020-05-19
+
+ * Fix #198 cmake popt detection using pkg-config and #199 test scripts on
+ FreeBSD. Fixes and tidies FindPOPT.cmake and Findlibb2.cmake to use
+ pkg-config correctly and behave more like official FindPackage() cmake
+ modules. Makes all test scripts use /bin/sh instead of /bin/bash. (dbaarda,
+ mandree https://github.com/librsync/librsync/pull/200)
+
+ * Change default block_len to always be a multiple of the blake2b 128 byte
+ blocksize for efficiency. Tidy and update docs to explain using
+ rs_sig_args() and rs_build_hash_table(), add rs_file_*() utils, and
+ document new magic types. Remove really obsolete entries in TODO.md. Update
+ to Doxygen 1.8.16. (dbaarda, https://github.com/librsync/librsync/pull/195)
+
+ * Improve hashtable performance by adding a small optional bloom filter,
+ reducing max loadfactor from 80% to 70%, Fix hashcmp_count stats to include
+ comparing against empty buckets. This speeds up deltas by 20%~50%.
+ (dbaarda, https://github.com/librsync/librsync/pull/192,
+ https://github.com/librsync/librsync/pull/193,
+ https://github.com/librsync/librsync/pull/196)
+
+ * Optimize rabinkarp_update() by correctly using unsigned constants and
+ manually unrolling the loop for best performance. (dbaarda,
+ https://github.com/librsync/librsync/pull/191)
+
+## librsync 2.3.0
+
+Released 2020-04-07
+
+ * Bump minor version from 2.2.1 to 2.3.0 to reflect additional rs_sig_args()
+ and strong_len=-1 support.
+
+ * Add public rs_sig_args() function for getting the recommend signature args
+ from the file size. Added support to rdiff for `--sum-size=-1` to indicate
+ "use minimum size safe against random block collisions". Added warning
+ output for sum-sizes that are too small to be safe. Fixed possible rdiff
+ bug affecting popt parsing on non-little-endian platforms. (dbaarda,
+ https://github.com/librsync/librsync/pull/109)
+
+ * Fixed yet more compiler warnings for various platforms/compilers.
+ (Adsun701, texierp, https://github.com/librsync/librsync/pull/187,
+ https://github.com/librsync/librsync/pull/188)
+
+ * Improved cmake popt handling to find popt dependencies using PkgConfig.
+ (ffontaine, https://github.com/librsync/librsync/pull/186)
+
+ * Tidied internal code and improved tests for netint.[ch], tube.c, and
+ hashtable.h. (dbaarda, https://github.com/librsync/librsync/pull/183
+ https://github.com/librsync/librsync/pull/185).
+
+ * Improved C99 compatibility. Add `-std=c99 -pedantic` to `CMAKE_C_FLAGS` for
+ gcc and clang. Fix all C99 warnings by making all code C99 compliant. Tidy
+ all CMake checks, `#cmakedefines`, and `#includes`. Fix 64bit support for
+ mdfour checksums (texierp, dbaarda,
+ https://github.com/librsync/librsync/pull/181,
+ https://github.com/librsync/librsync/pull/182)
+
+ * Usage clarified in rdiff (1) man page. (AaronM04,
+ https://github.com/librsync/librsync/pull/180)
+
+## librsync 2.2.1
+
+Released 2019-10-16
+
+ * Fix #176 hangs calculating deltas for files larger than 4GB. (dbaarda,
+ https://github.com/librsync/librsync/pull/177)
+
+## librsync 2.2.0
+
+Released 2019-10-12
+
+ * Bump minor version from 2.1.0 to 2.2.0 to reflect additional RabinKarp
+ rollsum support.
+
+ * Fix MSVC builds by adding missing LIBRSYNC_EXPORT to variables in
+ librsync.h, add -DLIBRSYNC_STATIC_DEFINE to the sumset_test target,
+ and correctly install .dll files in the bin directory.
+ (adsun701, https://github.com/librsync/librsync/pull/161)
+
+ * Add RabinKarp rollsum support and make it the default. RabinKarp is a much
+ better rolling hash, which reduces the risk of hash collision corruption
+ and speeds up delta calculations. The rdiff cmd gets a new `-R
+ (rollsum|rabinkarp)` argument with the default being `rabinkarp`, Use `-R
+ rollsum` to generate backwards-compatible signatures. (dbaarda,
+ https://github.com/librsync/librsync/issues/3)
+
+ * Use single-byte literal commands for small inserts in deltas. This makes
+ each small insert use 1 less byte in deltas. (dbaarda,
+ https://github.com/librsync/librsync/issues/120)
+
+ * Fix multiple warnings (cross-)compiling for windows. (Adsun701,
+ https://github.com/librsync/librsync/pull/165,
+ https://github.com/librsync/librsync/pull/166)
+
+ * Change rs_file_size() to report -1 instead of 0 for unknown file sizes (not
+ a regular file). (dbaarda https://github.com/librsync/librsync/pull/168)
+
+ * Add cmake BUILD_SHARED_LIBS option for static library support.
+ BUILD_SHARED_LIBS defaults to ON, and can be set to OFF using `ccmake .` to
+ build librsync as a static library. (dbaarda
+ https://github.com/librsync/librsync/pull/169)
+
+ * Fix compile errors and add .gitignore entries for MSVS 2019. Fixes
+ hashtable.h to be C99 compliant. (ardovm
+ https://github.com/librsync/librsync/pull/170)
+
+## librsync 2.1.0
+
+Released 2019-08-19
+
+ * Bump minor version from 2.0.3 to 2.1.0 to reflect additions to librsync.h.
+
+ * Fix exporting of private symbols from librsync library. Add export of
+ useful large file functions `rs_file_open()`, `rs_file_close()`, and
+ `rs_file_size()` to librsync.h. Add export of `rs_signature_log_stats()` to
+ log signature hashtable hit/miss stats. Improve rdiff error output.
+ (dbaarda, https://github.com/librsync/librsync/issues/130)
+
+ * Updated release process to include stable tarballs. (dbaarda,
+ https://github.com/librsync/librsync/issues/146)
+
+ * Remove redundant and broken `--paranoia` argument from rdiff. (dbaarda,
+ https://github.com/librsync/librsync/issues/155)
+
+ * Fix memory leak of `rs_signature_t->block_sigs` when freeing signatures.
+ (telles-simbiose, https://github.com/librsync/librsync/pull/147)
+
+ * Document delta file format. (zmj,
+ https://github.com/librsync/librsync/issues/46)
+
+ * Fix up doxygen comments. (dbaarda,
+ https://github.com/librsync/librsync/pull/151)
+
+## librsync 2.0.2
+
+Released 2018-02-27
+
+ * Improve CMake install paths configuration (wRAR,
+ https://github.com/librsync/librsync/pull/133) and platform support
+ checking when cross-compiling (fornwall,
+ https://github.com/librsync/librsync/pull/136).
+
+ * Fix Unaligned memory access for rs_block_sig_init() (dbaarda,
+ https://github.com/librsync/librsync/issues/135).
+
+ * Fix hashtable_test.c name collision for key_t in sys/types.h on some
+ platforms (dbaarda, https://github.com/librsync/librsync/issues/134)
+
+ * Format code with consistent style, adding `make tidy` and `make
+ tidyc` targets for reformating code and comments. (dbaarda,
+ https://github.com/librsync/librsync/issues/125)
+
+ * Removed perl as a build dependency. Note it is still required for some
+ tests. (dbaarda, https://github.com/librsync/librsync/issues/75)
+
+ * Update RPM spec file for v2.0.2 and fix cmake man page install. (deajan,
+ https://github.com/librsync/librsync/issues/47)
+
+## librsync 2.0.1
+
+Released 2017-10-17
+
+ * Extensively reworked Doxygen documentation, now available at
+ http://librsync.sourcefrog.net/ (Martin Pool)
+
+ * Removed some declarations from librsync.h that were unimplemented or no
+ longer ever useful: `rs_work_options`, `rs_accum_value`. Remove
+ declaration of unimplemented `rs_mdfour_file()`. (Martin Pool)
+
+ * Remove shipped `snprintf` code: no longer acutally linked after changing to
+ CMake, and since it's part of C99 it should be widely available.
+ (Martin Pool)
+
+ * Document that Ninja (http://ninja-build.org/) is supported under CMake.
+ It's a bit faster and nicer than Make. (Martin Pool)
+
+ * `make check` (or `ninja check` etc) will now build and run the tests.
+ Previously due to a CMake limitation, `make test` would only run existing
+ tests and could fail if they weren't built.
+ (Martin Pool, https://github.com/librsync/librsync/issues/49)
+
+ * Added cmake options to exclude rdiff target and compression from build.
+ See install documentation for details. Thanks to Michele Bertasi.
+
+ * `popt` is only needed when `rdiff` is being built. (gulikoza)
+
+ * Improved large file support for platforms using different variants
+ of `fseek` (`fseeko`, `fseeko64`, `_fseeki64`), `fstat` (`fstat64`,
+ `_fstati64`), and `fileno` (`_fileno`). (dbaarda, charlievieth,
+ gulikoza, marius-nicolae)
+
+ * `rdiff -s` option now shows bytes read/written and speed. (gulikoza).
+ For delta operations it also shows hashtable match statistics. (dbaarda)
+
+ * Running rdiff should not overwrite existing files (signatures, deltas and
+ new patched files) by default. If the destination file exists, rdiff will
+ now exit with an error. Add new option -f (--force) to overwrite existing
+ files. (gulikoza)
+
+ * Improve signature memory allocation (doubling size instead of calling
+ realloc for every sig block) and added support for preallocation. See
+ streaming.md job->estimated_signature_count for usage when using the
+ library. `rdiff` uses this by default if possible. (gulikoza, dbaarda)
+
+ * Significantly tidied signature handling code and testing, resulting in more
+ consistent error handling behaviour, and making it easier to plug in
+ alternative weak and strong sum implementations. Also fixed "slack delta"
+ support for delta calculation with no signature. (dbaarda)
+
+ * `stdint.h` and `inttypes.h` from C99 is now required. Removed redundant
+ librsync-config.h header file. (dbaarda)
+
+ * Lots of small fixes for windows platforms and building with MSVC.
+ (lasalvavida, mbrt, dbaarda)
+
+ * New open addressing hashtable implementation that significantly speeds up
+ delta operations, particularly for large files. Also fixed degenerate
+ behaviour with large number of duplicate blocks like runs of zeros
+ in sparse files. (dbaarda)
+
+ * Optional support with cmake option for using libb2 blake2 implementation.
+ Also updated included reference blake2 implementation with bug fixes
+ (dbaarda).
+
+ * Improved default values for input and output buffer sizes. The defaults are
+ now --input-size=0 and --output-size=0, which will choose recommended
+ default sizes based on the --block-size and the operation being performed.
+ (dbaarda)
+
+ * Fixed hanging for truncated input files. It will now correctly report an
+ error indicating an unexpected EOF was encountered. (dbaarda,
+ https://github.com/librsync/librsync/issues/32)
+
+ * Fixed #13 so that faster slack delta's are used for signatures of
+ empty files. (dbaarda,
+ https://github.com/librsync/librsync/issues/13)
+
+ * Fixed #33 so rs_job_iter() doesn't need calling twice with eof=1.
+ Also tidied and optimized it a bit. (dbaarda,
+ https://github.com/librsync/librsync/issues/33)
+
+ * Fixed #55 remove excessive rs_fatal() calls, replacing checks for
+ programming errors with assert statements. Now rs_fatal() will only
+ be called for rare unrecoverable fatal errors like malloc failures or
+ impossibly large inputs. (dbaarda,
+ https://github.com/librsync/librsync/issues/55)
+
+## librsync 2.0.0
+
+Released 2015-11-29
+
+Note: despite the major version bump, this release has few changes and should
+be binary and API compatible with the previous version.
+
+ * Bump librsync version number to 2.0, to match the library
+ soname/dylib version.
+ (Martin Pool, https://github.com/librsync/librsync/issues/48)
+
+## librsync 1.0.1 (2015-11-21)
+
+ * Better performance on large files. (VictorDenisov)
+
+ * Add comment on usage of rs_build_hash_table(), and assert correct use.
+ Callers must call rs_build_hash_table() after loading the signature,
+ and before calling rs_delta_begin().
+ Thanks to Paul Harris <paulharris@computer.org>
+
+ * Switch from autoconf to CMake.
+
+ Thanks to Adam Schubert.
+
+## librsync 1.0.0 (2015-01-23)
+
+ * SECURITY: CVE-2014-8242: librsync previously used a truncated MD4
+ "strong" check sum to match blocks. However, MD4 is not cryptographically
+ strong. It's possible that an attacker who can control the contents of one
+ part of a file could use it to control other regions of the file, if it's
+ transferred using librsync/rdiff. For example this might occur in a
+ database, mailbox, or VM image containing some attacker-controlled data.
+
+ To mitigate this issue, signatures will by default be computed with a
+ 256-bit BLAKE2 hash. Old versions of librsync will complain about a
+ bad magic number when given these signature files.
+
+ Backward compatibility can be obtained using the new
+ `rdiff sig --hash=md4`
+ option or through specifying the "signature magic" in the API, but
+ this should not be used when either the old or new file contain
+ untrusted data.
+
+ Deltas generated from those signatures will also use BLAKE2 during
+ generation, but produce output that can be read by old versions.
+
+ See https://github.com/librsync/librsync/issues/5
+
+ Thanks to Michael Samuel <miknet.net> for reporting this and offering an
+ initial patch.
+
+ * Various build fixes, thanks Timothy Gu.
+
+ * Improved rdiff man page from Debian.
+
+ * Improved librsync.spec file for building RPMs.
+
+ * Fixed bug #1110812 'internal error: job made no progress'; on large
+ files.
+
+ * Moved hosting to https://github.com/librsync/librsync/
+
+ * Travis-CI.org integration test at https://travis-ci.org/librsync/librsync/
+
+ * You can set `$LIBTOOLIZE` before running `autogen.sh`, for example on
+ OS X Homebrew where it is called `glibtoolize`.
+
+## 0.9.7 (released 2004-10-10)
+
+ * Yet more large file support fixes.
+
+ * `extern "C"` guards in librsync.h to let it be used from C++.
+
+ * Removed Debian files from dist tarball.
+
+ * Changed rdiff to an installed program on "make install".
+
+ * Refactored delta calculation code to be cleaner and faster.
+
+ * \#879763: Fixed mdfour to work on little-endian machines which don't
+ like unaligned word access. This should make librsync work on
+ pa-risc, and it makes it slightly faster on ia64.
+
+ * \#1022764: Fix corrupted encoding of some COPY commands in large
+ files.
+
+ * \#1024881: Print long integers directly, rather than via casts to
+ double.
+
+ * Fix printf formats for size_t: both the format and the argument
+ should be cast to long.
+
+## 0.9.6
+
+ * Large file support fixes.
+
+ * [v]snprintf or _[v]snprintf autoconf replacement function fix.
+
+ * Changed installed include file from rsync.h to librsync.h.
+
+ * Migration to sourceforge for hosting.
+
+ * Rollsum bugfix that produces much smaller deltas.
+
+ * Memory leaks bugfix patches.
+
+ * mdfour bigendian and >512M bugfix, plus optimisations patch.
+
+ * autoconf/automake updates and cleanups for autoconf 2.53.
+
+ * Windows compilation patch, heavily modified.
+
+ * MacOSX compilation patch, modified to autoconf vararg macro fix.
+
+ * Debian package build scripts patch.
+
+## 0.9.5
+
+ * Bugfix patch from Shirish Hemant Phatak
+
+## 0.9.4: (library 1.1.0)
+
+ * Fixes for rsync.h from Thorsten Schuett <thorsten.schuett@zib.de>
+
+ * RLL encoding fix from Shirish Hemant Phatak <shirish@nustorage.com>
+
+ * RPM spec file by Peter J. Braam <braam@clusterfs.com>
+
+ * No (intentional) changes to binary API.
+
+## 0.9.3
+
+ * Big speed improvements in MD4 routines and generation of weak
+ checksums.
+
+ * Patch to build on FreeBSD by Jos Backus <josb@cncdsl.com>
+
+ * Suggestions to build on Solaris 2.6 from Alberto Accomazzi
+ <aaccomazzi@cfa.harvard.edu>
+
+ * Add rs_job_drive, a generic mechanism for turning the library into
+ blocking mode. rs_whole_run now builds on top of this. The
+ filebuf interface has changed a little to accomodate it.
+
+ * Generating and loading signatures now generates statistics.
+
+ * More test cases.
+
+ * I suspect there may be a bug in rolling checksums, but it probably
+ only causes inefficiency and not corruption.
+
+ * Portability fixes for alphaev67-dec-osf5.1; at the moment builds
+ but does not work because librsync tries to do unaligned accesses.
+
+ * Works on sparc64-unknown-linux-gnu (Debian/2.2)
+
+## 0.9.2
+
+ * Improve delta algorithm so that deltas are actually
+ delta-compressed, rather than faked.
+
+## 0.9.1
+
+ * Rename the library to `librsync'.
+
+ * Portability fixes.
+
+ * Include the popt library, and use it to build rdiff if the library
+ is not present on the host.
+
+ * Add file(1) magic for rdiff.
+
+ * Add more to the manual pages.
+
+ * It's no longer necessary to call rs_buffers_init on a stream before
+ starting to use it: all the internal data is kept in the job, not
+ in the stream.
+
+ * Rename rs_stream_t to rs_buffers_t, a more obvious name. Pass the
+ buffers to every rs_job_iter() call, rather than setting it at
+ startup. Similarly for all the _begin() functions.
+
+ * rs_job_new also takes the initial state function.
+
+ * Return RS_PARAM_ERROR when library is misused.
+
+## 0.9.0
+
+ * Redesign API to be more like zlib/bzlib.
+
+ * Put all command-line functions into a single rdiff(1) program.
+
+ * New magic number `rs6'
+
+ * Change to using popt for command line parsing.
+
+ * Use Doxygen for API documentation.
+
+## 0.5.7
+
+ * Changes stats string format.
+
+ * Slightly improved test cases
+
+## 0.5.6
+
+ * Don't install debugging tools into /usr/local/bin; leave them in
+ the source directory.
+
+ * Fix libhsync to build on (sgi-mips, IRIX64, gcc, GNU Make)
+
+ * Include README.CVS in tarball
+
+ * Back out of using libtool and shared libraries, as it is
+ unnecessary at this stage, complicates installation and slows down
+ compilation.
+
+ * Use mapptr when reading data to decode, so that decoding should
+ have less latency and be more reliable.
+
+ * Cope better on systems that are missing functions like snprintf.
+
+## 0.5.5
+
+ * Put genuine search encoding back into the nad algorithm, and
+ further clean up the nad code. Literals are now sent out using a
+ literal buffer integrated with the input mapptr so that data is not
+ copied. Checksums are still calculated from scratch each time
+ rather than by rolling -- this is very slow but simple.
+
+ * Reshuffle test cases so that they use files generated by hsmapread,
+ rather than the source directory. This makes the tests quicker and
+ more reproducible, hopefully without losing coverage. Further
+ develop the test driver framework.
+
+ * Add hsdumpsums debugging tool.
+
+ * Hex strings (eg strong checksums) are broken up by underscores for
+ readability.
+
+ * Stats now go to the log rather than stdout.
+
+ * mapptr acts properly when we're skipping/rewinding to data already
+ present in the buffer -- it does a copy if required, but not
+ necessarily real IO.
+
+## 0.5.4
+
+ * Improved mapptr input code
+
+ * Turn on more warnings if using gcc
+
+ * More test cases
+
+## 0.5.3
+
+ * Improvements to mapptr to make it work better for network IO.
+
+ * Debug trace code is compiled in unless turned off in ./configure
+ (although most programs will not write it out unless asked.)
+
+ * Add libhsyncinfo program to show compiled-in settings and version.
+
+ * Add test cases that run across localhost TCP sockets.
+
+ * Improved build code; should now build easily from CVS through
+ autogen.sh.
+
+ * Improved trace code.
+
+ * Clean up to build on sparc-sun-solaris2.8, and in the process clean
+ up the handling of bytes vs chars, and of building without gcc
+
+ * Reverse build scripts so that driver.sh calls the particular
+ script.
+
+## 0.5.2
+
+ * Use mapptr for input.
+
+ * Implement a new structure for encoding in nad.c. It doesn't
+ encode at the moment, but it's much more maintainable.
+
+ * More regression cases.
+
+ * Clean up build process.
+
+## 0.5.0
+
+ * Rewrite hs_inbuf and hs_encode to make them simpler and more
+ reliable.
+
+ * Test cases for input handling.
+
+ * Use the map_ptr idea for input from both streams and files.
+
+## 0.4.1
+
+ * automake/autoconf now works cleanly when the build directory is
+ different to the source directory.
+
+ * --enable-ccmalloc works again.
+
+## 0.4.0
+
+* A much better regression suite.
+
+* CHECKSUM token includes the file's checksum up to the current
+ location, to aid in self-testing.
+
+* Various bug fixes, particularly to do with short IO returns.
diff --git a/README.RPM b/README.RPM
new file mode 100644
index 0000000..10af3e5
--- /dev/null
+++ b/README.RPM
@@ -0,0 +1,7 @@
+librsync now comes with an RPM .spec file contributed by Peter Braam
+and Shirish Hemant Phatak that will allow you to build an RPM package.
+
+To do this, simply execute the command:
+
+ rpm -ta librsync-0.9.3.tar.gz
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..de95708
--- /dev/null
+++ b/README.md
@@ -0,0 +1,83 @@
+# librsync
+
+http://librsync.sourcefrog.net/
+
+\copyright
+
+Copyright 1999-2016 Martin Pool and other contributors.
+
+librsync is distributed under the [GNU LGPL v2.1][LGPL]
+(see COPYING), which basically
+means that you can dynamically link librsync into non-GPL programs, but you
+must redistribute the librsync source, with any modifications you have made.
+
+[LGPL]: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
+
+librsync contains the BLAKE2 hash algorithm, written by Samuel Neves and
+released under the [CC0 public domain dedication][CC0].
+
+[CC0]: http://creativecommons.org/publicdomain/zero/1.0/
+
+
+## Introduction
+
+librsync is a library for calculating and applying network deltas,
+with an interface designed to ease integration into diverse
+network applications.
+
+librsync encapsulates the core algorithms of the rsync protocol, which
+help with efficient calculation of the differences between two files.
+The rsync algorithm is different from most differencing algorithms
+because it does not require the presence of the two files to calculate
+the delta. Instead, it requires a set of checksums of each block of
+one file, which together form a signature for that file. Blocks at
+any in the other file which have the same checksum are likely to be
+identical, and whatever remains is the difference.
+
+This algorithm transfers the differences between two files without
+needing both files on the same system.
+
+librsync is for building other programs that transfer files as efficiently
+as rsync. You can use librsync in a program you write to do backups,
+distribute binary patches to programs, or sync directories to a server
+or between peers.
+
+This tree also produces the \ref page_rdiff that exposes the key operations of
+librsync: generating file signatures, generating the delta from a signature to
+a new file, and applying the delta to regenerate the new file given the old
+file.
+
+librsync was originally written for the rproxy experiment in
+delta-compression for HTTP.
+librsync is used by: [Dropbox](https://dropbox.com/),
+[rdiff-backup](http://www.nongnu.org/rdiff-backup/),
+[Duplicity](http://www.nongnu.org/duplicity/), and others.
+(If you would like to be listed here, let me know.)
+
+### What librsync is not
+
+1. librsync does not implement the rsync wire protocol. If you want to talk to
+an rsync server to transfer files you'll need to shell out to `rsync`.
+You cannot make use of librsync to talk to an rsync server.
+
+2. librsync does not deal with file metadata or structure, such as filenames,
+permissions, or directories. To this library, a file is just a stream of bytes.
+Higher-level tools can deal with such issues in a way appropriate to their
+users.
+
+3. librsync also does not include any network functions for talking to SSH
+or any other server. To access a remote filesystem, you need to provide
+your own code or make use of some other virtual filesystem layer.
+
+
+## More information
+
+* \ref page_downloads
+* \ref versioning
+* \ref page_install
+* \ref page_rdiff
+* \ref page_api
+* \ref page_formats
+* \ref page_support
+* \ref page_contributing
+* \ref NEWS.md
diff --git a/THANKS b/THANKS
new file mode 100644
index 0000000..13fcbf0
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,121 @@
+ -*- text -*-
+Originators and Contributors up to 0.9.5
+---------------------------------------
+
+Andrew Tridgell and Paulus Mackerras started this whole mess. Luke
+Leighton was a tremendous help in sorting out the combined
+encoding/signature algorithm.
+
+Thanks to Linuxcare, Inc, for their support of this project.
+
+Neale Banks <neale@lowendale.com.au>: the first known user outside of
+OzLabs.
+
+Paul `Rusty' Russell <rusty@rustcorp.com>
+Andrew Tridgell <tridge@samba.org>
+Paulus Mackerras
+Peter Barker <pbarker@samba.org>
+Neale Banks <neale@lowendale.com.au>
+Luke Kenneth Casson Leighton
+Tim Potter
+Hugh Blemings
+David Gibson
+
+
+Contributors by release
+-----------------------
+
+The following is a list of contributors for each release. It is
+possible we have missed some contributors. If you know of anyone who
+has been omitted and deserves to be included, please send the details
+so they can be added.
+
+For later releases, contributors are listed in NEWS.
+
+Contributors for 0.9.6
+
+ * Wayne Davison <wayned@users.sourceforge.net>
+ - librsync sf project admin
+ - sf project creation, import cvs etc
+ - many cvs commits of submitted patches
+ - rsync.h -> librsync.h rename
+ - librsync-conf.h addition and config.h issue resolution
+
+ * Martin Pool <mbp@users.sourceforge.net>
+ - sf project admin
+ - sf project developers setup
+
+ * Donovan Baarda <abo@minkirri.apana.org.au>
+ - librsync sf project admin
+ - sf project tracker and lists setup
+ - MSVC6 and cygwin compiling patch and updates
+ - mdfour optimisations and cleanups patch
+ - autconf/autmake cleanups
+ - large file debugging and fixes
+ - build and release
+
+ * Ben Escoto <bescoto@users.sourceforge.net>
+ - librsync sf project admin
+
+ * Ben Elliston <bje@air.net.au>
+ - many cvs commits before migrating to sf
+
+ * Robert Weber <chipsforbrains@users.sourceforge.net>
+ - bigendian and >512M mdfour patch
+
+ * Skip Montanaro <montanaro@users.sourceforge.net>
+ - librsync on MacOSX patch
+
+ * Diego Liziero <diegoliz@users.sourceforge.net>
+ - memory leak patches
+ - again rdiff cosmetic patch
+
+ * Berkan Eskikaya <berkan@users.sourceforge.net>
+ - Control files for librsync debian packages patch
+
+ * Mark Moraes <moraes@sbcglobal.net>
+ - cygwin testsuite fixes email patch
+
+ * Robert Collins <robert.collins@itdomain.com.au>
+ - autoconf/automake cleanups email (old patch)
+
+ * Paul Green <lists@webleicester.co.uk>
+ - large file testing and debugging
+
+
+Contributors for 0.9.7
+
+ * Donovan Baarda <abo@minkirri.apana.org.au>
+ - librsync sf project admin
+ - delta refactor patch
+ - bug resolution
+
+ * Martin Pool <mbp@users.sourceforge.net>
+ - sf project admin
+ - documentation updates.
+ - bug fixes
+
+ * John Goerzen <jgoerzen@complete.org>
+ - Debian package maintainence
+
+ * Dave Coombs <dcoombs@nit.ca>
+ - C++ wrapper patch
+
+ * Eran Tromer <tromer@users.sourceforge.net>
+ - [#855477] buf.c incorrect header order, and fix.
+
+ - [#1022764] Reported and diagnosed nasty corruption bug with large
+ files.
+
+ * Simon Law <sfllaw@debian.org>
+ - [#879763] Fixed problems with unaligned access in mdfour.
+
+
+Contributors for 0.9.8 (release pending)
+
+ * Charles Duffy <cduffy@users.sourceforge.net>
+ - [#1056544] Submitted patch with improved spec file for building RPMs.
+ - [#1056548] Reported man page bug about using '-' for stdin/stdout.
+
+ * Don Malcolm <donmalcolm@users.sourceforge.net>
+ - [#1439412] Submitted patch for bug #1110812 error on large files.
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 0000000..e2ac4bb
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,147 @@
+# librsync TODO
+
+* We have a few functions to do with reading a netint, stashing
+ it somewhere, then moving into a different state. Is it worth
+ writing generic functions for that, or would it be too confusing?
+
+* Optimisations and code cleanups;
+
+ scoop.c: Scoop needs major refactor. Perhaps the API needs
+ tweaking?
+
+ rsync.h: rs_buffers_s and rs_buffers_t should be one typedef?
+
+ mdfour.c: This code has a different API to the RSA code in libmd
+ and is coupled with librsync in unhealthy ways (trace?). Recommend
+ changing to RSA API?
+
+* Just how useful is rs_job_drive anyway?
+
+* Don't use the rs_buffers_t structure.
+
+ There's something confusing about the existence of this structure.
+ In part it may be the name. I think people expect that it will be
+ something that behaves like a FILE* or C++ stream, and it really
+ does not. Also, the structure does not behave as an object: it's
+ really just a shorthand for passing values in to the encoding
+ routines, and so does not have a lot of identity of its own.
+
+ An alternative might be
+
+ result = rs_job_iter(job,
+ in_buf, &in_len, in_is_ending,
+ out_buf, &out_len);
+
+ where we update the length parameters on return to show how much we
+ really consumed.
+
+ One technicality here will be to restructure the code so that the
+ input buffers are passed down to the scoop/tube functions that need
+ them, which are relatively deeply embedded. I guess we could just
+ stick them into the job structure, which is becoming a kind of
+ catch-all "environment" for poor C programmers.
+
+* Meta-programming
+
+ * Plot lengths of each function
+
+ * Some kind of statistics on delta each day
+
+* Encoding format
+
+ * Include a version in the signature and difference fields
+
+ * Remember to update them if we ever ship a buggy version (nah!) so
+ that other parties can know not to trust the encoded data.
+
+* abstract encoding
+
+ In fact, we can vary on several different variables:
+
+ * what signature format are we using
+
+ * what command protocol are we using
+
+ * what search algorithm are we using?
+
+ * what implementation version are we?
+
+ Some are more likely to change than others. We need a chart
+ showing which source files depend on which variable.
+
+* Encoding algorithm
+
+ * Self-referential copy commands
+
+ Suppose we have a file with repeating blocks. The gdiff format
+ allows for COPY commands to extend into the *output* file so that
+ they can easily point this out. By doing this, they get
+ compression as well as differencing.
+
+ It'd be pretty simple to implement this, I think: as we produce
+ output, we'd also generate checksums (using the search block
+ size), and add them to the sum set. Then matches will fall out
+ automatically, although we might have to specially allow for
+ short blocks.
+
+ However, I don't see many files which have repeated 1kB chunks,
+ so I don't know if it would be worthwhile.
+
+* Support compression of the difference stream. Does this
+ belong here, or should it be in the client and librsync just have
+ an interface that lets it cleanly plug in?
+
+ I think if we're going to just do plain gzip, rather than
+ rsync-gzip, then it might as well be external.
+
+ rsync-gzip: preload with the omitted text so as to get better
+ compression. Abo thinks this gets significantly better
+ compression. On the other hand we have to important and maintain
+ our own zlib fork, at least until we can persuade the upstream to
+ take the necessary patch. Can that be done?
+
+ abo says
+
+ It does get better compression, but at a price. I actually
+ think that getting the code to a point where a feature like
+ this can be easily added or removed is more important than the
+ feature itself. Having generic pre and post processing layers
+ for hit/miss data would be useful. I would not like to see it
+ added at all if it tangled and complicated the code.
+
+ It also doesn't require a modified zlib... pysync uses the
+ standard zlib to do it by compressing the data, then throwing
+ it away. I don't know how much benefit the rsync modifications
+ to zlib actually are, but if I was implementing it I would
+ stick to a stock zlib until it proved significantly better to
+ go with the fork.
+
+* Licensing
+
+ Will the GNU Lesser GPL work? Specifically, will it be a problem
+ in distributing this with Mozilla or Apache?
+
+* Testing
+
+ * Just more testing in general.
+
+ * Test broken pipes and that IO errors are handled properly.
+
+ * Test files >2GB, >4GB. Presumably these must be done in streams
+ so that the disk requirements to run the test suite are not too
+ ridiculous. I wonder if it will take too long to run these
+ tests? Probably, but perhaps we can afford to run just one
+ carefully-chosen test.
+
+ * Fuzz instruction streams. <https://code.google.com/p/american-fuzzy-lop/>?
+
+ * Generate random data; do random mutations.
+
+ * Tests should fail if they can't find their inputs, or have zero
+ inputs: at present they tend to succeed by default.
+
+* Security audit
+
+ * If this code was to read differences or sums from random machines
+ on the network, then it's a security boundary. Make sure that
+ corrupt input data can't make the program crash or misbehave.
diff --git a/cmake/FindPOPT.cmake b/cmake/FindPOPT.cmake
new file mode 100644
index 0000000..1dd114f
--- /dev/null
+++ b/cmake/FindPOPT.cmake
@@ -0,0 +1,79 @@
+#--------------------------------------------------------------------------------
+# Copyright (C) 2012-2013, Lars Baehren <lbaehren@gmail.com>
+# Copyright (C) 2015 Adam Schubert <adam.schubert@sg1-game.net>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#--------------------------------------------------------------------------------
+
+# - Check for the presence of POPT
+#
+# The following vars can be set to change behaviour;
+# POPT_ROOT_DIR - path hint for finding popt.
+# POPT_INCLUDE_DIR - cached override for POPT_INCLUDE_DIRS.
+# POPT_LIBRARY_RELEASE - cached override for POPT_LIBRARIES.
+#
+# The following variables are set when POPT is found:
+# POPT_FOUND = Set to true, if all components of POPT have been found.
+# POPT_INCLUDE_DIRS = Include path for the header files of POPT.
+# POPT_LIBRARIES = Link these to use POPT.
+
+# Check with PkgConfig (to retrieve static dependencies such as iconv)
+find_package(PkgConfig)
+if (PKG_CONFIG_FOUND)
+ pkg_search_module (POPT QUIET IMPORTED_TARGET popt)
+ if (POPT_FOUND)
+ # PkgConfig found it, set cached vars to use the imported target it created.
+ set(POPT_INCLUDE_DIR "" CACHE PATH "Path to headers for popt.")
+ set(POPT_LIBRARY_RELEASE PkgConfig::POPT CACHE FILEPATH "Path to library for popt.")
+ endif (POPT_FOUND)
+endif (PKG_CONFIG_FOUND)
+
+# Fallback to searching for path and library if PkgConfig didn't work.
+if (NOT POPT_FOUND)
+ find_path (POPT_INCLUDE_DIR popt.h
+ HINTS ${POPT_ROOT_DIR} ${CMAKE_INSTALL_PREFIX} $ENV{programfiles}\\GnuWin32 $ENV{programfiles32}\\GnuWin32
+ PATH_SUFFIXES include)
+ find_library (POPT_LIBRARY_RELEASE popt
+ HINTS ${POPT_ROOT_DIR} ${CMAKE_INSTALL_PREFIX} $ENV{programfiles}\\GnuWin32 $ENV{programfiles32}\\GnuWin32
+ PATH_SUFFIXES lib)
+endif (NOT POPT_FOUND)
+
+# Check library and paths and set POPT_FOUND appropriately.
+INCLUDE(FindPackageHandleStandardArgs)
+if (TARGET "${POPT_LIBRARY_RELEASE}")
+ # The library is a taget created by PkgConfig.
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(POPT
+ REQUIRED_VARS POPT_LIBRARY_RELEASE
+ VERSION_VAR POPT_VERSION)
+else ()
+ # The library is a library file and header include path.
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(POPT DEFAULT_MSG POPT_LIBRARY_RELEASE POPT_INCLUDE_DIR)
+endif ()
+
+# Set output vars from auto-detected/cached vars.
+if (POPT_FOUND)
+ set(POPT_INCLUDE_DIRS "${POPT_INCLUDE_DIR}")
+ set(POPT_LIBRARIES "${POPT_LIBRARY_RELEASE}")
+endif (POPT_FOUND)
+
+# Mark cache vars as advanced.
+mark_as_advanced (POPT_INCLUDE_DIR POPT_LIBRARY_RELEASE)
diff --git a/cmake/Findlibb2.cmake b/cmake/Findlibb2.cmake
new file mode 100644
index 0000000..8e3644d
--- /dev/null
+++ b/cmake/Findlibb2.cmake
@@ -0,0 +1,24 @@
+# - Check for the presence of libb2
+#
+# The following vars can be set to change behaviour;
+# LIBB2_INCLUDE_DIR - cached override for LIBB2_INCLUDE_DIRS.
+# LIBB2_LIBRARY_RELEASE - cached override for LIBB2_LIBRARIES.
+#
+# The following variables are set when libb2 is found:
+# LIBB2_FOUND = Set to true, if all components of libb2 have been found.
+# LIBB2_INCLUDE_DIRS = Include path for the header files of libb2.
+# LIBB2_LIBRARIES = Link these to use libb2.
+
+find_path (LIBB2_INCLUDE_DIR blake2.h)
+find_library (LIBB2_LIBRARY_RELEASE b2)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS (LIBB2 DEFAULT_MSG LIBB2_LIBRARY_RELEASE LIBB2_INCLUDE_DIR)
+
+# Set output vars from auto-detected/cached vars.
+if (LIBB2_FOUND)
+ set(LIBB2_INCLUDE_DIRS "${LIBB2_INCLUDE_DIR}")
+ set(LIBB2_LIBRARIES "${LIBB2_LIBRARY_RELEASE}")
+endif (LIBB2_FOUND)
+
+mark_as_advanced (LIBB2_INCLUDE_DIR LIBB2_LIBRARY_RELEASE)
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..5c43fc5
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,46 @@
+librsync (0.9.6-2) unstable; urgency=low
+
+ * Manually install the rdiff bin because it wasn't anymore.
+ Closes: #205469.
+ * Fixed description. Closes: #191658.
+
+ -- John Goerzen <jgoerzen@complete.org> Mon, 18 Aug 2003 11:25:03 -0500
+
+librsync (0.9.6-1) unstable; urgency=low
+
+ * New upstream release
+
+ -- John Goerzen <jgoerzen@complete.org> Mon, 11 Aug 2003 17:36:26 -0500
+
+librsync (0.9.5.1-3) unstable; urgency=low
+
+ * Ran autoreconf --force, then rebuilt. Should make mips even happier
+ now. Closes: #180005.
+
+ -- John Goerzen <jgoerzen@complete.org> Fri, 7 Feb 2003 14:06:35 -0600
+
+librsync (0.9.5.1-2) unstable; urgency=low
+
+ * Copied /usr/share/misc/config.{guess,sub} over the package defaults.
+ This is apparently needed for the mips arch. Closes: #172497.
+
+ -- John Goerzen <jgoerzen@complete.org> Wed, 5 Feb 2003 15:00:55 -0600
+
+librsync (0.9.5.1-1) unstable; urgency=low
+
+ * New upstream release
+
+ -- John Goerzen <jgoerzen@complete.org> Tue, 3 Dec 2002 15:04:04 -0600
+
+librsync (0.9.5-2) unstable; urgency=low
+
+ * Applied patch from Mark van Walraven. Closes: #149267.
+
+ -- John Goerzen <jgoerzen@complete.org> Fri, 26 Jul 2002 15:05:42 -0500
+
+librsync (0.9.5-1) unstable; urgency=low
+
+ * Initial Release, lintian-clean. Closes: #133441.
+
+ -- John Goerzen <jgoerzen@complete.org> Mon, 11 Feb 2002 13:03:19 -0500
+
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..fc89e01
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,30 @@
+Source: librsync
+Section: utils
+Priority: optional
+Maintainer: John Goerzen <jgoerzen@complete.org>
+Build-Depends: debhelper (>> 3.0.0), libpopt-dev (>= 1.6.2), zlib1g-dev, autoconf2.13
+Standards-Version: 3.5.2
+
+Package: librsync1
+Section: libs
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: Binary diff library based on the rsync algorithm
+ librsync is the next generation of librsync, and provides flexible
+ checksum-based differencing. The main application at the moment in
+ rproxy, but the library should eventually be generally useful.
+
+Package: librsync-dev
+Section: devel
+Architecture: any
+Depends: librsync1 (= ${Source-Version}), libc6-dev
+Description: Binary diff library based on the rsync algorithm
+ These are the development files for librsync1.
+
+Package: rdiff
+Section: utils
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: Binary diff tool for signature-based differences
+ rdiff is a little like diff and patch all rolled into one, with
+ support for binary files.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..d14ca09
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,12 @@
+This package was debianized by John Goerzen <jgoerzen@complete.org> on
+Mon, 11 Feb 2002 13:03:19 -0500.
+
+The homepage is http://librsync.sourcefrog.net/.
+
+Upstream Author(s): Martin Pool <mbp@sourcefrog.net>
+Andrew Tridgell <tridge@samba.org>
+
+
+Copyright:
+
+GNU LGPL version 2.1, found at /usr/share/common-licenses/LGPL-2.1
diff --git a/debian/dirs b/debian/dirs
new file mode 100644
index 0000000..ca882bb
--- /dev/null
+++ b/debian/dirs
@@ -0,0 +1,2 @@
+usr/bin
+usr/sbin
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 0000000..e7769c9
--- /dev/null
+++ b/debian/docs
@@ -0,0 +1,5 @@
+NEWS
+README
+README.CVS
+TODO
+libversions.txt
diff --git a/debian/librsync-dev.dirs b/debian/librsync-dev.dirs
new file mode 100644
index 0000000..4418816
--- /dev/null
+++ b/debian/librsync-dev.dirs
@@ -0,0 +1,2 @@
+usr/lib
+usr/include
diff --git a/debian/librsync-dev.files b/debian/librsync-dev.files
new file mode 100644
index 0000000..55f55ea
--- /dev/null
+++ b/debian/librsync-dev.files
@@ -0,0 +1,4 @@
+usr/include/*
+usr/lib/lib*.a
+usr/lib/lib*.la
+usr/lib/lib*.so
diff --git a/debian/librsync1.dirs b/debian/librsync1.dirs
new file mode 100644
index 0000000..6845771
--- /dev/null
+++ b/debian/librsync1.dirs
@@ -0,0 +1 @@
+usr/lib
diff --git a/debian/librsync1.files b/debian/librsync1.files
new file mode 100644
index 0000000..1ff7a2f
--- /dev/null
+++ b/debian/librsync1.files
@@ -0,0 +1,2 @@
+usr/lib/lib*.so.*
+usr/share/man/man3/*
diff --git a/debian/rdiff.files b/debian/rdiff.files
new file mode 100644
index 0000000..68671de
--- /dev/null
+++ b/debian/rdiff.files
@@ -0,0 +1,2 @@
+usr/bin/*
+usr/share/man/man1/*
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..566b7d5
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,95 @@
+#!/usr/bin/make -f
+# Sample debian/rules that uses debhelper.
+# GNU copyright 1997 to 1999 by Joey Hess.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# This is the debhelper compatability version to use.
+export DH_COMPAT=3
+
+# shared library versions, option 1
+version=2.0.5
+major=2
+# option 2, assuming the library is created as src/.libs/libfoo.so.2.0.5 or so
+#version=`ls src/.libs/lib*.so.* | \
+# awk '{if (match($$0,/[0-9]+\.[0-9]+\.[0-9]+$$/)) print substr($$0,RSTART)}'`
+#major=`ls src/.libs/lib*.so.* | \
+# awk '{if (match($$0,/\.so\.[0-9]+$$/)) print substr($$0,RSTART+4)}'`
+
+configure: configure-stamp
+configure-stamp:
+ dh_testdir
+ # Add here commands to configure the package.
+ ./configure --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --enable-shared
+
+ touch configure-stamp
+
+build: build-stamp
+build-stamp: configure-stamp
+ dh_testdir
+
+ # Add here commands to compile the package.
+ $(MAKE) all check
+
+ touch build-stamp
+
+clean:
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp configure-stamp
+
+ # Add here commands to clean up after the build process.
+ -$(MAKE) distclean
+
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ # Add here commands to install the package into debian/tmp
+ $(MAKE) install prefix=$(CURDIR)/debian/tmp/usr
+ -mkdir debian/tmp/usr/bin
+ cp .libs/rdiff debian/tmp/usr/bin
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+ dh_testdir
+ dh_testroot
+ dh_movefiles
+
+# dh_installdebconf
+ dh_installdocs
+ dh_installexamples
+ dh_installmenu
+# dh_installlogrotate
+# dh_installemacsen
+# dh_installpam
+# dh_installmime
+# dh_installinit
+ dh_installcron
+ dh_installman
+ dh_installinfo
+# dh_undocumented
+ dh_installchangelogs NEWS
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+ dh_makeshlibs
+ dh_installdeb
+# dh_perl
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 0000000..25b4595
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,6 @@
+# Example watch control file for uscan
+# Rename this file to "watch" and then you can run the "uscan" command
+# to check for upstream updates and more.
+# Site Directory Pattern Version Script
+#sunsite.unc.edu /pub/Linux/Incoming librsync-(.*)\.tar\.gz debian uupdate
+ftp.sourceforge.net /pub/sourceforge/rproxy librsync-(.*)\.tar\.gz debian uupdate
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644
index 0000000..1ce6651
--- /dev/null
+++ b/doc/Doxyfile.in
@@ -0,0 +1,2523 @@
+# Doxyfile 1.8.16
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = librsync
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = @LIBRSYNC_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = .
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all generated output in the proper direction.
+# Possible values are: None, LTR, RTL and Context.
+# The default value is: None.
+
+OUTPUT_TEXT_DIRECTION = None
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = YES
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines (in the resulting output). You can put ^^ in the value part of an
+# alias to insert a newline as if a physical newline was in the original file.
+# When you need a literal { or } or , in the value part of an alias you have to
+# escape them by means of a backslash (\), this can lead to conflicts with the
+# commands \{ and \} for these it is advised to use the version @{ and @} or use
+# a double escape (\\{ and \\})
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,
+# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is
+# Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 5
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# (including Cygwin) ands Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = NO
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation. If
+# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = @CMAKE_CURRENT_SOURCE_DIR@/src \
+ @CMAKE_CURRENT_SOURCE_DIR@ \
+ @CMAKE_CURRENT_SOURCE_DIR@/doc
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS = *.c \
+ *.h \
+ *.dox \
+ *.md
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS = _*
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = README.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = NO
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files
+# were built. This is equivalent to specifying the "-p" option to a clang tool,
+# such as clang-check. These options will then be passed to the parser.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+
+CLANG_DATABASE_PATH =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER = @CMAKE_CURRENT_SOURCE_DIR@/doc/header.html
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER = @CMAKE_CURRENT_SOURCE_DIR@/doc/footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET = @CMAKE_CURRENT_SOURCE_DIR@/doc/doxygen.css
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via Javascript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have Javascript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: https://developer.apple.com/xcode/), introduced with OSX
+# 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: https://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = YES
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = YES
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = ENTRY=ENTRY \
+ KEY=KEY \
+ MATCH=MATCH \
+ NAME=NAME
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = NO
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/doc/DoxygenLayout.xml b/doc/DoxygenLayout.xml
new file mode 100644
index 0000000..c7e65b9
--- /dev/null
+++ b/doc/DoxygenLayout.xml
@@ -0,0 +1,194 @@
+<doxygenlayout version="1.0">
+ <!-- Generated by doxygen 1.8.10 -->
+ <!-- Navigation index tabs for HTML output -->
+ <navindex>
+ <tab type="mainpage" visible="yes" title=""/>
+ <tab type="pages" visible="yes" title="" intro=""/>
+ <tab type="modules" visible="yes" title="" intro=""/>
+ <tab type="namespaces" visible="yes" title="">
+ <tab type="namespacelist" visible="yes" title="" intro=""/>
+ <tab type="namespacemembers" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="classes" visible="yes" title="">
+ <tab type="classlist" visible="yes" title="" intro=""/>
+ <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
+ <tab type="hierarchy" visible="yes" title="" intro=""/>
+ <tab type="classmembers" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="files" visible="yes" title="">
+ <tab type="filelist" visible="yes" title="" intro=""/>
+ <tab type="globals" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="examples" visible="yes" title="" intro=""/>
+ </navindex>
+
+ <!-- Layout definition for a class page -->
+ <class>
+ <briefdescription visible="yes"/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <inheritancegraph visible="$CLASS_GRAPH"/>
+ <collaborationgraph visible="$COLLABORATION_GRAPH"/>
+ <memberdecl>
+ <nestedclasses visible="yes" title=""/>
+ <publictypes title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <publicslots title=""/>
+ <signals title=""/>
+ <publicmethods title=""/>
+ <publicstaticmethods title=""/>
+ <publicattributes title=""/>
+ <publicstaticattributes title=""/>
+ <protectedtypes title=""/>
+ <protectedslots title=""/>
+ <protectedmethods title=""/>
+ <protectedstaticmethods title=""/>
+ <protectedattributes title=""/>
+ <protectedstaticattributes title=""/>
+ <packagetypes title=""/>
+ <packagemethods title=""/>
+ <packagestaticmethods title=""/>
+ <packageattributes title=""/>
+ <packagestaticattributes title=""/>
+ <properties title=""/>
+ <events title=""/>
+ <privatetypes title=""/>
+ <privateslots title=""/>
+ <privatemethods title=""/>
+ <privatestaticmethods title=""/>
+ <privateattributes title=""/>
+ <privatestaticattributes title=""/>
+ <friends title=""/>
+ <related title="" subtitle=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <constructors title=""/>
+ <functions title=""/>
+ <related title=""/>
+ <variables title=""/>
+ <properties title=""/>
+ <events title=""/>
+ </memberdef>
+ <allmemberslink visible="yes"/>
+ <usedfiles visible="$SHOW_USED_FILES"/>
+ <authorsection visible="yes"/>
+ </class>
+
+ <!-- Layout definition for a namespace page -->
+ <namespace>
+ <briefdescription visible="yes"/>
+ <memberdecl>
+ <nestednamespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </namespace>
+
+ <!-- Layout definition for a file page -->
+ <file>
+ <briefdescription visible="yes"/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <includegraph visible="$INCLUDE_GRAPH"/>
+ <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
+ <sourcelink visible="yes"/>
+ <memberdecl>
+ <classes visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection/>
+ </file>
+
+ <!-- Layout definition for a group page -->
+ <group>
+ <briefdescription visible="yes"/>
+ <groupgraph visible="$GROUP_GRAPHS"/>
+ <memberdecl>
+ <nestedgroups visible="yes" title=""/>
+ <dirs visible="yes" title=""/>
+ <files visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <pagedocs/>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </group>
+
+ <!-- Layout definition for a directory page -->
+ <directory>
+ <briefdescription visible="yes"/>
+ <directorygraph visible="yes"/>
+ <memberdecl>
+ <dirs visible="yes"/>
+ <files visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ </directory>
+</doxygenlayout>
diff --git a/doc/buffer_internals.md b/doc/buffer_internals.md
new file mode 100644
index 0000000..6cca05b
--- /dev/null
+++ b/doc/buffer_internals.md
@@ -0,0 +1,84 @@
+# Buffer internals {#buffer_internals}
+
+## Input scoop
+
+A module called the *scoop* is used for buffering data going into
+librsync. It accumulates data when the application does not supply it
+in large enough chunks for librsync to make use of it.
+
+The scoop object is a set of fields in the rs_job_t object::
+
+ char *scoop_buf; /* the allocation pointer */
+ size_t scoop_alloc; /* the allocation size */
+ size_t scoop_avail; /* the data size */
+
+Data from the read callback always goes into the scoop buffer.
+
+The state functions call rs__scoop_read when they need some input
+data. If the read callback blocks, it might take multiple attempts
+before it can be filled. Each time, the state function will also need
+to block, and then be reawakened by the library.
+
+Once the scoop has been sufficiently filled, it must be completely
+consumed by the state function. This is easy if the state function
+always requests one unit of work at a time: a block, a file header
+element, etc.
+
+All this means that the valid data is always located at the start of
+the scoop, continuing for scoop_avail bytes. The library is never
+allowed to consume only part of the data.
+
+One the state function has consumed the data, it should call
+rs__scoop_reset(), which resets scoop_avail to 0.
+
+
+## Output queue
+
+The library can set up data to be written out by putting a
+pointer/length for it in the output queue::
+
+ char *outq_ptr;
+ size_t outq_bytes;
+
+The job infrastructure will make sure this is written out before the
+next call into the state machine.
+
+There is only one outq_ptr, so any given state function can only
+produce one contiguous block of output.
+
+
+## Buffer sharing
+
+The scoop buffer may be used by the output queue. This means that
+data can traverse the library with no extra copies: one copy into the
+scoop buffer, and one copy out. In this case outq_ptr points into
+scoop_buf, and outq_bytes tells how much data needs to be written.
+
+The state function calls rs__scoop_reset before returning when it is
+finished with the data in the scoop. However, the outq may still
+point into the scoop buffer, if it has not yet been able to be copied
+out. This means that there is data in the scoop beyond scoop_avail
+that must still be retained.
+
+This is safe because neither the scoop nor the state function will
+get to run before the output queue has completely drained.
+
+
+## Readahead
+
+How much readahead is required?
+
+At the moment (??) our rollsum and MD4 routines require a full
+contiguous block to calculate a checksum. This could be relaxed, at a
+possible loss of efficiency.
+
+So calculating block checksums requires one full block to be in
+memory.
+
+When applying a patch, we only need enough readahead to unpack the
+command header.
+
+When calculating a delta, we need a full block to calculate its
+checksum, plus space for the missed data. We can accumulate any
+amount of missed data before emitting it as a literal; the more we can
+accumulate the more compact the encoding will be.
diff --git a/doc/callbacks.md b/doc/callbacks.md
new file mode 100644
index 0000000..81519d6
--- /dev/null
+++ b/doc/callbacks.md
@@ -0,0 +1,103 @@
+# IO callbacks {#api_callbacks}
+
+librsync jobs use IO callbacks to read and write files in pull mode.
+It uses a "copy callback" to read data from the basis file for
+"patch" operations in both push and pull mode.
+
+These callbacks
+might write the data directly to a file or network connection, or they
+can do some additional work such as compression or encryption.
+
+Callbacks are passed a `void *` baton, which is chosen by the application when
+setting up the job. The baton can hold context or state for the
+callback, such as a file handle or descriptor.
+
+There are three types of callbacks, for input, output, and a special
+"copy callback" for random-access reads of the basis file when patching.
+
+## Input and output callbacks
+
+Input and output callbacks are both of type ::rs_driven_cb. These
+are used for all operations in pull mode only (see \ref api_pull).
+
+The callbacks are passed to rs_job_drive() and are called repeatedly
+until the job completes, fails, or permanently blocks.
+
+Input and output callbacks can and must choose their own buffers, which they
+provide as pointers to librsync as the job proceeds. There are many
+possibilities:
+
+ * The application may allocate a buffer when starting the job,
+ and shuffle data in and out of it as the job proceeds. As librsync
+ produces data in the output buffer, it is written out e.g. to a socket,
+ and the output pointer is then reset.
+
+ * The application may allocate a single output buffer adequate to hold all
+ the output, and then the output callback need do nothing but let librsync
+ gradually consume it.
+
+ * The input or output pointers might point into a mmap'd file.
+
+ * The input and output buffers might be provided by some other library.
+
+The caller is responsible for freeing the buffer, and for remembering where
+it previously asked librsync to write output.
+
+## Input callbacks
+
+Input callbacks are passed a ::rs_buffers_s struct into which they can store
+a pointer to the data they have read. Note that librsync does not allocate
+the buffer, the caller must do so. The input callback should update
+::rs_buffers_s::next_in, ::rs_buffers_s::avail_in, and set ::rs_buffers_s::eof_in
+if it's reached the end of the input.
+
+When an input callback reaches end-of-file and can return no more data, it
+should return ::RS_INPUT_ENDED. If the callback has just a
+little data left before end of file, then it should return that data
+with ::RS_DONE. On the next call, unless the file has grown, it can
+return ::RS_INPUT_ENDED.
+
+## Output callbacks
+
+Output callbacks are also passed a ::rs_buffers_s struct. On the first call,
+the output callback should store a pointer to its buffer into
+::rs_buffers_s::next_out, and the length into ::rs_buffers_s::avail_out. On
+subsequent calls, librsync will have used some of this buffer and updated
+those fields. The caller should then write out the used buffer space,
+and possibly update the buffer to the place it wants new output to go.
+
+If the callback processes only part of the requested data, it should
+still return ::RS_DONE.
+In this case librsync will call the callback again later
+until it either completes, fails, or blocks.
+
+The key thing to understand about ::rs_buffers_s is that the counts and
+pointers are from librsync's point of view: the next byte, and the number
+of bytes, that it should read or write.
+
+## Copy callbacks
+
+Copy callbacks are used from both push-mode (rs_job_iter()) and pull-mode
+(rs_job_drive()) invocations, only when doing a "patch" operation started by
+rs_patch_begin().
+
+Copy callbacks have type ::rs_copy_cb.
+
+Copy callbacks are directly passed a buffer and length into which they
+should write the data read from the basis file.
+
+## Callback lifecycle
+
+IO callbacks are only called from within rs_job_drive() or
+rs_job_iter().
+
+Different callbacks may be called several times in a
+single invocation of rs_job_iter() or rs_job_drive().
+
+## Return values
+
+Callbacks return a ::rs_result value to indicate success, an error, or
+being blocked.
+
+If the callbacks return an error, that error will typically be passed
+back to the application.
diff --git a/doc/downloads.md b/doc/downloads.md
new file mode 100644
index 0000000..0669a21
--- /dev/null
+++ b/doc/downloads.md
@@ -0,0 +1,9 @@
+# Downloads {#page_downloads}
+
+librsync's home is http://librsync.sourcefrog.net/ and built documentation
+is available there.
+
+Source and bug tracking is at https://github.com/librsync/librsync/.
+
+Source tarballs and git tags are at
+https://github.com/librsync/librsync/releases.
diff --git a/doc/doxygen.css b/doc/doxygen.css
new file mode 100644
index 0000000..b2c94ac
--- /dev/null
+++ b/doc/doxygen.css
@@ -0,0 +1,1454 @@
+/* The standard CSS for doxygen 1.8.10 */
+
+body, table, div, p, dl {
+ font: 400 14px/22px Roboto,sans-serif;
+}
+
+/* @group Heading Levels */
+
+h1.groupheader {
+ font-size: 150%;
+}
+
+.title {
+ font: 400 14px/28px Roboto,sans-serif;
+ font-size: 150%;
+ font-weight: bold;
+ margin: 10px 2px;
+}
+
+h2.groupheader {
+ border-bottom: 1px solid #879ECB;
+ color: #354C7B;
+ font-size: 150%;
+ font-weight: normal;
+ margin-top: 1.75em;
+ padding-top: 8px;
+ padding-bottom: 4px;
+ width: 100%;
+}
+
+h3.groupheader {
+ font-size: 100%;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ -webkit-transition: text-shadow 0.5s linear;
+ -moz-transition: text-shadow 0.5s linear;
+ -ms-transition: text-shadow 0.5s linear;
+ -o-transition: text-shadow 0.5s linear;
+ transition: text-shadow 0.5s linear;
+ margin-right: 15px;
+}
+
+h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow {
+ text-shadow: 0 0 15px cyan;
+}
+
+dt {
+ font-weight: bold;
+}
+
+div.multicol {
+ -moz-column-gap: 1em;
+ -webkit-column-gap: 1em;
+ -moz-column-count: 3;
+ -webkit-column-count: 3;
+}
+
+p.startli, p.startdd {
+ margin-top: 2px;
+}
+
+p.starttd {
+ margin-top: 0px;
+}
+
+p.endli {
+ margin-bottom: 0px;
+}
+
+p.enddd {
+ margin-bottom: 4px;
+}
+
+p.endtd {
+ margin-bottom: 2px;
+}
+
+/* @end */
+
+caption {
+ font-weight: bold;
+}
+
+span.legend {
+ font-size: 70%;
+ text-align: center;
+}
+
+h3.version {
+ font-size: 90%;
+ text-align: center;
+}
+
+div.qindex, div.navtab{
+ background-color: #EBEFF6;
+ border: 1px solid #A3B4D7;
+ text-align: center;
+}
+
+div.qindex, div.navpath {
+ width: 100%;
+ line-height: 140%;
+}
+
+div.navtab {
+ margin-right: 15px;
+}
+
+/* @group Link Styling */
+
+a {
+ color: #3D578C;
+ font-weight: normal;
+ text-decoration: none;
+}
+
+.contents a:visited {
+ color: #4665A2;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+a.qindex {
+ font-weight: bold;
+}
+
+a.qindexHL {
+ font-weight: bold;
+ background-color: #9CAFD4;
+ color: #ffffff;
+ border: 1px double #869DCA;
+}
+
+.contents a.qindexHL:visited {
+ color: #ffffff;
+}
+
+a.el {
+ font-weight: bold;
+}
+
+a.elRef {
+}
+
+a.code, a.code:visited, a.line, a.line:visited {
+ color: #4665A2;
+}
+
+a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
+ color: #4665A2;
+}
+
+/* @end */
+
+dl.el {
+ margin-left: -1cm;
+}
+
+pre.fragment {
+ border: 1px solid #C4CFE5;
+ background-color: #FBFCFD;
+ padding: 4px 6px;
+ margin: 4px 8px 4px 2px;
+ overflow: auto;
+ word-wrap: break-word;
+ font-size: 9pt;
+ line-height: 125%;
+ font-family: monospace, fixed;
+ font-size: 105%;
+}
+
+div.fragment {
+ padding: 4px 6px;
+ margin: 4px 8px 4px 2px;
+ background-color: #FBFCFD;
+ border: 1px solid #C4CFE5;
+}
+
+div.line {
+ font-family: monospace, fixed;
+ font-size: 13px;
+ min-height: 13px;
+ line-height: 1.0;
+ text-wrap: unrestricted;
+ white-space: -moz-pre-wrap; /* Moz */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ white-space: pre-wrap; /* CSS3 */
+ word-wrap: break-word; /* IE 5.5+ */
+ text-indent: -53px;
+ padding-left: 53px;
+ padding-bottom: 0px;
+ margin: 0px;
+ -webkit-transition-property: background-color, box-shadow;
+ -webkit-transition-duration: 0.5s;
+ -moz-transition-property: background-color, box-shadow;
+ -moz-transition-duration: 0.5s;
+ -ms-transition-property: background-color, box-shadow;
+ -ms-transition-duration: 0.5s;
+ -o-transition-property: background-color, box-shadow;
+ -o-transition-duration: 0.5s;
+ transition-property: background-color, box-shadow;
+ transition-duration: 0.5s;
+}
+
+div.line.glow {
+ background-color: cyan;
+ box-shadow: 0 0 10px cyan;
+}
+
+
+span.lineno {
+ padding-right: 4px;
+ text-align: right;
+ border-right: 2px solid #0F0;
+ background-color: #E8E8E8;
+ white-space: pre;
+}
+span.lineno a {
+ background-color: #D8D8D8;
+}
+
+span.lineno a:hover {
+ background-color: #C8C8C8;
+}
+
+div.ah, span.ah {
+ background-color: black;
+ font-weight: bold;
+ color: #ffffff;
+ margin-bottom: 3px;
+ margin-top: 3px;
+ padding: 0.2em;
+ border: solid thin #333;
+ border-radius: 0.5em;
+ -webkit-border-radius: .5em;
+ -moz-border-radius: .5em;
+ box-shadow: 2px 2px 3px #999;
+ -webkit-box-shadow: 2px 2px 3px #999;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));
+ background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);
+}
+
+div.classindex ul {
+ list-style: none;
+ padding-left: 0;
+}
+
+div.classindex span.ai {
+ display: inline-block;
+}
+
+div.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ font-weight: bold;
+}
+
+div.groupText {
+ margin-left: 16px;
+ font-style: italic;
+}
+
+body {
+ background-color: white;
+ color: black;
+ margin: 0;
+}
+
+div.contents {
+ margin-top: 10px;
+ margin-left: 12px;
+ margin-right: 8px;
+}
+
+td.indexkey {
+ background-color: #EBEFF6;
+ font-weight: bold;
+ border: 1px solid #C4CFE5;
+ margin: 2px 0px 2px 0;
+ padding: 2px 10px;
+ white-space: nowrap;
+ vertical-align: top;
+}
+
+td.indexvalue {
+ background-color: #EBEFF6;
+ border: 1px solid #C4CFE5;
+ padding: 2px 10px;
+ margin: 2px 0px;
+}
+
+tr.memlist {
+ background-color: #EEF1F7;
+}
+
+p.formulaDsp {
+ text-align: center;
+}
+
+img.formulaDsp {
+
+}
+
+img.formulaInl {
+ vertical-align: middle;
+}
+
+div.center {
+ text-align: center;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding: 0px;
+}
+
+div.center img {
+ border: 0px;
+}
+
+address.footer {
+ text-align: right;
+ padding-right: 12px;
+}
+
+img.footer {
+ border: 0px;
+ vertical-align: middle;
+}
+
+/* @group Code Colorization */
+
+span.keyword {
+ color: #008000
+}
+
+span.keywordtype {
+ color: #604020
+}
+
+span.keywordflow {
+ color: #e08000
+}
+
+span.comment {
+ color: #800000
+}
+
+span.preprocessor {
+ color: #806020
+}
+
+span.stringliteral {
+ color: #002080
+}
+
+span.charliteral {
+ color: #008080
+}
+
+span.vhdldigit {
+ color: #ff00ff
+}
+
+span.vhdlchar {
+ color: #000000
+}
+
+span.vhdlkeyword {
+ color: #700070
+}
+
+span.vhdllogic {
+ color: #ff0000
+}
+
+blockquote {
+ background-color: #F7F8FB;
+ border-left: 2px solid #9CAFD4;
+ margin: 0 24px 0 4px;
+ padding: 0 12px 0 16px;
+}
+
+/* @end */
+
+/*
+.search {
+ color: #003399;
+ font-weight: bold;
+}
+
+form.search {
+ margin-bottom: 0px;
+ margin-top: 0px;
+}
+
+input.search {
+ font-size: 75%;
+ color: #000080;
+ font-weight: normal;
+ background-color: #e8eef2;
+}
+*/
+
+td.tiny {
+ font-size: 75%;
+}
+
+.dirtab {
+ padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #A3B4D7;
+}
+
+th.dirtab {
+ background: #EBEFF6;
+ font-weight: bold;
+}
+
+hr {
+ height: 0px;
+ border: none;
+ border-top: 1px solid #4A6AAA;
+}
+
+hr.footer {
+ height: 1px;
+}
+
+/* @group Member Descriptions */
+
+table.memberdecls {
+ border-spacing: 0px;
+ padding: 0px;
+}
+
+.memberdecls td, .fieldtable tr {
+ -webkit-transition-property: background-color, box-shadow;
+ -webkit-transition-duration: 0.5s;
+ -moz-transition-property: background-color, box-shadow;
+ -moz-transition-duration: 0.5s;
+ -ms-transition-property: background-color, box-shadow;
+ -ms-transition-duration: 0.5s;
+ -o-transition-property: background-color, box-shadow;
+ -o-transition-duration: 0.5s;
+ transition-property: background-color, box-shadow;
+ transition-duration: 0.5s;
+}
+
+.memberdecls td.glow, .fieldtable tr.glow {
+ background-color: cyan;
+ box-shadow: 0 0 15px cyan;
+}
+
+.mdescLeft, .mdescRight,
+.memItemLeft, .memItemRight,
+.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
+ background-color: #F9FAFC;
+ border: none;
+ margin: 4px;
+ padding: 1px 0 0 8px;
+}
+
+.mdescLeft, .mdescRight {
+ padding: 0px 8px 4px 8px;
+ color: #555;
+}
+
+.memSeparator {
+ border-bottom: 1px solid #DEE4F0;
+ line-height: 1px;
+ margin: 0px;
+ padding: 0px;
+}
+
+.memItemLeft, .memTemplItemLeft {
+ white-space: nowrap;
+}
+
+.memItemRight {
+ width: 100%;
+}
+
+.memTemplParams {
+ color: #4665A2;
+ white-space: nowrap;
+ font-size: 80%;
+}
+
+/* @end */
+
+/* @group Member Details */
+
+/* Styles for detailed member documentation */
+
+.memtemplate {
+ font-size: 80%;
+ color: #4665A2;
+ font-weight: normal;
+ margin-left: 9px;
+}
+
+.memnav {
+ background-color: #EBEFF6;
+ border: 1px solid #A3B4D7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+
+.mempage {
+ width: 100%;
+}
+
+.memitem {
+ padding: 0;
+ margin-bottom: 10px;
+ margin-right: 5px;
+ -webkit-transition: box-shadow 0.5s linear;
+ -moz-transition: box-shadow 0.5s linear;
+ -ms-transition: box-shadow 0.5s linear;
+ -o-transition: box-shadow 0.5s linear;
+ transition: box-shadow 0.5s linear;
+ display: table !important;
+ width: 100%;
+}
+
+.memitem.glow {
+ box-shadow: 0 0 15px cyan;
+}
+
+.memname {
+ font-weight: bold;
+ margin-left: 6px;
+}
+
+.memname td {
+ vertical-align: bottom;
+}
+
+.memproto, dl.reflist dt {
+ border-top: 1px solid #A8B8D9;
+ border-left: 1px solid #A8B8D9;
+ border-right: 1px solid #A8B8D9;
+ padding: 6px 0px 6px 0px;
+ color: #253555;
+ font-weight: bold;
+ text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+ background-image:url('nav_f.png');
+ background-repeat:repeat-x;
+ background-color: #E2E8F2;
+ /* opera specific markup */
+ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+ /* firefox specific markup */
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+ -moz-border-radius-topright: 4px;
+ -moz-border-radius-topleft: 4px;
+ /* webkit specific markup */
+ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ -webkit-border-top-right-radius: 4px;
+ -webkit-border-top-left-radius: 4px;
+
+}
+
+.memdoc, dl.reflist dd {
+ border-bottom: 1px solid #A8B8D9;
+ border-left: 1px solid #A8B8D9;
+ border-right: 1px solid #A8B8D9;
+ padding: 6px 10px 2px 10px;
+ background-color: #FBFCFD;
+ border-top-width: 0;
+ background-image:url('nav_g.png');
+ background-repeat:repeat-x;
+ background-color: #FFFFFF;
+ /* opera specific markup */
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ /* firefox specific markup */
+ -moz-border-radius-bottomleft: 4px;
+ -moz-border-radius-bottomright: 4px;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+ /* webkit specific markup */
+ -webkit-border-bottom-left-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+}
+
+dl.reflist dt {
+ padding: 5px;
+}
+
+dl.reflist dd {
+ margin: 0px 0px 10px 0px;
+ padding: 5px;
+}
+
+.paramkey {
+ text-align: right;
+}
+
+.paramtype {
+ white-space: nowrap;
+}
+
+.paramname {
+ color: #602020;
+ white-space: nowrap;
+}
+.paramname em {
+ font-style: normal;
+}
+.paramname code {
+ line-height: 14px;
+}
+
+.params, .retval, .exception, .tparams {
+ margin-left: 0px;
+ padding-left: 0px;
+}
+
+.params .paramname, .retval .paramname {
+ font-weight: bold;
+ vertical-align: top;
+}
+
+.params .paramtype {
+ font-style: italic;
+ vertical-align: top;
+}
+
+.params .paramdir {
+ font-family: "courier new",courier,monospace;
+ vertical-align: top;
+}
+
+table.mlabels {
+ border-spacing: 0px;
+}
+
+td.mlabels-left {
+ width: 100%;
+ padding: 0px;
+}
+
+td.mlabels-right {
+ vertical-align: bottom;
+ padding: 0px;
+ white-space: nowrap;
+}
+
+span.mlabels {
+ margin-left: 8px;
+}
+
+span.mlabel {
+ background-color: #728DC1;
+ border-top:1px solid #5373B4;
+ border-left:1px solid #5373B4;
+ border-right:1px solid #C4CFE5;
+ border-bottom:1px solid #C4CFE5;
+ text-shadow: none;
+ color: white;
+ margin-right: 4px;
+ padding: 2px 3px;
+ border-radius: 3px;
+ font-size: 7pt;
+ white-space: nowrap;
+ vertical-align: middle;
+}
+
+
+
+/* @end */
+
+/* these are for tree view inside a (index) page */
+
+div.directory {
+ margin: 10px 0px;
+ border-top: 1px solid #9CAFD4;
+ border-bottom: 1px solid #9CAFD4;
+ width: 100%;
+}
+
+.directory table {
+ border-collapse:collapse;
+}
+
+.directory td {
+ margin: 0px;
+ padding: 0px;
+ vertical-align: top;
+}
+
+.directory td.entry {
+ white-space: nowrap;
+ padding-right: 6px;
+ padding-top: 3px;
+}
+
+.directory td.entry a {
+ outline:none;
+}
+
+.directory td.entry a img {
+ border: none;
+}
+
+.directory td.desc {
+ width: 100%;
+ padding-left: 6px;
+ padding-right: 6px;
+ padding-top: 3px;
+ border-left: 1px solid rgba(0,0,0,0.05);
+}
+
+.directory tr.even {
+ padding-left: 6px;
+ background-color: #F7F8FB;
+}
+
+.directory img {
+ vertical-align: -30%;
+}
+
+.directory .levels {
+ white-space: nowrap;
+ width: 100%;
+ text-align: right;
+ font-size: 9pt;
+}
+
+.directory .levels span {
+ cursor: pointer;
+ padding-left: 2px;
+ padding-right: 2px;
+ color: #3D578C;
+}
+
+.arrow {
+ color: #9CAFD4;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ cursor: pointer;
+ font-size: 80%;
+ display: inline-block;
+ width: 16px;
+ height: 22px;
+}
+
+.icon {
+ font-family: Arial, Helvetica;
+ font-weight: bold;
+ font-size: 12px;
+ height: 14px;
+ width: 16px;
+ display: inline-block;
+ background-color: #728DC1;
+ color: white;
+ text-align: center;
+ border-radius: 4px;
+ margin-left: 2px;
+ margin-right: 2px;
+}
+
+.icona {
+ width: 24px;
+ height: 22px;
+ display: inline-block;
+}
+
+.iconfopen {
+ width: 24px;
+ height: 18px;
+ margin-bottom: 4px;
+ background-image:url('folderopen.png');
+ background-position: 0px -4px;
+ background-repeat: repeat-y;
+ vertical-align:top;
+ display: inline-block;
+}
+
+.iconfclosed {
+ width: 24px;
+ height: 18px;
+ margin-bottom: 4px;
+ background-image:url('folderclosed.png');
+ background-position: 0px -4px;
+ background-repeat: repeat-y;
+ vertical-align:top;
+ display: inline-block;
+}
+
+.icondoc {
+ width: 24px;
+ height: 18px;
+ margin-bottom: 4px;
+ background-image:url('doc.png');
+ background-position: 0px -4px;
+ background-repeat: repeat-y;
+ vertical-align:top;
+ display: inline-block;
+}
+
+table.directory {
+ font: 400 14px Roboto,sans-serif;
+}
+
+/* @end */
+
+div.dynheader {
+ margin-top: 8px;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+address {
+ font-style: normal;
+ color: #2A3D61;
+}
+
+table.doxtable {
+ border-collapse:collapse;
+ margin-top: 4px;
+ margin-bottom: 4px;
+}
+
+table.doxtable td, table.doxtable th {
+ border: 1px solid #2D4068;
+ padding: 3px 7px 2px;
+}
+
+table.doxtable th {
+ background-color: #374F7F;
+ color: #FFFFFF;
+ font-size: 110%;
+ padding-bottom: 4px;
+ padding-top: 5px;
+}
+
+table.fieldtable {
+ /*width: 100%;*/
+ margin-bottom: 10px;
+ border: 1px solid #A8B8D9;
+ border-spacing: 0px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+ -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
+ box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
+}
+
+.fieldtable td, .fieldtable th {
+ padding: 3px 7px 2px;
+}
+
+.fieldtable td.fieldtype, .fieldtable td.fieldname {
+ white-space: nowrap;
+ border-right: 1px solid #A8B8D9;
+ border-bottom: 1px solid #A8B8D9;
+ vertical-align: top;
+}
+
+.fieldtable td.fieldname {
+ padding-top: 3px;
+}
+
+.fieldtable td.fielddoc {
+ border-bottom: 1px solid #A8B8D9;
+ /*width: 100%;*/
+}
+
+.fieldtable td.fielddoc p:first-child {
+ margin-top: 0px;
+}
+
+.fieldtable td.fielddoc p:last-child {
+ margin-bottom: 2px;
+}
+
+.fieldtable tr:last-child td {
+ border-bottom: none;
+}
+
+.fieldtable th {
+ background-image:url('nav_f.png');
+ background-repeat:repeat-x;
+ background-color: #E2E8F2;
+ font-size: 90%;
+ color: #253555;
+ padding-bottom: 4px;
+ padding-top: 5px;
+ text-align:left;
+ -moz-border-radius-topleft: 4px;
+ -moz-border-radius-topright: 4px;
+ -webkit-border-top-left-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ border-bottom: 1px solid #A8B8D9;
+}
+
+
+.tabsearch {
+ top: 0px;
+ left: 10px;
+ height: 36px;
+ background-image: url('tab_b.png');
+ z-index: 101;
+ overflow: hidden;
+ font-size: 13px;
+}
+
+.navpath ul
+{
+ font-size: 11px;
+ background-image:url('tab_b.png');
+ background-repeat:repeat-x;
+ background-position: 0 -5px;
+ height:30px;
+ line-height:30px;
+ color:#8AA0CC;
+ border:solid 1px #C2CDE4;
+ overflow:hidden;
+ margin:0px;
+ padding:0px;
+}
+
+.navpath li
+{
+ list-style-type:none;
+ float:left;
+ padding-left:10px;
+ padding-right:15px;
+ background-image:url('bc_s.png');
+ background-repeat:no-repeat;
+ background-position:right;
+ color:#364D7C;
+}
+
+.navpath li.navelem a
+{
+ height:32px;
+ display:block;
+ text-decoration: none;
+ outline: none;
+ color: #283A5D;
+ font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif;
+ text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+ text-decoration: none;
+}
+
+.navpath li.navelem a:hover
+{
+ color:#6884BD;
+}
+
+.navpath li.footer
+{
+ list-style-type:none;
+ float:right;
+ padding-left:10px;
+ padding-right:15px;
+ background-image:none;
+ background-repeat:no-repeat;
+ background-position:right;
+ color:#364D7C;
+ font-size: 8pt;
+}
+
+
+div.summary
+{
+ float: right;
+ font-size: 8pt;
+ padding-right: 5px;
+ width: 50%;
+ text-align: right;
+}
+
+div.summary a
+{
+ white-space: nowrap;
+}
+
+div.ingroups
+{
+ font-size: 8pt;
+ width: 50%;
+ text-align: left;
+}
+
+div.ingroups a
+{
+ white-space: nowrap;
+}
+
+div.header
+{
+ background-image:url('nav_h.png');
+ background-repeat:repeat-x;
+ background-color: #F9FAFC;
+ margin: 0px;
+ border-bottom: 1px solid #C4CFE5;
+}
+
+div.headertitle
+{
+ padding: 5px 5px 5px 10px;
+}
+
+dl
+{
+ padding: 0 0 0 10px;
+}
+
+/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */
+dl.section
+{
+ margin-left: 0px;
+ padding-left: 0px;
+}
+
+dl.note
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #D0C000;
+}
+
+dl.warning, dl.attention
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #FF0000;
+}
+
+dl.pre, dl.post, dl.invariant
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #00D000;
+}
+
+dl.deprecated
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #505050;
+}
+
+dl.todo
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #00C0E0;
+}
+
+dl.test
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #3030E0;
+}
+
+dl.bug
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #C08050;
+}
+
+dl.section dd {
+ margin-bottom: 6px;
+}
+
+
+#projectlogo
+{
+ text-align: center;
+ vertical-align: bottom;
+ border-collapse: separate;
+}
+
+#projectlogo img
+{
+ border: 0px none;
+}
+
+#projectalign
+{
+ vertical-align: middle;
+}
+
+#projectname
+{
+ font: 300% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 2px 0px;
+}
+
+#projectbrief
+{
+ font: 120% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 0px;
+}
+
+#projectnumber
+{
+ font: 50% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 0px;
+}
+
+#titlearea
+{
+ padding: 0px;
+ margin: 0px;
+ width: 100%;
+ border-bottom: 1px solid #5373B4;
+}
+
+.image
+{
+ text-align: center;
+}
+
+.dotgraph
+{
+ text-align: center;
+}
+
+.mscgraph
+{
+ text-align: center;
+}
+
+.diagraph
+{
+ text-align: center;
+}
+
+.caption
+{
+ font-weight: bold;
+}
+
+div.zoom
+{
+ border: 1px solid #90A5CE;
+}
+
+dl.citelist {
+ margin-bottom:50px;
+}
+
+dl.citelist dt {
+ color:#334975;
+ float:left;
+ font-weight:bold;
+ margin-right:10px;
+ padding:5px;
+}
+
+dl.citelist dd {
+ margin:2px 0;
+ padding:5px 0;
+}
+
+div.toc {
+ padding: 14px 25px;
+ background-color: #F4F6FA;
+ border: 1px solid #D8DFEE;
+ border-radius: 7px 7px 7px 7px;
+ float: right;
+ height: auto;
+ margin: 0 20px 10px 10px;
+ width: 200px;
+}
+
+div.toc li {
+ background: url("bdwn.png") no-repeat scroll 0 5px transparent;
+ font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif;
+ margin-top: 5px;
+ padding-left: 10px;
+ padding-top: 2px;
+}
+
+div.toc h3 {
+ font: bold 12px/1.2 Arial,FreeSans,sans-serif;
+ color: #4665A2;
+ border-bottom: 0 none;
+ margin: 0;
+}
+
+div.toc ul {
+ list-style: none outside none;
+ border: medium none;
+ padding: 0px;
+}
+
+div.toc li.level1 {
+ margin-left: 0px;
+}
+
+div.toc li.level2 {
+ margin-left: 15px;
+}
+
+div.toc li.level3 {
+ margin-left: 30px;
+}
+
+div.toc li.level4 {
+ margin-left: 45px;
+}
+
+.inherit_header {
+ font-weight: bold;
+ color: gray;
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.inherit_header td {
+ padding: 6px 0px 2px 5px;
+}
+
+.inherit {
+ display: none;
+}
+
+tr.heading h2 {
+ margin-top: 12px;
+ margin-bottom: 4px;
+}
+
+/* tooltip related style info */
+
+.ttc {
+ position: absolute;
+ display: none;
+}
+
+#powerTip {
+ cursor: default;
+ white-space: nowrap;
+ background-color: white;
+ border: 1px solid gray;
+ border-radius: 4px 4px 4px 4px;
+ box-shadow: 1px 1px 7px gray;
+ display: none;
+ font-size: smaller;
+ max-width: 80%;
+ opacity: 0.9;
+ padding: 1ex 1em 1em;
+ position: absolute;
+ z-index: 2147483647;
+}
+
+#powerTip div.ttdoc {
+ color: grey;
+ font-style: italic;
+}
+
+#powerTip div.ttname a {
+ font-weight: bold;
+}
+
+#powerTip div.ttname {
+ font-weight: bold;
+}
+
+#powerTip div.ttdeci {
+ color: #006318;
+}
+
+#powerTip div {
+ margin: 0px;
+ padding: 0px;
+ font: 12px/16px Roboto,sans-serif;
+}
+
+#powerTip:before, #powerTip:after {
+ content: "";
+ position: absolute;
+ margin: 0px;
+}
+
+#powerTip.n:after, #powerTip.n:before,
+#powerTip.s:after, #powerTip.s:before,
+#powerTip.w:after, #powerTip.w:before,
+#powerTip.e:after, #powerTip.e:before,
+#powerTip.ne:after, #powerTip.ne:before,
+#powerTip.se:after, #powerTip.se:before,
+#powerTip.nw:after, #powerTip.nw:before,
+#powerTip.sw:after, #powerTip.sw:before {
+ border: solid transparent;
+ content: " ";
+ height: 0;
+ width: 0;
+ position: absolute;
+}
+
+#powerTip.n:after, #powerTip.s:after,
+#powerTip.w:after, #powerTip.e:after,
+#powerTip.nw:after, #powerTip.ne:after,
+#powerTip.sw:after, #powerTip.se:after {
+ border-color: rgba(255, 255, 255, 0);
+}
+
+#powerTip.n:before, #powerTip.s:before,
+#powerTip.w:before, #powerTip.e:before,
+#powerTip.nw:before, #powerTip.ne:before,
+#powerTip.sw:before, #powerTip.se:before {
+ border-color: rgba(128, 128, 128, 0);
+}
+
+#powerTip.n:after, #powerTip.n:before,
+#powerTip.ne:after, #powerTip.ne:before,
+#powerTip.nw:after, #powerTip.nw:before {
+ top: 100%;
+}
+
+#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after {
+ border-top-color: #ffffff;
+ border-width: 10px;
+ margin: 0px -10px;
+}
+#powerTip.n:before {
+ border-top-color: #808080;
+ border-width: 11px;
+ margin: 0px -11px;
+}
+#powerTip.n:after, #powerTip.n:before {
+ left: 50%;
+}
+
+#powerTip.nw:after, #powerTip.nw:before {
+ right: 14px;
+}
+
+#powerTip.ne:after, #powerTip.ne:before {
+ left: 14px;
+}
+
+#powerTip.s:after, #powerTip.s:before,
+#powerTip.se:after, #powerTip.se:before,
+#powerTip.sw:after, #powerTip.sw:before {
+ bottom: 100%;
+}
+
+#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after {
+ border-bottom-color: #ffffff;
+ border-width: 10px;
+ margin: 0px -10px;
+}
+
+#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before {
+ border-bottom-color: #808080;
+ border-width: 11px;
+ margin: 0px -11px;
+}
+
+#powerTip.s:after, #powerTip.s:before {
+ left: 50%;
+}
+
+#powerTip.sw:after, #powerTip.sw:before {
+ right: 14px;
+}
+
+#powerTip.se:after, #powerTip.se:before {
+ left: 14px;
+}
+
+#powerTip.e:after, #powerTip.e:before {
+ left: 100%;
+}
+#powerTip.e:after {
+ border-left-color: #ffffff;
+ border-width: 10px;
+ top: 50%;
+ margin-top: -10px;
+}
+#powerTip.e:before {
+ border-left-color: #808080;
+ border-width: 11px;
+ top: 50%;
+ margin-top: -11px;
+}
+
+#powerTip.w:after, #powerTip.w:before {
+ right: 100%;
+}
+#powerTip.w:after {
+ border-right-color: #ffffff;
+ border-width: 10px;
+ top: 50%;
+ margin-top: -10px;
+}
+#powerTip.w:before {
+ border-right-color: #808080;
+ border-width: 11px;
+ top: 50%;
+ margin-top: -11px;
+}
+
+@media print
+{
+ #top { display: none; }
+ #side-nav { display: none; }
+ #nav-path { display: none; }
+ body { overflow:visible; }
+ h1, h2, h3, h4, h5, h6 { page-break-after: avoid; }
+ .summary { display: none; }
+ .memitem { page-break-inside: avoid; }
+ #doc-content
+ {
+ margin-left:0 !important;
+ height:auto !important;
+ width:auto !important;
+ overflow:inherit;
+ display:inline;
+ }
+}
+
diff --git a/doc/footer.html b/doc/footer.html
new file mode 100644
index 0000000..b274b00
--- /dev/null
+++ b/doc/footer.html
@@ -0,0 +1,45 @@
+<!-- HTML footer for doxygen 1.8.10-->
+<!-- start footer part -->
+<!--BEGIN GENERATE_TREEVIEW-->
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+ <ul>
+ $navpath
+ <li class="footer">$generatedby
+ <a href="http://www.doxygen.org/index.html">
+ <img class="footer" src="$relpath^doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
+ </ul>
+</div>
+<!--END GENERATE_TREEVIEW-->
+
+<!-- ad -->
+<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
+<!-- librsync -->
+<ins class="adsbygoogle"
+ style="display:block"
+ data-ad-client="ca-pub-3547096055927362"
+ data-ad-slot="8322976738"
+ data-ad-format="auto"></ins>
+<script>
+(adsbygoogle = window.adsbygoogle || []).push({});
+</script>
+
+
+<!-- analytics -->
+<script>
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+ ga('create', 'UA-71109100-1', 'auto');
+ ga('send', 'pageview');
+</script>
+
+<!--BEGIN !GENERATE_TREEVIEW-->
+<hr class="footer"/><address class="footer"><small>
+$generatedby  <a href="http://www.doxygen.org/index.html">
+<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/>
+</a> $doxygenversion
+</small></address>
+<!--END !GENERATE_TREEVIEW-->
+</body>
+</html>
diff --git a/doc/format.md b/doc/format.md
new file mode 100644
index 0000000..eb505c1
--- /dev/null
+++ b/doc/format.md
@@ -0,0 +1,79 @@
+# File formats {#page_formats}
+
+## Generalities
+
+There are two file formats used by `librsync` and `rdiff`: the
+*signature* file, which summarizes a data file, and the *delta* file,
+which describes the edits from one data file to another.
+
+librsync does not know or care about any formats in the data files.
+
+All integers are big-endian.
+
+## Magic numbers
+
+All librsync files start with a u32 \ref rs_magic_number identifying them.
+These are declared in `librsync.h`, and there are different numbers for every
+different signature and delta file type. Note magic numbers for newer file
+types are not supported by older versions of librsync. Older librsync versions
+will immediately fail with an error when they encounter file types they don't
+support.
+
+## Signatures
+
+Signatures consist of a header followed by a number of block signatures for
+each block in the data file.
+
+The signature header is:
+
+ u32 magic; // Some RS_*_SIG_MAGIC value.
+ u32 block_len; // Bytes per block.
+ u32 strong_sum_len; // Bytes per strong sum in each block.
+
+Each block signature includes a weaksum followed by a truncated strongsum hash
+for one block of `block_len` bytes from the input data file. The strongsum
+signature will be truncated to the `strong_sum_len` in the header. The final
+data block may be shorter. The number of blocks in the signature is therefore
+
+ ceil(input_len/block_len)
+
+The block signature weak checksum is used as a rolling checksum to find moved
+data, and a strong hash used to check the match is correct. The weak checksum
+is either a rollsum (based on adler32) or (better alternative) rabinkarp, and
+the strong hash is either MD4 or BLAKE2 depending on the magic number.
+
+Truncating the strongsum makes the signatures smaller at a cost of a greater
+chance of collisions. The strongsums are truncated by keeping the left most
+(first) bytes after computation.
+
+Each signature block format is (see `rs_sig_do_block`):
+
+ u32 weak_sum;
+ u8[strong_sum_len] strong_sum;
+
+## Delta files
+
+Deltas consist of the delta magic constant `RS_DELTA_MAGIC` followed by a
+series of commands. Commands tell the patch logic how to construct the result
+file (new version) from the basis file (old version).
+
+There are three kinds of commands: the literal command, the copy command, and
+the end command. A command consists of a single byte followed by zero or more
+arguments. The number and size of the arguments are defined in `prototab.c`.
+
+A literal command describes data not present in the basis file. It has one
+argument: `length`. The format is:
+
+ u8 command; // in the range 0x41 through 0x44 inclusive
+ u8[arg1_len] length;
+ u8[length] data; // new data to append
+
+A copy command describes a range of data in the basis file. It has two
+arguments: `start` and `length`. The format is:
+
+ u8 command; // in the range 0x45 through 0x54 inclusive
+ u8[arg1_len] start; // offset in the basis to begin copying data
+ u8[arg2_len] length; // number of bytes to copy from the basis
+
+The end command indicates the end of the delta file. It consists of a single
+null byte and has no arguments.
diff --git a/doc/header.html b/doc/header.html
new file mode 100644
index 0000000..c9d3c0b
--- /dev/null
+++ b/doc/header.html
@@ -0,0 +1,68 @@
+<!-- HTML header for doxygen 1.8.10-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<meta name="generator" content="Doxygen $doxygenversion"/>
+<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="$relpath^jquery.js"></script>
+<script type="text/javascript" src="$relpath^dynsections.js"></script>
+$treeview
+$search
+$mathjax
+<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
+$extrastylesheet
+</head>
+<body>
+<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+
+ <!-- ad -->
+ <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
+ <!-- librsync -->
+ <ins class="adsbygoogle"
+ style="display:block"
+ data-ad-client="ca-pub-3547096055927362"
+ data-ad-slot="8322976738"
+ data-ad-format="auto"></ins>
+ <script>
+ (adsbygoogle = window.adsbygoogle || []).push({});
+ </script>
+
+
+<!--BEGIN TITLEAREA-->
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+ <!--BEGIN PROJECT_LOGO-->
+ <td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
+ <!--END PROJECT_LOGO-->
+ <!--BEGIN PROJECT_NAME-->
+ <td id="projectalign" style="padding-left: 0.5em;">
+ <div id="projectname">$projectname
+ <!--BEGIN PROJECT_NUMBER--> <span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
+ </div>
+ <!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
+ </td>
+ <!--END PROJECT_NAME-->
+ <!--BEGIN !PROJECT_NAME-->
+ <!--BEGIN PROJECT_BRIEF-->
+ <td style="padding-left: 0.5em;">
+ <div id="projectbrief">$projectbrief</div>
+ </td>
+ <!--END PROJECT_BRIEF-->
+ <!--END !PROJECT_NAME-->
+ <!--BEGIN DISABLE_INDEX-->
+ <!--BEGIN SEARCHENGINE-->
+ <td>$searchbox</td>
+ <!--END SEARCHENGINE-->
+ <!--END DISABLE_INDEX-->
+ </tr>
+ </tbody>
+</table>
+</div>
+<!--END TITLEAREA-->
+<!-- end header part -->
diff --git a/doc/install.md b/doc/install.md
new file mode 100644
index 0000000..75709b0
--- /dev/null
+++ b/doc/install.md
@@ -0,0 +1,98 @@
+# Installing librsync {#page_install}
+
+## Requirements
+
+To build librsync you will need:
+
+* A C compiler and appropriate headers and libraries
+
+* [CMake]
+
+* Some build tool supported by CMake: [Make] is most common,
+ [Ninja] is nicer.
+
+* [popt] command line parsing library
+
+* [Doxygen] - optional, to build docs
+
+[popt]: http://rpm5.org/files/popt/
+[CMake]: http://cmake.org/
+[Doxygen]: https://www.stack.nl/~dimitri/doxygen
+[Ninja]: http://build-ninja.org
+[Make]: https://www.gnu.org/software/make/
+
+## Building
+
+Generate the Makefile by running
+
+ $ cmake .
+
+After building you can install `rdiff` and `librsync` for system-wide use.
+
+ $ make
+
+To build and run the tests:
+
+ $ make check
+
+To install:
+
+ $ sudo make install
+
+To build the documentation:
+
+ $ make doc
+
+librsync should be widely portable. Patches to fix portability bugs are
+welcome.
+
+If you are using GNU libc, you might like to use
+
+ MALLOC_CHECK_=2 ./rdiff
+
+to detect some allocation bugs.
+
+librsync has annotations for the SPLINT static checking tool.
+
+
+## Build options
+
+The build is customizable by using CMake options in the configure step:
+
+ $ cmake -D <option-name>=<value> .
+
+If you are interested in building only the `librsync` target, you can skip
+the `rdiff` build. In this way you don't need its dependencies (e.g. `popt`).
+To do that, set the `BUILD_RDIFF` option to `OFF`:
+
+ $ cmake -D BUILD_RDIFF=OFF .
+
+Be aware that many tests depend on `rdiff` executable, so when it is disabled,
+also those tests are.
+
+Compression support is under development (see
+[#8](https://github.com/librsync/librsync/issues/8)). It is so disabled by
+default. You can turn it on by using `ENABLE_COMPRESSION` option:
+
+ $ cmake -D ENABLE_COMPRESSION=ON .
+
+To build code for debug trace messages:
+
+ $ cmake -D ENABLE_TRACE=ON .
+
+## Ninja builds
+
+CMake generates input files for an underlying build tool that will actually do
+the build. Typically this is Make, but others are supported. In particular
+[Ninja] is a nice alternative. To use it:
+
+ $ cmake -G Ninja .
+ $ ninja check
+
+
+## Cygwin
+
+With Cygwin you can build using gcc as under a normal unix system. It
+is also possible to compile under Cygwin using MSVC++. You must have
+environment variables needed by MSVC set using the Vcvars32.bat
+script.
diff --git a/doc/librsync.3 b/doc/librsync.3
new file mode 100644
index 0000000..408bbbd
--- /dev/null
+++ b/doc/librsync.3
@@ -0,0 +1,71 @@
+.\"
+.\" librsync -- dynamic caching and delta update in HTTP
+.\"
+.\" Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU Lesser General Public License
+.\" as published by the Free Software Foundation; either version 2.1 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
+.\" Lesser General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU Lesser General Public
+.\" License along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.TH librsync 3 "$Date$" "Martin Pool"
+.SH NAME
+librsync \- library for delta compression of streams
+.SH SYNOPSYS
+ #include \fB<stdio.h>\fP
+.br
+ #include \fB<stdlib.h>\fP
+.br
+ #include \fB<librsync.h>\fP
+
+ cc ... \fB-lrsync\fP
+
+.SH DESCRIPTION
+The \fBlibrsync\fP library implements network delta-compression of
+streams and files. The algorithm is similar to that used in the
+\fBrsync(1)\fP and \fBxdelta(2)\fP programs, but specialized for
+transfer of arbitrary-length octet streams. Unlike most diff
+programs, \fBlibrsync\fP does not require access to both of the files
+on the same machine, but rather only a short ``signature'' of the old
+file and the complete contents of the new file.
+.PP
+The canonical use of \fBlibrsync\fP is in the \fBrproxy(8)\fP
+reference implementation of the \fIrsync\fP proposed extension to
+HTTP. It may be useful to other programs which wish to do
+delta-compression in HTTP, or within their own protocol. There are
+HTTP-specific utility functions within \fBlibrsync\fP, but they need
+not be used.
+.PP
+A number of tools such as \fBrdiff(1)\fP provide command-line and
+scriptable access to rsync functions.
+.SH "SEE ALSO"
+.BR rdiff "(1)"
+.PP
+.I rdiff and librsync Manual
+.PP
+\fIhttp://rproxy.sourceforge.net/\fP or \fIhttp://linuxcare.com.au/rproxy/\fP.
+.PP
+\fIdraft-pool-rsync\fP
+.SH BUGS
+The rsync protocol is still evolving. There may be bugs in the
+implementation. The interface may change in the future, but it is
+becoming more stable.
+.PP
+Many routines will panic in case of error rather than returning an
+error code to the caller. Patches to fix this are welcome, but at the
+current state of development aborting seems as useful as trusting to
+possibly-incomplete checking in the client.
+.SH "AUTHOR"
+Martin Pool <mbp@sourcefrog.net>, with Andrew Tridgell <tridge@samba.org>.
+.PP
+rdiff development has been supported by Linuxcare, Inc and VA Linux
+Systems.
diff --git a/doc/librsync.md b/doc/librsync.md
new file mode 100644
index 0000000..fa2007a
--- /dev/null
+++ b/doc/librsync.md
@@ -0,0 +1,51 @@
+# API Overview {#page_api}
+
+The library supports four basic operations:
+
+-# \b sig: Generating the signature S of a file A .
+-# \b loadsig: Read a signature from a file into memory.
+-# \b delta: Calculating a delta D from S and a new file B.
+-# \b patch: Applying D to A to reconstruct B.
+
+These are all available in three different modes:
+
+- \ref api_whole - for applications that just
+ want to make and use signatures and deltas on whole files
+ with a single function call.
+
+- \ref api_streaming - a "push" mode where the caller provides input and
+ output space, and rs_job_iter() makes as much progress as it can.
+
+- \ref api_pull - a "pull" mode where librsync will call application-provided
+ callbacks to fill and empty buffers.
+
+Other documentation pages:
+
+- \ref api_trace - aid debugging by showing messages about librsync's state.
+- \ref api_callbacks
+- \ref api_stats
+- \ref api_utility
+- \ref versioning
+
+The public interface to librsync is librsync.h, and other headers are internal.
+
+The librsync tree also provides the \ref page_rdiff, which makes this
+functionality available to users and scripting languages.
+
+## Naming conventions
+
+All external symbols have the prefix \c rs_, or
+\c RS_ in the case of preprocessor symbols.
+(There are some private symbols that currently don't match this, but these
+are considered to be bugs.)
+
+Symbols beginning with \c rs__ (double underscore) are private and should
+not be called from outside the library.
+
+## Threaded IO
+
+librsync may be used from threaded programs. librsync does no
+synchronization itself. Each job should be guarded by a monitor or used
+by only a single thread.
+
+Be careful that the trace functions are safe to call from multiple threads.
diff --git a/doc/pull.md b/doc/pull.md
new file mode 100644
index 0000000..a5ff14c
--- /dev/null
+++ b/doc/pull.md
@@ -0,0 +1,80 @@
+# Callback API {#api_pull}
+
+As an alternative to \ref api_streaming, librsync provides a "pull-mode"
+callback interface where it will repeatedly call application-provided
+callbacks to get more input data and to accept output data.
+
+Pull jobs are also created using rs_sig_begin(), rs_loadsig_begin,()
+rs_delta_begin(), rs_patch_begin().
+
+However, rather than calling rs_job_iter(), the application should then call
+rs_job_drive(), passing an input and an output callback. rs_job_drive() takes
+an opaque pointer for both the input and output callback: this could be a
+`FILE*` or some similar object telling them what to read and write.
+
+## Non-blocking IO
+
+The librsync interface allows non-blocking streaming processing of data.
+This means that the library will accept input and produce output when it
+suits the application. If nonblocking file IO is used and the IO
+callbacks support it, then librsync will never block waiting for IO.
+
+Normally callbacks will read/write the whole buffer when they're called,
+but in some cases they might not be able to process all of it, or
+perhaps not process any at all. This might happen if the callbacks are
+connected to a nonblocking socket. Either of two things can happen in
+this case. If the callback returns ::RS_BLOCKED, then rs_job_iter() will
+also return ::RS_BLOCKED shortly.
+
+When an IO callback blocks, it is the responsibility of the application
+to work out when it will be able to make progress and therefore when it
+is worth calling rs_job_iter() again. Typically this involves a mechanism
+like `poll` or `select` to wait for the file descriptor to be ready.
+
+## Blocking IO
+
+The IO callbacks are allowed to block.
+This will of course mean that the application's call to
+rs_job_drive() will also block.
+
+## Partial completion
+
+IO callbacks are also allowed to process or provide only part of the requested
+data, as will commonly happen with socket IO.
+
+The library might not get as much input as it wanted when it is first
+called. If it gets a partial read, it needs to hold onto that
+valuable and irreplaceable data.
+
+It cannot keep it on the stack, because it will be lost if the read
+blocks. It needs to be kept in the job structure, or in somewhere
+referenced from there.
+
+The state function probably cannot proceed until it has all the needed
+input. So possibly this can be expressed at a high level of the job
+structure. Or perhaps it should just be done by each particular state
+function.
+
+When the library has output to write out, the callback might not be
+able to accept all of it at the time it is called. Deferred outgoing
+data needs to be stored in a buffer referenced from the job structure.
+
+I think it's always OK to try to flush this when entering rs_job_iter.
+I think it's OK to not do anything else until all the outgoing data
+has been flushed.
+
+In many cases we would like to pass a pointer into the input (or
+pread) buffer straight to the output callback. In other cases, we
+need a different buffer to build up literal outgoing data.
+
+librsync deals with short, bounded-size headers and checksums, and
+with arbitrarily-large streaming data. Although the commands are of
+bounded size, they are not of fixed size, because there are different
+encodings to suit different situations.
+
+The situation is very similar to fetching variable-length headers from
+a socket. We cannot read the whole command in a single input, because
+we don't know how long it is. As a general principle I think we
+should *not* read in too much data and buffer it, because this
+complicates things. Therefore we need to read the type byte first,
+and then possibly read some parameters.
diff --git a/doc/rdiff.1 b/doc/rdiff.1
new file mode 100644
index 0000000..f16fce2
--- /dev/null
+++ b/doc/rdiff.1
@@ -0,0 +1,59 @@
+.\"
+.\" librsync -- dynamic caching and delta update in HTTP
+.\"
+.\" Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au>
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU Lesser General Public License
+.\" as published by the Free Software Foundation; either version 2.1 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
+.\" Lesser General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU Lesser General Public
+.\" License along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.TH rdiff 1 "$Date$"
+.SH NAME
+rdiff \- compute and apply signature-based file differences
+.SH SYNOPSYS
+.nf
+\fBrdiff\fP [\fIoptions\fP] \fBsignature\fP \fIold-file signature-file\fP
+.PP
+\fBrdiff\fP [\fIoptions\fP] \fBdelta\fP \fIsignature-file new-file delta-file\fP
+.PP
+\fBrdiff\fP [\fIoptions\fP] \fBpatch\fP \fIold-file delta-file new-file\fP
+.fi
+.SH USAGE
+You can use \fBrdiff\fP to update files, much like \fBrsync\fP does.
+However, unlike \fBrsync\fP, \fBrdiff\fP puts you in control. There
+are three steps to updating a file: \fBsignature\fP, \fBdelta\fP, and
+\fBpatch\fP. Use the \fBsignature\fP subcommand to generate a small
+\fIsignature-file\fP from the \fIold-file\fP. Use the \fBdelta\fP
+subcommand to generate a small \fIdelta-file\fP from the \fIsignature-file\fP
+to the \fInew-file\fP. Use the \fBpatch\fP subcommand to apply the
+\fIdelta-file\fP to the \fIold-file\fP to regenerate the \fInew-file\fP.
+
+.SH DESCRIPTION
+In every case where a filename must be specified, \- may be used
+instead to mean either standard input or standard output as
+appropriate. Be aware that if you do this, you'll need to terminate your
+\fIoptions\fP with \-\- or \fBrdiff\fP will think you are passing it
+an empty option.
+.SH "RETURN VALUE"
+0 for successful completion, 1 for environmental problems (file not
+found, invalid options, IO error, etc), 2 for a corrupt file and 3 for
+an internal error or unhandled situation in librsync or rdiff.
+.SH "SEE ALSO"
+.BR librsync "(3)"
+.SH "AUTHOR"
+Martin Pool <mbp@sourcefrog.net>
+.PP
+The original rsync algorithm was discovered by Andrew Tridgell.
+.PP
+rdiff development has been supported by Linuxcare, Inc and VA Linux
+Systems.
diff --git a/doc/rdiff.md b/doc/rdiff.md
new file mode 100644
index 0000000..2310729
--- /dev/null
+++ b/doc/rdiff.md
@@ -0,0 +1,164 @@
+# rdiff command {#page_rdiff}
+
+Introduction
+============
+
+*rdiff* is a program to compute and apply network deltas. An *rdiff
+delta* is a delta between binary files, describing how a *basis* (or
+*old*) file can be automatically edited to produce a *result* (or *new*)
+file.
+
+Unlike most diff programs, librsync does not require access to both of
+the files when the diff is computed. Computing a delta requires just a
+short "signature" of the old file and the complete contents of the new
+file. The signature contains checksums for blocks of the old file. Using
+these checksums, rdiff finds matching blocks in the new file, and then
+computes the delta.
+
+rdiff deltas are usually less compact and also slower to produce than
+xdeltas or regular text diffs. If it is possible to have both the old
+and new files present when computing the delta,
+[xdelta](http://www.xcf.berkeley.edu/~jmacd/xdelta.html) will generally
+produce a much smaller file. If the files being compared are plain text,
+then GNU [diff](http://www.gnu.org/software/diffutils/diffutils.html) is
+usually a better choice, as the diffs can be viewed by humans and
+applied as inexact matches.
+
+rdiff comes into its own when it is not convenient to have both files
+present at the same time. One example of this is that the two files are
+on separate machines, and you want to transfer only the differences.
+Another example is when one of the files has been moved to archive or
+backup media, leaving only its signature.
+
+Symbolically
+
+> signature(*basis-file*) -> *sig-file*
+>
+> delta(*sig-file*, *new-file*) -> *delta-file*
+>
+> patch(*basis-file*, *delta-file*) -> *recreated-file*
+
+rdiff signatures and deltas are binary files in a format specific to
+rdiff. Signatures consist of a header, followed by a list of checksums
+for successive fixed-size blocks. Deltas consist of a header followed by
+an instruction stream, which when executed produces the output file.
+There are instructions to insert new data specified in the patch, or to
+copy data from the basis file.
+
+Unlike regular text diffs, rdiff deltas can describe sections of the
+input file which have been reordered or copied.
+
+Because block checksums are used to find identical sections, rdiff
+cannot find common sections smaller than one block, and it may not
+exactly identify common sections near changed sections. Changes that
+touch every block of the file, such as changing newlines to CRLF, are
+likely to cause no blocks to match at all.
+
+rdiff does not deal with file metadata or structure, such as filenames,
+permissions, or directories. To rdiff, a file is just a stream of bytes.
+Higher-level tools, such as
+[rdiff-backup](http://rdiff-backup.stanford.edu/) can deal with these
+issues in a way appropriate to their users.
+
+Use patterns
+============
+
+A typical application of the rsync algorithm is to transfer a file *A2*
+from a machine A to a machine B which has a similar file *A1*. This can
+be done as follows:
+
+1. B generates the rdiff signature of *A1*. Call this *S1*. B sends the
+ signature to A. (The signature is usually much smaller than the file
+ it describes.)
+2. A computes the rdiff delta between *S1* and *A2*. Call this delta
+ *D*. A sends the delta to B.
+3. B applies the delta to recreate *A2*.
+
+In cases where *A1* and *A2* contain runs of identical bytes, rdiff
+should give a significant space saving.
+
+Invoking rdiff
+==============
+
+There are three distinct modes of operation: *signature*, *delta* and
+*patch*. The mode is selected by the first command argument.
+
+signature
+---------
+
+> rdiff \[OPTIONS\] signature INPUT SIGNATURE
+
+**rdiff signature** generates a signature file from an input file. The
+signature can later be used to generate a delta relative to the old
+file.
+
+delta
+-----
+
+> rdiff \[OPTIONS\] delta SIGNATURE NEWFILE DELTA
+
+**rdiff delta** reads in a delta describing a basis file. It then
+calculates and writes a delta delta that transforms the basis into the
+new file.
+
+patch
+-----
+
+> rdiff \[OPTIONS\] patch BASIS DELTA OUTPUT
+
+rdiff applies a delta to a basis file and writes out the result.
+
+rdiff cannot update files in place: the output file must not be the same
+as the input file.
+
+rdiff does not currently check that the delta is being applied to the
+correct file. If a delta is applied to the wrong basis file, the results
+will be garbage.
+
+The basis file must allow random access. This means it must be a regular
+file rather than a pipe or socket.
+
+Global Options
+--------------
+
+These options are available for all commands.
+
+`--version` Show program version and copyright.
+
+`--help` Show brief help message.
+
+`--statistics` Show counts of internal operations.
+
+`--debug` Write debugging information to stderr.
+
+Options must be specified before the command name.
+
+Return Value
+============
+
+0: Successful completion.
+
+1: Environmental problems (file not found, invalid options, IO
+ error, etc).
+
+2: Corrupt signature or delta file.
+
+3: Internal error or unhandled situation in librsync or rdiff.
+
+Bugs
+====
+
+Unlike text patches, rdiff deltas can only be usefully applied to the
+exact basis file that they were generated from. rdiff does not protect
+against trying to apply a delta to the wrong file, though this will
+produce garbage output. It may be useful to store a hash of the file to
+which the digest is meant to be applied.
+
+Author
+======
+
+rdiff was written by Martin Pool. The original rsync algorithm was
+discovered by Andrew Tridgell.
+
+This program is part of the [librsync](http://librsync.sourcefrog.net/)
+package.
diff --git a/doc/stats.md b/doc/stats.md
new file mode 100644
index 0000000..5974ff8
--- /dev/null
+++ b/doc/stats.md
@@ -0,0 +1,24 @@
+# Stats {#api_stats}
+
+Encoding and decoding routines accumulate compression performance
+statistics, such as the number of bytes read and written, indicators
+a ::rs_stats_t structure.
+
+The particular statistics collected depend on the type
+of job.
+
+Stats may be
+converted to human-readable form or written to the log file using
+::rs_format_stats() or ::rs_log_stats() respectively.
+
+Statistics are held in a structure referenced by the job object. The
+statistics are kept up-to-date as the job runs and so can be used for
+progress indicators.
+
+::rs_job_statistics returns a pointer to statistics for the job. The
+pointer is valid throughout the life of the job, until the job is freed.
+The statistics are updated during processing and can be used to measure
+progress.
+
+Whole-file functions write statistics into a structure supplied by the caller.
+\c NULL may be passed as the \p stats pointer if you don't want the stats.
diff --git a/doc/streaming.md b/doc/streaming.md
new file mode 100644
index 0000000..449ee13
--- /dev/null
+++ b/doc/streaming.md
@@ -0,0 +1,140 @@
+# Streaming API {#api_streaming}
+
+A key design requirement for librsync is that it should handle data as
+and when the hosting application requires it. librsync can be used
+inside applications that do non-blocking IO or filtering of network
+streams, because it never does IO directly, or needs to block waiting
+for data.
+
+Arbitrary-length input and output buffers are passed to the
+library by the application, through an instance of ::rs_buffers_t. The
+library proceeds as far as it can, and returns an ::rs_result value
+indicating whether it needs more data or space.
+
+All the state needed by the library to resume processing when more
+data is available is kept in a small opaque ::rs_job_t structure.
+After creation of a job, repeated calls to rs_job_iter() in between
+filling and emptying the buffers keeps data flowing through the
+stream. The ::rs_result values returned may indicate
+
+- ::RS_DONE: processing is complete
+- ::RS_BLOCKED: processing has blocked pending more data
+- one of various possible errors in processing (see ::rs_result.)
+
+These can be converted to a human-readable string by rs_strerror().
+
+\note Smaller buffers have high relative handling costs. Application
+performance will be improved by using buffers of at least 32kb or so
+on each call.
+
+\sa \ref api_whole - Simpler but more limited interface than the streaming
+interface.
+
+\sa \ref api_pull - Intermediate-complexity callback interface.
+
+\sa \ref api_callbacks - for reading from the basis file
+when doing a "patch" operation.
+
+
+## Creating Jobs
+
+All streaming librsync jobs are initiated using a `_begin`
+function to create a ::rs_job_t object, passing in any necessary
+initialization parameters. The various jobs available are:
+
+- rs_sig_begin(): Calculate the signature of a file.
+- rs_loadsig_begin(): Load a signature into memory.
+- rs_delta_begin(): Calculate the delta between a signature and a new
+file.
+- rs_patch_begin(): Apply a delta to a basis to recreate the new
+file.
+
+Additionally, the following helper functions can be used to get the
+recommended signature arguments from the input file's size.
+
+- rs_sig_args(): Get the recommended sigature arguments from the file size.
+
+After a signature has been loaded, before it can be used to calculate a delta,
+the hashtable needs to be initialized by calling
+
+- rs_build_hash_table(): Initialized the signature hashtable.
+
+The patch job accepts the patch as input, and uses a callback to look up
+blocks within the basis file.
+
+You must configure read, write and basis callbacks after creating the
+job but before it is run.
+
+
+## Running Jobs
+
+The work of the operation is done when the application calls
+rs_job_iter(). This includes reading from input files via the callback,
+running the rsync algorithms, and writing output.
+
+The IO callbacks are only called from inside rs_job_iter(). If any of
+them return an error, rs_job_iter() will generally return the same error.
+
+When librsync needs to do input or output, it calls one of the callback
+functions. rs_job_iter() returns when the operation has completed or
+failed, or when one of the IO callbacks has blocked.
+
+rs_job_iter() will usually be called in a loop, perhaps alternating
+librsync processing with other application functions.
+
+
+## Deleting Jobs
+
+A job is deleted and its memory freed up using rs_job_free().
+
+This is typically called when the job has completed or failed. It can be
+called earlier if the application decides it wants to cancel
+processing.
+
+rs_job_free() does not delete the output of the job, such as the sumset
+loaded into memory. It does delete the job's statistics.
+
+
+## State Machine Internals
+
+Internally, the operations are implemented as state machines that move
+through various states as input and output buffers become available.
+
+All computers and programs are state machines. So why is the
+representation as a state machine a little more explicit (and perhaps
+verbose) in librsync than other places? Because we need to be able to
+let the real computer go off and do something else like waiting for
+network traffic, while still remembering where it was in the librsync
+state machine.
+
+librsync will never block waiting for IO, unless the callbacks do
+that.
+
+The current state is represented by the private field
+::rs_job_t::statefn, which points to a function with a name like
+`rs_OPERATION_s_STATE`. Every time librsync tries to make progress,
+it will call this function.
+
+The state function returns one of the ::rs_result values. The
+most important values are
+
+ * ::RS_DONE: Completed successfully.
+
+ * ::RS_BLOCKED: Cannot make further progress at this point.
+
+ * ::RS_RUNNING: The state function has neither completed nor blocked but
+ wants to be called again. **XXX**: Perhaps this should be removed?
+
+States need to correspond to suspension points. The only place the
+job can resume after blocking is at the entry to a state function.
+
+Therefore states must be "all or nothing" in that they can either
+complete, or restart without losing information.
+
+Basically every state needs to work from one input buffer to one
+output buffer.
+
+States should never generally return ::RS_DONE directly. Instead, they
+should call rs__job_done(), which sets the state function to
+rs__s_done(). This makes sure that any pending output is flushed out
+before ::RS_DONE is returned to the application.
diff --git a/doc/support.md b/doc/support.md
new file mode 100644
index 0000000..b61868d
--- /dev/null
+++ b/doc/support.md
@@ -0,0 +1,12 @@
+# Support {#page_support}
+
+There are two mailing lists:
+
+- https://groups.google.com/forum/#!forum/librsync-announce
+- https://groups.google.com/forum/#!forum/librsync
+
+There are some [questions and answers about librsync on stackoverflow.com tagged
+`librsync`][stackoverflow].
+That is a good place to see if your question has already been answered.
+
+[stackoverflow]: http://stackoverflow.com/questions/tagged/librsync
diff --git a/doc/trace.md b/doc/trace.md
new file mode 100644
index 0000000..b622739
--- /dev/null
+++ b/doc/trace.md
@@ -0,0 +1,33 @@
+# Debugging trace and error logging {#api_trace}
+
+librsync can output trace or log messages as it proceeds.
+Error
+messages supplement return codes by describing in more detail what went
+wrong. Debug messages are useful when debugging librsync or applications
+that call it.
+
+These
+follow a fairly standard priority-based filtering system
+(rs_trace_set_level()), using the same severity levels as UNIX syslog.
+Messages by default are sent to stderr, but may be passed to an
+application-provided callback (rs_trace_to(), rs_trace_fn_t()).
+
+The default configuration is that warning and error messages are written
+to stderr. This should be appropriate for many applications. If it is
+not, the level and destination of messages may be changed.
+
+Messages are passed out of librsync through a trace callback which is
+passed a severity and message string. The type for this callback is
+\ref rs_trace_fn_t.
+
+The default trace function is \ref rs_trace_stderr.
+
+The trace callback may be changed at runtime with \ref rs_trace_to.
+
+Messages from librsync are labelled with a severity indicator of
+enumerated type \ref rs_loglevel.
+
+The application may also specify a minimum severity of interest through
+\ref rs_trace_set_level.
+Messages lower than the specified level
+are discarded without being passed to the trace callback.
diff --git a/doc/utilities.md b/doc/utilities.md
new file mode 100644
index 0000000..f7d395e
--- /dev/null
+++ b/doc/utilities.md
@@ -0,0 +1,13 @@
+# Utility functions {#api_utility}
+
+Some additional functions are used internally and also exposed in the
+API:
+
+- platform independent large file utils: rs_file_open(), rs_file_close(),
+ rs_file_size(), rs_file_copy_cb().
+
+- encoding/decoding binary data: rs_base64(), rs_unbase64(),
+ rs_hexify().
+
+- MD4 message digests: rs_mdfour(), rs_mdfour_begin(),
+ rs_mdfour_update(), rs_mdfour_result().
diff --git a/doc/versioning.md b/doc/versioning.md
new file mode 100644
index 0000000..c9d3b0c
--- /dev/null
+++ b/doc/versioning.md
@@ -0,0 +1,21 @@
+# Versioning {#versioning}
+
+librsync uses the [SemVer] approach to versioning: the major version number
+changes when the API changes in an incompatible way, the minor version
+changes when new features are added, and the patchlevel changes when there
+are improvements or fixes that do not change the API.
+
+[SemVer]: http://semver.org/
+
+The solib/dylib version is simply the major number of the library version.
+
+The librsync signature and patch files are separately versioned under
+application control, by passing a ::rs_magic_number when creating a job.
+
+The library version can be checked at runtime in ::rs_librsync_version.
+
+See [NEWS.md](NEWS.md) for a list of changes.
+
+\note Only the public interface, defined in \ref librsync.h, is covered
+by the API stability contract. Internal symbols and functions may change
+without notice.
diff --git a/doc/whole.md b/doc/whole.md
new file mode 100644
index 0000000..434344f
--- /dev/null
+++ b/doc/whole.md
@@ -0,0 +1,21 @@
+# Whole-file API {#api_whole}
+
+Some applications do not require the fine-grained control over IO, but
+rather just want to process a whole file with a single call.
+librsync provides whole-file APIs to do exactly that.
+
+These functions open files, process the entire contents, and return an overall
+result. The whole-file operations are the core of the \ref page_rdiff.
+
+This interface is implemented on top of the \ref api_streaming. Processing of
+a whole file begins with creation of a ::rs_job_t object for the appropriate
+operation, just as if the application was going to do buffering itself. After
+creation, the job may be passed to rs_whole_run(), which will feed it to and
+from two FILEs as necessary until end of file is reached or the operation
+completes.
+
+\see rs_sig_args()
+\see rs_sig_file()
+\see rs_loadsig_file()
+\see rs_delta_file()
+\see rs_patch_file()
diff --git a/librsync.spec b/librsync.spec
new file mode 100644
index 0000000..40f26b7
--- /dev/null
+++ b/librsync.spec
@@ -0,0 +1,91 @@
+# This RPM supposes that you download the release zip file from github to SOURCES directory as v2.3.2.zip
+
+%define name librsync
+%define version 2.3.2
+%define gitsource https://github.com/librsync/%{name}/archive/v%{version}.zip
+
+Summary: Rsync libraries
+Name: %{name}
+Version: %{version}
+Release: 1%{?dist}
+License: LGPL
+Group: System Environment/Libraries
+Source0: %{gitsource}
+URL: http://librsync.sourcefrog.net
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+BuildRequires: zlib cmake popt-devel bzip2-devel doxygen
+
+%description
+librsync implements the "rsync" algorithm, which allows remote
+differencing of binary files. librsync computes a delta relative to a
+file's checksum, so the two files need not both be present to generate
+a delta.
+
+%package devel
+Summary: Headers and development libraries for librsync
+Group: Development/Libraries
+Requires: %{name} = %{version}
+
+%description devel
+librsync implements the "rsync" algorithm, which allows remote
+differencing of binary files. librsync computes a delta relative to a
+file's checksum, so the two files need not both be present to generate
+a delta.
+
+This package contains header files necessary for developing programs
+based on librsync.
+
+%prep
+#wget --no-check-certificate --timeout=5 -O %{_sourcedir}/v%{version}.zip %{gitsource}
+%setup
+# The next line is only needed if there are any non-upstream patches. In
+# this distribution there are none.
+#%patch
+%build
+
+# By default, cmake installs to /usr/local, need to tweak here
+cmake -DCMAKE_INSTALL_PREFIX=%{_prefix} -DCMAKE_BUILD_TYPE=Release .
+make CFLAGS="$RPM_OPT_FLAGS"
+make doc
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make DESTDIR=$RPM_BUILD_ROOT install
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%defattr(-,root,root)
+%doc AUTHORS COPYING NEWS.md README.md
+%{_bindir}/rdiff
+%{_mandir}/man1/rdiff.1.gz
+%{_libdir}/%{name}*
+%{_mandir}/man3/librsync.3.gz
+
+%files devel
+%defattr(-,root,root)
+%{_includedir}/%{name}*
+
+%changelog
+* Tue May 19 2020 Donovan Baarda <abo@minkirri.apana.org.au>
+- Prepared SPEC file for librsync 2.3.2
+* Tue May 19 2020 Donovan Baarda <abo@minkirri.apana.org.au>
+- Updated SPEC file for librsync 2.3.1
+* Tue Apr 07 2020 Donovan Baarda <abo@minkirri.apana.org.au>
+- Updated SPEC file for librsync 2.3.0
+* Wed Oct 16 2019 Donovan Baarda <abo@minkirri.apana.org.au>
+- Updated SPEC file for librsync 2.2.1
+* Wed Oct 12 2019 Donovan Baarda <abo@minkirri.apana.org.au>
+- Updated SPEC file for librsync 2.2.0
+* Sat Aug 17 2019 Donovan Baarda <abo@minkirri.apana.org.au>
+- Updated SPEC file for librsync 2.1.0
+* Tue Feb 27 2018 Orsiris de Jong <ozy@netpower>
+- Updated SPEC file for librsync 2.0.2
+- Fixed cmake paths for RHEL 7 64 bits
+- Added automatic source download using wget (for tests)
+- Updated dependencies
diff --git a/src/base64.c b/src/base64.c
new file mode 100644
index 0000000..bd3e60f
--- /dev/null
+++ b/src/base64.c
@@ -0,0 +1,89 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 2000 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include "librsync.h"
+
+/** Decode a base64 string in-place - simple and slow algorithm.
+ *
+ * See RFC1521 for the specification of base64. */
+size_t rs_unbase64(char *s)
+{
+ char const *b64 =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int bit_offset, byte_offset, idx, i, n;
+ unsigned char *d = (unsigned char *)s;
+ char *p;
+
+ n = i = 0;
+
+ while (*s && (p = strchr(b64, *s))) {
+ idx = (int)(p - b64);
+ byte_offset = (i * 6) / 8;
+ bit_offset = (i * 6) % 8;
+ d[byte_offset] &= (unsigned char)~((1 << (8 - bit_offset)) - 1);
+ if (bit_offset < 3) {
+ d[byte_offset] |= (unsigned char)(idx << (2 - bit_offset));
+ n = byte_offset + 1;
+ } else {
+ d[byte_offset] |= (unsigned char)(idx >> (bit_offset - 2));
+ d[byte_offset + 1] = (unsigned char)(idx << (8 - (bit_offset - 2)));
+ n = byte_offset + 2;
+ }
+ s++;
+ i++;
+ }
+ return n;
+}
+
+/** Encode a buffer as base64 - simple and slow algorithm. */
+void rs_base64(unsigned char const *buf, int n, char *out)
+{
+ char const *b64 =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int bytes, i;
+
+ /* work out how many bytes of output there are */
+ bytes = ((n * 8) + 5) / 6;
+
+ for (i = 0; i < bytes; i++) {
+ int byte = (i * 6) / 8;
+ int bit = (i * 6) % 8;
+
+ if (bit < 3) {
+ if (byte >= n)
+ abort();
+ *out = b64[(buf[byte] >> (2 - bit)) & 0x3F];
+ } else {
+ if (byte + 1 == n) {
+ *out = b64[(buf[byte] << (bit - 2)) & 0x3F];
+ } else {
+ *out =
+ b64[(buf[byte] << (bit - 2) | buf[byte + 1] >> (10 - bit)) &
+ 0x3F];
+ }
+ }
+ out++;
+ }
+ *out = 0;
+}
diff --git a/src/blake2/blake2-impl.h b/src/blake2/blake2-impl.h
new file mode 100644
index 0000000..2cbc0a3
--- /dev/null
+++ b/src/blake2/blake2-impl.h
@@ -0,0 +1,165 @@
+/*
+ BLAKE2 reference source code package - reference C implementations
+
+ Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
+ terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
+ your option. The terms of these licenses can be found at:
+
+ - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ - OpenSSL license : https://www.openssl.org/source/license.html
+ - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
+
+ More information about the BLAKE2 hash function can be found at
+ https://blake2.net.
+*/
+#ifndef BLAKE2_IMPL_H
+#define BLAKE2_IMPL_H
+
+#include <stdint.h>
+#include <string.h>
+#include "config.h"
+
+#ifndef WORDS_BIGENDIAN /* From librsync config.h. */
+# define NATIVE_LITTLE_ENDIAN
+#endif
+
+#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
+ #if defined(_MSC_VER)
+ #define BLAKE2_INLINE __inline
+ #elif defined(__GNUC__)
+ #define BLAKE2_INLINE __inline__
+ #else
+ #define BLAKE2_INLINE
+ #endif
+#else
+ #define BLAKE2_INLINE inline
+#endif
+
+static BLAKE2_INLINE uint32_t load32( const void *src )
+{
+#if defined(NATIVE_LITTLE_ENDIAN)
+ uint32_t w;
+ memcpy(&w, src, sizeof w);
+ return w;
+#else
+ const uint8_t *p = ( const uint8_t * )src;
+ return (( uint32_t )( p[0] ) << 0) |
+ (( uint32_t )( p[1] ) << 8) |
+ (( uint32_t )( p[2] ) << 16) |
+ (( uint32_t )( p[3] ) << 24) ;
+#endif
+}
+
+static BLAKE2_INLINE uint64_t load64( const void *src )
+{
+#if defined(NATIVE_LITTLE_ENDIAN)
+ uint64_t w;
+ memcpy(&w, src, sizeof w);
+ return w;
+#else
+ const uint8_t *p = ( const uint8_t * )src;
+ return (( uint64_t )( p[0] ) << 0) |
+ (( uint64_t )( p[1] ) << 8) |
+ (( uint64_t )( p[2] ) << 16) |
+ (( uint64_t )( p[3] ) << 24) |
+ (( uint64_t )( p[4] ) << 32) |
+ (( uint64_t )( p[5] ) << 40) |
+ (( uint64_t )( p[6] ) << 48) |
+ (( uint64_t )( p[7] ) << 56) ;
+#endif
+}
+
+static BLAKE2_INLINE uint16_t load16( const void *src )
+{
+#if defined(NATIVE_LITTLE_ENDIAN)
+ uint16_t w;
+ memcpy(&w, src, sizeof w);
+ return w;
+#else
+ const uint8_t *p = ( const uint8_t * )src;
+ return (( uint16_t )( p[0] ) << 0) |
+ (( uint16_t )( p[1] ) << 8) ;
+#endif
+}
+
+static BLAKE2_INLINE void store16( void *dst, uint16_t w )
+{
+#if defined(NATIVE_LITTLE_ENDIAN)
+ memcpy(dst, &w, sizeof w);
+#else
+ uint8_t *p = ( uint8_t * )dst;
+ *p++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w;
+#endif
+}
+
+static BLAKE2_INLINE void store32( void *dst, uint32_t w )
+{
+#if defined(NATIVE_LITTLE_ENDIAN)
+ memcpy(dst, &w, sizeof w);
+#else
+ uint8_t *p = ( uint8_t * )dst;
+ p[0] = (uint8_t)(w >> 0);
+ p[1] = (uint8_t)(w >> 8);
+ p[2] = (uint8_t)(w >> 16);
+ p[3] = (uint8_t)(w >> 24);
+#endif
+}
+
+static BLAKE2_INLINE void store64( void *dst, uint64_t w )
+{
+#if defined(NATIVE_LITTLE_ENDIAN)
+ memcpy(dst, &w, sizeof w);
+#else
+ uint8_t *p = ( uint8_t * )dst;
+ p[0] = (uint8_t)(w >> 0);
+ p[1] = (uint8_t)(w >> 8);
+ p[2] = (uint8_t)(w >> 16);
+ p[3] = (uint8_t)(w >> 24);
+ p[4] = (uint8_t)(w >> 32);
+ p[5] = (uint8_t)(w >> 40);
+ p[6] = (uint8_t)(w >> 48);
+ p[7] = (uint8_t)(w >> 56);
+#endif
+}
+
+static BLAKE2_INLINE uint64_t load48( const void *src )
+{
+ const uint8_t *p = ( const uint8_t * )src;
+ return (( uint64_t )( p[0] ) << 0) |
+ (( uint64_t )( p[1] ) << 8) |
+ (( uint64_t )( p[2] ) << 16) |
+ (( uint64_t )( p[3] ) << 24) |
+ (( uint64_t )( p[4] ) << 32) |
+ (( uint64_t )( p[5] ) << 40) ;
+}
+
+static BLAKE2_INLINE void store48( void *dst, uint64_t w )
+{
+ uint8_t *p = ( uint8_t * )dst;
+ p[0] = (uint8_t)(w >> 0);
+ p[1] = (uint8_t)(w >> 8);
+ p[2] = (uint8_t)(w >> 16);
+ p[3] = (uint8_t)(w >> 24);
+ p[4] = (uint8_t)(w >> 32);
+ p[5] = (uint8_t)(w >> 40);
+}
+
+static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c )
+{
+ return ( w >> c ) | ( w << ( 32 - c ) );
+}
+
+static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c )
+{
+ return ( w >> c ) | ( w << ( 64 - c ) );
+}
+
+/* prevents compiler optimizing out memset() */
+static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n)
+{
+ static void *(*const volatile memset_v)(void *, int, size_t) = &memset;
+ memset_v(v, 0, n);
+}
+
+#endif
diff --git a/src/blake2/blake2.h b/src/blake2/blake2.h
new file mode 100644
index 0000000..ad62f26
--- /dev/null
+++ b/src/blake2/blake2.h
@@ -0,0 +1,195 @@
+/*
+ BLAKE2 reference source code package - reference C implementations
+
+ Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
+ terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
+ your option. The terms of these licenses can be found at:
+
+ - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ - OpenSSL license : https://www.openssl.org/source/license.html
+ - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
+
+ More information about the BLAKE2 hash function can be found at
+ https://blake2.net.
+*/
+#ifndef BLAKE2_H
+#define BLAKE2_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#if defined(_MSC_VER)
+#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop))
+#else
+#define BLAKE2_PACKED(x) x __attribute__((packed))
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+ enum blake2s_constant
+ {
+ BLAKE2S_BLOCKBYTES = 64,
+ BLAKE2S_OUTBYTES = 32,
+ BLAKE2S_KEYBYTES = 32,
+ BLAKE2S_SALTBYTES = 8,
+ BLAKE2S_PERSONALBYTES = 8
+ };
+
+ enum blake2b_constant
+ {
+ BLAKE2B_BLOCKBYTES = 128,
+ BLAKE2B_OUTBYTES = 64,
+ BLAKE2B_KEYBYTES = 64,
+ BLAKE2B_SALTBYTES = 16,
+ BLAKE2B_PERSONALBYTES = 16
+ };
+
+ typedef struct blake2s_state__
+ {
+ uint32_t h[8];
+ uint32_t t[2];
+ uint32_t f[2];
+ uint8_t buf[BLAKE2S_BLOCKBYTES];
+ size_t buflen;
+ size_t outlen;
+ uint8_t last_node;
+ } blake2s_state;
+
+ typedef struct blake2b_state__
+ {
+ uint64_t h[8];
+ uint64_t t[2];
+ uint64_t f[2];
+ uint8_t buf[BLAKE2B_BLOCKBYTES];
+ size_t buflen;
+ size_t outlen;
+ uint8_t last_node;
+ } blake2b_state;
+
+ typedef struct blake2sp_state__
+ {
+ blake2s_state S[8][1];
+ blake2s_state R[1];
+ uint8_t buf[8 * BLAKE2S_BLOCKBYTES];
+ size_t buflen;
+ size_t outlen;
+ } blake2sp_state;
+
+ typedef struct blake2bp_state__
+ {
+ blake2b_state S[4][1];
+ blake2b_state R[1];
+ uint8_t buf[4 * BLAKE2B_BLOCKBYTES];
+ size_t buflen;
+ size_t outlen;
+ } blake2bp_state;
+
+
+ BLAKE2_PACKED(struct blake2s_param__
+ {
+ uint8_t digest_length; /* 1 */
+ uint8_t key_length; /* 2 */
+ uint8_t fanout; /* 3 */
+ uint8_t depth; /* 4 */
+ uint32_t leaf_length; /* 8 */
+ uint32_t node_offset; /* 12 */
+ uint16_t xof_length; /* 14 */
+ uint8_t node_depth; /* 15 */
+ uint8_t inner_length; /* 16 */
+ /* uint8_t reserved[0]; */
+ uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */
+ uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */
+ });
+
+ typedef struct blake2s_param__ blake2s_param;
+
+ BLAKE2_PACKED(struct blake2b_param__
+ {
+ uint8_t digest_length; /* 1 */
+ uint8_t key_length; /* 2 */
+ uint8_t fanout; /* 3 */
+ uint8_t depth; /* 4 */
+ uint32_t leaf_length; /* 8 */
+ uint32_t node_offset; /* 12 */
+ uint32_t xof_length; /* 16 */
+ uint8_t node_depth; /* 17 */
+ uint8_t inner_length; /* 18 */
+ uint8_t reserved[14]; /* 32 */
+ uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */
+ uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
+ });
+
+ typedef struct blake2b_param__ blake2b_param;
+
+ typedef struct blake2xs_state__
+ {
+ blake2s_state S[1];
+ blake2s_param P[1];
+ } blake2xs_state;
+
+ typedef struct blake2xb_state__
+ {
+ blake2b_state S[1];
+ blake2b_param P[1];
+ } blake2xb_state;
+
+ /* Padded structs result in a compile-time error */
+ enum {
+ BLAKE2_DUMMY_1 = 1/(sizeof(blake2s_param) == BLAKE2S_OUTBYTES),
+ BLAKE2_DUMMY_2 = 1/(sizeof(blake2b_param) == BLAKE2B_OUTBYTES)
+ };
+
+ /* Streaming API */
+ int blake2s_init( blake2s_state *S, size_t outlen );
+ int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen );
+ int blake2s_init_param( blake2s_state *S, const blake2s_param *P );
+ int blake2s_update( blake2s_state *S, const void *in, size_t inlen );
+ int blake2s_final( blake2s_state *S, void *out, size_t outlen );
+
+ int blake2b_init( blake2b_state *S, size_t outlen );
+ int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen );
+ int blake2b_init_param( blake2b_state *S, const blake2b_param *P );
+ int blake2b_update( blake2b_state *S, const void *in, size_t inlen );
+ int blake2b_final( blake2b_state *S, void *out, size_t outlen );
+
+ int blake2sp_init( blake2sp_state *S, size_t outlen );
+ int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen );
+ int blake2sp_update( blake2sp_state *S, const void *in, size_t inlen );
+ int blake2sp_final( blake2sp_state *S, void *out, size_t outlen );
+
+ int blake2bp_init( blake2bp_state *S, size_t outlen );
+ int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen );
+ int blake2bp_update( blake2bp_state *S, const void *in, size_t inlen );
+ int blake2bp_final( blake2bp_state *S, void *out, size_t outlen );
+
+ /* Variable output length API */
+ int blake2xs_init( blake2xs_state *S, const size_t outlen );
+ int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen );
+ int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen );
+ int blake2xs_final(blake2xs_state *S, void *out, size_t outlen);
+
+ int blake2xb_init( blake2xb_state *S, const size_t outlen );
+ int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen );
+ int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen );
+ int blake2xb_final(blake2xb_state *S, void *out, size_t outlen);
+
+ /* Simple API */
+ int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
+ int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
+
+ int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
+ int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
+
+ int blake2xs( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
+ int blake2xb( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
+
+ /* This is simply an alias for blake2b */
+ int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/src/blake2/blake2b-ref.c b/src/blake2/blake2b-ref.c
new file mode 100644
index 0000000..cd38b1b
--- /dev/null
+++ b/src/blake2/blake2b-ref.c
@@ -0,0 +1,379 @@
+/*
+ BLAKE2 reference source code package - reference C implementations
+
+ Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
+ terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
+ your option. The terms of these licenses can be found at:
+
+ - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ - OpenSSL license : https://www.openssl.org/source/license.html
+ - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
+
+ More information about the BLAKE2 hash function can be found at
+ https://blake2.net.
+*/
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "blake2.h"
+#include "blake2-impl.h"
+
+static const uint64_t blake2b_IV[8] =
+{
+ 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
+ 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
+ 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
+ 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
+};
+
+static const uint8_t blake2b_sigma[12][16] =
+{
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
+ { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
+ { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
+ { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
+ { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
+ { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
+ { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
+ { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
+ { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
+};
+
+
+static void blake2b_set_lastnode( blake2b_state *S )
+{
+ S->f[1] = (uint64_t)-1;
+}
+
+/* Some helper functions, not necessarily useful */
+static int blake2b_is_lastblock( const blake2b_state *S )
+{
+ return S->f[0] != 0;
+}
+
+static void blake2b_set_lastblock( blake2b_state *S )
+{
+ if( S->last_node ) blake2b_set_lastnode( S );
+
+ S->f[0] = (uint64_t)-1;
+}
+
+static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc )
+{
+ S->t[0] += inc;
+ S->t[1] += ( S->t[0] < inc );
+}
+
+static void blake2b_init0( blake2b_state *S )
+{
+ size_t i;
+ memset( S, 0, sizeof( blake2b_state ) );
+
+ for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
+}
+
+/* init xors IV with input parameter block */
+int blake2b_init_param( blake2b_state *S, const blake2b_param *P )
+{
+ const uint8_t *p = ( const uint8_t * )( P );
+ size_t i;
+
+ blake2b_init0( S );
+
+ /* IV XOR ParamBlock */
+ for( i = 0; i < 8; ++i )
+ S->h[i] ^= load64( p + sizeof( S->h[i] ) * i );
+
+ S->outlen = P->digest_length;
+ return 0;
+}
+
+
+
+int blake2b_init( blake2b_state *S, size_t outlen )
+{
+ blake2b_param P[1];
+
+ if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
+
+ P->digest_length = (uint8_t)outlen;
+ P->key_length = 0;
+ P->fanout = 1;
+ P->depth = 1;
+ store32( &P->leaf_length, 0 );
+ store32( &P->node_offset, 0 );
+ store32( &P->xof_length, 0 );
+ P->node_depth = 0;
+ P->inner_length = 0;
+ memset( P->reserved, 0, sizeof( P->reserved ) );
+ memset( P->salt, 0, sizeof( P->salt ) );
+ memset( P->personal, 0, sizeof( P->personal ) );
+ return blake2b_init_param( S, P );
+}
+
+
+int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen )
+{
+ blake2b_param P[1];
+
+ if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
+
+ if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
+
+ P->digest_length = (uint8_t)outlen;
+ P->key_length = (uint8_t)keylen;
+ P->fanout = 1;
+ P->depth = 1;
+ store32( &P->leaf_length, 0 );
+ store32( &P->node_offset, 0 );
+ store32( &P->xof_length, 0 );
+ P->node_depth = 0;
+ P->inner_length = 0;
+ memset( P->reserved, 0, sizeof( P->reserved ) );
+ memset( P->salt, 0, sizeof( P->salt ) );
+ memset( P->personal, 0, sizeof( P->personal ) );
+
+ if( blake2b_init_param( S, P ) < 0 ) return -1;
+
+ {
+ uint8_t block[BLAKE2B_BLOCKBYTES];
+ memset( block, 0, BLAKE2B_BLOCKBYTES );
+ memcpy( block, key, keylen );
+ blake2b_update( S, block, BLAKE2B_BLOCKBYTES );
+ secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
+ }
+ return 0;
+}
+
+#define G(r,i,a,b,c,d) \
+ do { \
+ a = a + b + m[blake2b_sigma[r][2*i+0]]; \
+ d = rotr64(d ^ a, 32); \
+ c = c + d; \
+ b = rotr64(b ^ c, 24); \
+ a = a + b + m[blake2b_sigma[r][2*i+1]]; \
+ d = rotr64(d ^ a, 16); \
+ c = c + d; \
+ b = rotr64(b ^ c, 63); \
+ } while(0)
+
+#define ROUND(r) \
+ do { \
+ G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
+ G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
+ G(r,2,v[ 2],v[ 6],v[10],v[14]); \
+ G(r,3,v[ 3],v[ 7],v[11],v[15]); \
+ G(r,4,v[ 0],v[ 5],v[10],v[15]); \
+ G(r,5,v[ 1],v[ 6],v[11],v[12]); \
+ G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
+ G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
+ } while(0)
+
+static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] )
+{
+ uint64_t m[16];
+ uint64_t v[16];
+ size_t i;
+
+ for( i = 0; i < 16; ++i ) {
+ m[i] = load64( block + i * sizeof( m[i] ) );
+ }
+
+ for( i = 0; i < 8; ++i ) {
+ v[i] = S->h[i];
+ }
+
+ v[ 8] = blake2b_IV[0];
+ v[ 9] = blake2b_IV[1];
+ v[10] = blake2b_IV[2];
+ v[11] = blake2b_IV[3];
+ v[12] = blake2b_IV[4] ^ S->t[0];
+ v[13] = blake2b_IV[5] ^ S->t[1];
+ v[14] = blake2b_IV[6] ^ S->f[0];
+ v[15] = blake2b_IV[7] ^ S->f[1];
+
+ ROUND( 0 );
+ ROUND( 1 );
+ ROUND( 2 );
+ ROUND( 3 );
+ ROUND( 4 );
+ ROUND( 5 );
+ ROUND( 6 );
+ ROUND( 7 );
+ ROUND( 8 );
+ ROUND( 9 );
+ ROUND( 10 );
+ ROUND( 11 );
+
+ for( i = 0; i < 8; ++i ) {
+ S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
+ }
+}
+
+#undef G
+#undef ROUND
+
+int blake2b_update( blake2b_state *S, const void *pin, size_t inlen )
+{
+ const unsigned char * in = (const unsigned char *)pin;
+ if( inlen > 0 )
+ {
+ size_t left = S->buflen;
+ size_t fill = BLAKE2B_BLOCKBYTES - left;
+ if( inlen > fill )
+ {
+ S->buflen = 0;
+ memcpy( S->buf + left, in, fill ); /* Fill buffer */
+ blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
+ blake2b_compress( S, S->buf ); /* Compress */
+ in += fill; inlen -= fill;
+ while(inlen > BLAKE2B_BLOCKBYTES) {
+ blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
+ blake2b_compress( S, in );
+ in += BLAKE2B_BLOCKBYTES;
+ inlen -= BLAKE2B_BLOCKBYTES;
+ }
+ }
+ memcpy( S->buf + S->buflen, in, inlen );
+ S->buflen += inlen;
+ }
+ return 0;
+}
+
+int blake2b_final( blake2b_state *S, void *out, size_t outlen )
+{
+ uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
+ size_t i;
+
+ if( out == NULL || outlen < S->outlen )
+ return -1;
+
+ if( blake2b_is_lastblock( S ) )
+ return -1;
+
+ blake2b_increment_counter( S, S->buflen );
+ blake2b_set_lastblock( S );
+ memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */
+ blake2b_compress( S, S->buf );
+
+ for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
+ store64( buffer + sizeof( S->h[i] ) * i, S->h[i] );
+
+ memcpy( out, buffer, S->outlen );
+ secure_zero_memory(buffer, sizeof(buffer));
+ return 0;
+}
+
+/* inlen, at least, should be uint64_t. Others can be size_t. */
+int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
+{
+ blake2b_state S[1];
+
+ /* Verify parameters */
+ if ( NULL == in && inlen > 0 ) return -1;
+
+ if ( NULL == out ) return -1;
+
+ if( NULL == key && keylen > 0 ) return -1;
+
+ if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
+
+ if( keylen > BLAKE2B_KEYBYTES ) return -1;
+
+ if( keylen > 0 )
+ {
+ if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1;
+ }
+ else
+ {
+ if( blake2b_init( S, outlen ) < 0 ) return -1;
+ }
+
+ blake2b_update( S, ( const uint8_t * )in, inlen );
+ blake2b_final( S, out, outlen );
+ return 0;
+}
+
+int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) {
+ return blake2b(out, outlen, in, inlen, key, keylen);
+}
+
+#if defined(SUPERCOP)
+int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen )
+{
+ return blake2b( out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0 );
+}
+#endif
+
+#if defined(BLAKE2B_SELFTEST)
+#include <string.h>
+#include "blake2-kat.h"
+int main( void )
+{
+ uint8_t key[BLAKE2B_KEYBYTES];
+ uint8_t buf[BLAKE2_KAT_LENGTH];
+ size_t i, step;
+
+ for( i = 0; i < BLAKE2B_KEYBYTES; ++i )
+ key[i] = ( uint8_t )i;
+
+ for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
+ buf[i] = ( uint8_t )i;
+
+ /* Test simple API */
+ for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
+ {
+ uint8_t hash[BLAKE2B_OUTBYTES];
+ blake2b( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES );
+
+ if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) )
+ {
+ goto fail;
+ }
+ }
+
+ /* Test streaming API */
+ for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) {
+ for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
+ uint8_t hash[BLAKE2B_OUTBYTES];
+ blake2b_state S;
+ uint8_t * p = buf;
+ size_t mlen = i;
+ int err = 0;
+
+ if( (err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) {
+ goto fail;
+ }
+
+ while (mlen >= step) {
+ if ( (err = blake2b_update(&S, p, step)) < 0 ) {
+ goto fail;
+ }
+ mlen -= step;
+ p += step;
+ }
+ if ( (err = blake2b_update(&S, p, mlen)) < 0) {
+ goto fail;
+ }
+ if ( (err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) {
+ goto fail;
+ }
+
+ if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) {
+ goto fail;
+ }
+ }
+ }
+
+ puts( "ok" );
+ return 0;
+fail:
+ puts("error");
+ return -1;
+}
+#endif
diff --git a/src/buf.c b/src/buf.c
new file mode 100644
index 0000000..8616c9a
--- /dev/null
+++ b/src/buf.c
@@ -0,0 +1,156 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | Pick a window, Jimmy, you're leaving.
+ */
+
+/** \file buf.c
+ * Buffers that map between stdio file streams and librsync streams.
+ *
+ * As the stream consumes input and produces output, it is refilled from
+ * appropriate input and output FILEs. A dynamically allocated buffer of
+ * configurable size is used as an intermediary.
+ *
+ * \todo Perhaps be more efficient by filling the buffer on every call even if
+ * not yet completely empty. Check that it's really our buffer, and shuffle
+ * remaining data down to the front.
+ *
+ * \todo Perhaps expose a routine for shuffling the buffers. */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include "librsync.h"
+#include "buf.h"
+#include "job.h"
+#include "trace.h"
+#include "util.h"
+
+struct rs_filebuf {
+ FILE *f;
+ char *buf;
+ size_t buf_len;
+};
+
+rs_filebuf_t *rs_filebuf_new(FILE *f, size_t buf_len)
+{
+ rs_filebuf_t *pf = rs_alloc_struct(rs_filebuf_t);
+
+ pf->buf = rs_alloc(buf_len, "file buffer");
+ pf->buf_len = buf_len;
+ pf->f = f;
+ return pf;
+}
+
+void rs_filebuf_free(rs_filebuf_t *fb)
+{
+ free(fb->buf);
+ rs_bzero(fb, sizeof *fb);
+ free(fb);
+}
+
+/* If the stream has no more data available, read some from F into BUF, and let
+ the stream use that. On return, SEEN_EOF is true if the end of file has
+ passed into the stream. */
+rs_result rs_infilebuf_fill(rs_job_t *job, rs_buffers_t *buf, void *opaque)
+{
+ size_t len;
+ rs_filebuf_t *fb = (rs_filebuf_t *)opaque;
+ FILE *f = fb->f;
+
+ /* This is only allowed if either the buf has no input buffer yet, or that
+ buffer could possibly be BUF. */
+ if (buf->next_in != NULL) {
+ assert(buf->avail_in <= fb->buf_len);
+ assert(buf->next_in >= fb->buf);
+ assert(buf->next_in <= fb->buf + fb->buf_len);
+ } else {
+ assert(buf->avail_in == 0);
+ }
+
+ if (buf->eof_in || (buf->eof_in = feof(f))) {
+ rs_trace("seen end of file on input");
+ return RS_DONE;
+ }
+
+ if (buf->avail_in)
+ /* Still some data remaining. Perhaps we should read anyhow? */
+ return RS_DONE;
+
+ len = fread(fb->buf, 1, fb->buf_len, f);
+ if (len == 0) {
+ /* This will happen if file size is a multiple of input block len */
+ if (feof(f)) {
+ rs_trace("seen end of file on input");
+ buf->eof_in = 1;
+ return RS_DONE;
+ }
+ if (ferror(f)) {
+ rs_error("error filling buf from file: %s", strerror(errno));
+ return RS_IO_ERROR;
+ } else {
+ rs_error("no error bit, but got " FMT_SIZE
+ " return when trying to read", len);
+ return RS_IO_ERROR;
+ }
+ }
+ buf->avail_in = len;
+ buf->next_in = fb->buf;
+ job->stats.in_bytes += len;
+ return RS_DONE;
+}
+
+/* The buf is already using BUF for an output buffer, and probably contains
+ some buffered output now. Write this out to F, and reset the buffer cursor. */
+rs_result rs_outfilebuf_drain(rs_job_t *job, rs_buffers_t *buf, void *opaque)
+{
+ rs_filebuf_t *fb = (rs_filebuf_t *)opaque;
+ FILE *f = fb->f;
+
+ /* This is only allowed if either the buf has no output buffer yet, or that
+ buffer could possibly be BUF. */
+ if (buf->next_out == NULL) {
+ assert(buf->avail_out == 0);
+ buf->next_out = fb->buf;
+ buf->avail_out = fb->buf_len;
+ return RS_DONE;
+ }
+
+ assert(buf->avail_out <= fb->buf_len);
+ assert(buf->next_out >= fb->buf);
+ assert(buf->next_out <= fb->buf + fb->buf_len);
+
+ size_t present = buf->next_out - fb->buf;
+ if (present > 0) {
+ size_t result = fwrite(fb->buf, 1, present, f);
+ if (present != result) {
+ rs_error("error draining buf to file: %s", strerror(errno));
+ return RS_IO_ERROR;
+ }
+ buf->next_out = fb->buf;
+ buf->avail_out = fb->buf_len;
+ job->stats.out_bytes += result;
+ }
+ return RS_DONE;
+}
diff --git a/src/buf.h b/src/buf.h
new file mode 100644
index 0000000..331e9a9
--- /dev/null
+++ b/src/buf.h
@@ -0,0 +1,30 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+typedef struct rs_filebuf rs_filebuf_t;
+
+rs_filebuf_t *rs_filebuf_new(FILE *f, size_t buf_len);
+
+void rs_filebuf_free(rs_filebuf_t *fb);
+
+rs_result rs_infilebuf_fill(rs_job_t *, rs_buffers_t *buf, void *fb);
+
+rs_result rs_outfilebuf_drain(rs_job_t *, rs_buffers_t *, void *fb);
diff --git a/src/checksum.c b/src/checksum.c
new file mode 100644
index 0000000..cb2d108
--- /dev/null
+++ b/src/checksum.c
@@ -0,0 +1,68 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 1999, 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 1996 by Andrew Tridgell
+ * Copyright (C) 1996 by Paul Mackerras
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include "checksum.h"
+#include "blake2.h"
+
+LIBRSYNC_EXPORT const int RS_MD4_SUM_LENGTH = 16;
+LIBRSYNC_EXPORT const int RS_BLAKE2_SUM_LENGTH = 32;
+
+/** A simple 32bit checksum that can be incrementally updated. */
+rs_weak_sum_t rs_calc_weak_sum(weaksum_kind_t kind, void const *buf, size_t len)
+{
+ if (kind == RS_ROLLSUM) {
+ Rollsum sum;
+ RollsumInit(&sum);
+ RollsumUpdate(&sum, buf, len);
+ return RollsumDigest(&sum);
+ } else {
+ rabinkarp_t sum;
+ rabinkarp_init(&sum);
+ rabinkarp_update(&sum, buf, len);
+ return rabinkarp_digest(&sum);
+ }
+}
+
+/** Calculate and store into SUM a strong checksum.
+ *
+ * In plain rsync, the checksum is perturbed by a seed value. This is used when
+ * retrying a failed transmission: we've discovered that the hashes collided at
+ * some point, so we're going to try again with different hashes to see if we
+ * can get it right. (Check tridge's thesis for details and to see if that's
+ * correct.)
+ *
+ * Since we can't retry I'm not sure if it's very useful for librsync, except
+ * perhaps as protection against hash collision attacks. */
+void rs_calc_strong_sum(strongsum_kind_t kind, void const *buf, size_t len,
+ rs_strong_sum_t *sum)
+{
+ if (kind == RS_MD4) {
+ rs_mdfour((unsigned char *)sum, buf, len);
+ } else {
+ blake2b_state ctx;
+ blake2b_init(&ctx, RS_MAX_STRONG_SUM_LENGTH);
+ blake2b_update(&ctx, (const uint8_t *)buf, len);
+ blake2b_final(&ctx, (uint8_t *)sum, RS_MAX_STRONG_SUM_LENGTH);
+ }
+}
diff --git a/src/checksum.h b/src/checksum.h
new file mode 100644
index 0000000..be9a8b1
--- /dev/null
+++ b/src/checksum.h
@@ -0,0 +1,136 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _CHECKSUM_H_
+# define _CHECKSUM_H_
+# include <assert.h>
+# include "librsync.h"
+# include "rollsum.h"
+# include "rabinkarp.h"
+# include "hashtable.h"
+
+/** Weaksum implementations. */
+typedef enum {
+ RS_ROLLSUM,
+ RS_RABINKARP,
+} weaksum_kind_t;
+
+/** Strongsum implementations. */
+typedef enum {
+ RS_MD4,
+ RS_BLAKE2,
+} strongsum_kind_t;
+
+/** Abstract wrapper around weaksum implementations.
+ *
+ * This is a polymorphic interface to the different rollsum implementations.
+ *
+ * Historically rollsum methods were implemented as static inline functions
+ * because they were small and needed to be fast. Now that we need to call
+ * different methods for different rollsum implementations, they are getting
+ * more complicated. Is it better to delegate calls to the right implementation
+ * using static inline switch statements, or stop inlining them and use virtual
+ * method pointers? Tests suggest inlined switch statements is faster. */
+typedef struct weaksum {
+ weaksum_kind_t kind;
+ union {
+ Rollsum rs;
+ rabinkarp_t rk;
+ } sum;
+} weaksum_t;
+
+static inline void weaksum_reset(weaksum_t *sum)
+{
+ if (sum->kind == RS_ROLLSUM)
+ RollsumInit(&sum->sum.rs);
+ else
+ rabinkarp_init(&sum->sum.rk);
+}
+
+static inline void weaksum_init(weaksum_t *sum, weaksum_kind_t kind)
+{
+ assert(kind == RS_ROLLSUM || kind == RS_RABINKARP);
+ sum->kind = kind;
+ weaksum_reset(sum);
+}
+
+static inline size_t weaksum_count(weaksum_t *sum)
+{
+ /* We take advantage of sum->sum.rs.count overlaying sum->sum.rk.count. */
+ return sum->sum.rs.count;
+}
+
+static inline void weaksum_update(weaksum_t *sum, const unsigned char *buf,
+ size_t len)
+{
+ if (sum->kind == RS_ROLLSUM)
+ RollsumUpdate(&sum->sum.rs, buf, len);
+ else
+ rabinkarp_update(&sum->sum.rk, buf, len);
+}
+
+static inline void weaksum_rotate(weaksum_t *sum, unsigned char out,
+ unsigned char in)
+{
+ if (sum->kind == RS_ROLLSUM)
+ RollsumRotate(&sum->sum.rs, out, in);
+ else
+ rabinkarp_rotate(&sum->sum.rk, out, in);
+}
+
+static inline void weaksum_rollin(weaksum_t *sum, unsigned char in)
+{
+ if (sum->kind == RS_ROLLSUM)
+ RollsumRollin(&sum->sum.rs, in);
+ else
+ rabinkarp_rollin(&sum->sum.rk, in);
+}
+
+static inline void weaksum_rollout(weaksum_t *sum, unsigned char out)
+{
+ if (sum->kind == RS_ROLLSUM)
+ RollsumRollout(&sum->sum.rs, out);
+ else
+ rabinkarp_rollout(&sum->sum.rk, out);
+}
+
+static inline rs_weak_sum_t weaksum_digest(weaksum_t *sum)
+{
+ if (sum->kind == RS_ROLLSUM)
+ /* We apply mix32() to rollsums before using them for matching. */
+ return mix32(RollsumDigest(&sum->sum.rs));
+ else
+ return rabinkarp_digest(&sum->sum.rk);
+}
+
+/** Calculate a weaksum.
+ *
+ * Note this does not apply mix32() to rollsum digests, unlike
+ * weaksum_digest(). This is because rollsums are stored raw without mix32()
+ * applied for backwards-compatibility, but we apply mix32() when adding them
+ * into a signature and when getting the digest for calculating deltas. */
+rs_weak_sum_t rs_calc_weak_sum(weaksum_kind_t kind, void const *buf,
+ size_t len);
+
+/** Calculate a strongsum. */
+void rs_calc_strong_sum(strongsum_kind_t kind, void const *buf, size_t len,
+ rs_strong_sum_t *sum);
+
+#endif /* _CHECKSUM_H_ */
diff --git a/src/command.c b/src/command.c
new file mode 100644
index 0000000..7cf7467
--- /dev/null
+++ b/src/command.c
@@ -0,0 +1,51 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 2000 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include "librsync.h"
+#include "command.h"
+
+/* For debugging purposes, here are some human-readable forms. */
+struct rs_op_kind_name const rs_op_kind_names[] = {
+ {"END", RS_KIND_END},
+ {"COPY", RS_KIND_COPY},
+ {"LITERAL", RS_KIND_LITERAL},
+ {"SIGNATURE", RS_KIND_SIGNATURE},
+ {"CHECKSUM", RS_KIND_CHECKSUM},
+ {"INVALID", RS_KIND_INVALID},
+ {NULL, 0}
+};
+
+/** Return a human-readable name for KIND. */
+char const *rs_op_kind_name(enum rs_op_kind kind)
+{
+ const struct rs_op_kind_name *k;
+
+ for (k = rs_op_kind_names; k->kind; k++) {
+ if (k->kind == kind) {
+ return k->name;
+ }
+ }
+
+ return NULL;
+}
diff --git a/src/command.h b/src/command.h
new file mode 100644
index 0000000..d125813
--- /dev/null
+++ b/src/command.h
@@ -0,0 +1,49 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- library for network deltas
+ *
+ * Copyright (C) 1999, 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 1999 by Andrew Tridgell <tridge@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** \file command.h
+ * Types of commands present in the encoding stream.
+ *
+ * The vague idea is that eventually this file will be more abstract than
+ * protocol.h, but it's not clear that will ever be required. */
+
+/** Classes of operation that can be present. Each may have several different
+ * possible representations. */
+enum rs_op_kind {
+ RS_KIND_END = 1000,
+ RS_KIND_LITERAL,
+ RS_KIND_SIGNATURE,
+ RS_KIND_COPY,
+ RS_KIND_CHECKSUM,
+ RS_KIND_RESERVED, /* for future expansion */
+
+ /* This one should never occur in file streams. It's an internal marker for
+ invalid commands. */
+ RS_KIND_INVALID
+};
+
+typedef struct rs_op_kind_name {
+ char const *name;
+ enum rs_op_kind const kind;
+} rs_op_kind_name_t;
+
+char const *rs_op_kind_name(enum rs_op_kind);
diff --git a/src/config.h.cmake b/src/config.h.cmake
new file mode 100644
index 0000000..d5b6392
--- /dev/null
+++ b/src/config.h.cmake
@@ -0,0 +1,144 @@
+/* config.h. Generated from config.h.cmake by cmake. */
+
+/* Define if building universal (internal helper macro) */
+#cmakedefine AC_APPLE_UNIVERSAL_BUILD
+
+/* Define this to enable trace code */
+#cmakedefine DO_RS_TRACE
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#cmakedefine HAVE_SYS_FILE_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#cmakedefine HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#cmakedefine HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <io.h> header file. */
+#cmakedefine HAVE_IO_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#cmakedefine HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the <mcheck.h> header file. */
+#cmakedefine HAVE_MCHECK_H 1
+
+/* Define to 1 if you have the <zlib.h> header file. */
+#cmakedefine HAVE_ZLIB_H 1
+
+/* Define to 1 if you have the <bzlib.h> header file. */
+#cmakedefine HAVE_BZLIB_H 1
+
+/* Define if your compiler has C99's __func__. */
+#cmakedefine HAVE___FUNC__
+
+/* Define if your compiler has GNU's __FUNCTION__. */
+#cmakedefine HAVE___FUNCTION__
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#cmakedefine HAVE_FSEEKO 1
+
+/* Define to 1 if fseeko64 (and presumably ftello64) exists and is declared. */
+#cmakedefine HAVE_FSEEKO64 1
+
+/* Define to 1 if _fseeki64 (and presumably _ftelli64) exists and is declared. */
+#cmakedefine HAVE__FSEEKI64 1
+
+/* Define to 1 if fstat64 exists and is declared. */
+#cmakedefine HAVE_FSTAT64 1
+
+/* Define to 1 if _fstati64 exists and is declared. */
+#cmakedefine HAVE__FSTATI64 1
+
+/* Define to 1 if fileno exists and is declared (Posix). */
+#cmakedefine HAVE_FILENO 1
+
+/* Define to 1 if _fileno exists and is declared (ISO C++). */
+#cmakedefine HAVE__FILENO 1
+
+/* Name of package */
+#define PACKAGE "${PROJECT_NAME}"
+
+/* The size of `long', as computed by sizeof. */
+#cmakedefine SIZEOF_LONG ${SIZEOF_LONG}
+
+/* The size of `long long', as computed by sizeof. */
+#cmakedefine SIZEOF_LONG_LONG ${SIZEOF_LONG_LONG}
+
+/* The size of `size_t', as computed by sizeof. */
+#cmakedefine SIZEOF_SIZE_T ${SIZEOF_SIZE_T}
+
+/* The size of `off_t', as computed by sizeof. */
+#cmakedefine SIZEOF_OFF_T ${SIZEOF_OFF_T}
+
+/* The size of `off64_t', as computed by sizeof. */
+#cmakedefine SIZEOF_OFF64_T ${SIZEOF_OFF64_T}
+
+/* The size of `unsigned int', as computed by sizeof. */
+#cmakedefine SIZEOF_UNSIGNED_INT ${SIZEOF_UNSIGNED_INT}
+
+/* The size of `unsigned long', as computed by sizeof. */
+#cmakedefine SIZEOF_UNSIGNED_LONG ${SIZEOF_UNSIGNED_LONG}
+
+/* The size of `unsigned short', as computed by sizeof. */
+#cmakedefine SIZEOF_UNSIGNED_SHORT ${SIZEOF_UNSIGNED_SHORT}
+
+/* Define to 1 if printf supports the size_t "%zu" length field. */
+#cmakedefine HAVE_PRINTF_Z 1
+
+/* FIXME Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* FIXME Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* FIXME Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* FIXME Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* FIXME Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+
+/* Version number of package */
+#define VERSION "${LIBRSYNC_VERSION}"
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#cmakedefine WORDS_BIGENDIAN 1
+
+/* FIXME Enable large inode numbers on Mac OS X 10.5. */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* FIXME Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* FIXME Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+/* #undef _LARGEFILE_SOURCE */
+
+/* FIXME Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* FIXME Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* FIXME Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* FIXME Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
diff --git a/src/delta.c b/src/delta.c
new file mode 100644
index 0000000..d2facaf
--- /dev/null
+++ b/src/delta.c
@@ -0,0 +1,400 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- library for network deltas
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | Let's climb to the TOP of that
+ | MOUNTAIN and think about STRIP
+ | MINING!!
+ */
+
+/** \file delta.c
+ * Generate in streaming mode an rsync delta given a set of signatures, and a
+ * new file.
+ *
+ * The size of blocks for signature generation is determined by the block size
+ * in the incoming signature.
+ *
+ * To calculate a signature, we need to be able to see at least one block of
+ * the new file at a time. Once we have that, we calculate its weak signature,
+ * and see if there is any block in the signature hash table that has the same
+ * weak sum. If there is one, then we also compute the strong sum of the new
+ * block, and cross check that. If they're the same, then we can assume we have
+ * a match.
+ *
+ * The final block of the file has to be handled a little differently, because
+ * it may be a short match. Short blocks in the signature don't include their
+ * length -- we just allow for the final short block of the file to match any
+ * block in the signature, and if they have the same checksum we assume they
+ * must have the same length. Therefore, when we emit a COPY command, we have
+ * to send it with a length that is the same as the block matched, and not the
+ * block length from the signature.
+ *
+ * Profiling results as of v1.26, 2001-03-18:
+ *
+ * If everything matches, then we spend almost all our time in rs_mdfour64 and
+ * rs_weak_sum, which is unavoidable and therefore a good profile.
+ *
+ * If nothing matches, it is not so good.
+ *
+ * 2002-06-26: Donovan Baarda
+ *
+ * The following is based entirely on pysync. It is much cleaner than the
+ * previous incarnation of this code. It is slightly complicated because in
+ * this case the output can block, so the main delta loop needs to stop when
+ * this happens.
+ *
+ * In pysync a 'last' attribute is used to hold the last miss or match for
+ * extending if possible. In this code, basis_len and scoop_pos are used
+ * instead of 'last'. When basis_len > 0, last is a match. When basis_len = 0
+ * and scoop_pos is > 0, last is a miss. When both are 0, last is None (ie,
+ * nothing).
+ *
+ * Pysync is also slightly different in that a 'flush' method is available to
+ * force output of accumulated data. This 'flush' is use to finalise delta
+ * calculation. In librsync input is terminated with an eof flag on the input
+ * stream. I have structured this code similar to pysync with a seperate flush
+ * function that is used when eof is reached. This allows for a flush style API
+ * if one is ever needed. Note that flush in pysync can be used for more than
+ * just terminating delta calculation, so a flush based API can in some ways be
+ * more flexible...
+ *
+ * The input data is first scanned, then processed. Scanning identifies input
+ * data as misses or matches, and emits the instruction stream. Processing the
+ * data consumes it off the input scoop and outputs the processed miss data
+ * into the tube.
+ *
+ * The scoop contains all data yet to be processed. The scoop_pos is an index
+ * into the scoop that indicates the point scanned to. As data is scanned,
+ * scoop_pos is incremented. As data is processed, it is removed from the scoop
+ * and scoop_pos adjusted. Everything gets complicated because the tube can
+ * block. When the tube is blocked, no data can be processed. */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include "librsync.h"
+#include "job.h"
+#include "sumset.h"
+#include "checksum.h"
+#include "stream.h"
+#include "emit.h"
+#include "trace.h"
+
+static rs_result rs_delta_s_scan(rs_job_t *job);
+static rs_result rs_delta_s_flush(rs_job_t *job);
+static rs_result rs_delta_s_end(rs_job_t *job);
+static inline void rs_getinput(rs_job_t *job);
+static inline int rs_findmatch(rs_job_t *job, rs_long_t *match_pos,
+ size_t *match_len);
+static inline rs_result rs_appendmatch(rs_job_t *job, rs_long_t match_pos,
+ size_t match_len);
+static inline rs_result rs_appendmiss(rs_job_t *job, size_t miss_len);
+static inline rs_result rs_appendflush(rs_job_t *job);
+static inline rs_result rs_processmatch(rs_job_t *job);
+static inline rs_result rs_processmiss(rs_job_t *job);
+
+/** Get a block of data if possible, and see if it matches.
+ *
+ * On each call, we try to process all of the input data available on the scoop
+ * and input buffer. */
+static rs_result rs_delta_s_scan(rs_job_t *job)
+{
+ const size_t block_len = job->signature->block_len;
+ rs_long_t match_pos;
+ size_t match_len;
+ rs_result result;
+
+ rs_job_check(job);
+ /* read the input into the scoop */
+ rs_getinput(job);
+ /* output any pending output from the tube */
+ result = rs_tube_catchup(job);
+ /* while output is not blocked and there is a block of data */
+ while ((result == RS_DONE)
+ && ((job->scoop_pos + block_len) < job->scoop_avail)) {
+ /* check if this block matches */
+ if (rs_findmatch(job, &match_pos, &match_len)) {
+ /* append the match and reset the weak_sum */
+ result = rs_appendmatch(job, match_pos, match_len);
+ weaksum_reset(&job->weak_sum);
+ } else {
+ /* rotate the weak_sum and append the miss byte */
+ weaksum_rotate(&job->weak_sum, job->scoop_next[job->scoop_pos],
+ job->scoop_next[job->scoop_pos + block_len]);
+ result = rs_appendmiss(job, 1);
+ }
+ }
+ /* if we completed OK */
+ if (result == RS_DONE) {
+ /* if we reached eof, we can flush the last fragment */
+ if (job->stream->eof_in) {
+ job->statefn = rs_delta_s_flush;
+ return RS_RUNNING;
+ } else {
+ /* we are blocked waiting for more data */
+ return RS_BLOCKED;
+ }
+ }
+ return result;
+}
+
+static rs_result rs_delta_s_flush(rs_job_t *job)
+{
+ rs_long_t match_pos;
+ size_t match_len;
+ rs_result result;
+
+ rs_job_check(job);
+ /* read the input into the scoop */
+ rs_getinput(job);
+ /* output any pending output */
+ result = rs_tube_catchup(job);
+ /* while output is not blocked and there is any remaining data */
+ while ((result == RS_DONE) && (job->scoop_pos < job->scoop_avail)) {
+ /* check if this block matches */
+ if (rs_findmatch(job, &match_pos, &match_len)) {
+ /* append the match and reset the weak_sum */
+ result = rs_appendmatch(job, match_pos, match_len);
+ weaksum_reset(&job->weak_sum);
+ } else {
+ /* rollout from weak_sum and append the miss byte */
+ weaksum_rollout(&job->weak_sum, job->scoop_next[job->scoop_pos]);
+ rs_trace("block reduced to " FMT_SIZE "",
+ weaksum_count(&job->weak_sum));
+ result = rs_appendmiss(job, 1);
+ }
+ }
+ /* if we are not blocked, flush and set end statefn. */
+ if (result == RS_DONE) {
+ result = rs_appendflush(job);
+ job->statefn = rs_delta_s_end;
+ }
+ if (result == RS_DONE) {
+ return RS_RUNNING;
+ }
+ return result;
+}
+
+static rs_result rs_delta_s_end(rs_job_t *job)
+{
+ rs_emit_end_cmd(job);
+ return RS_DONE;
+}
+
+static inline void rs_getinput(rs_job_t *job)
+{
+ size_t len;
+
+ len = rs_scoop_total_avail(job);
+ if (job->scoop_avail < len) {
+ rs_scoop_input(job, len);
+ }
+}
+
+/** find a match at scoop_pos, returning the match_pos and match_len.
+ *
+ * Note that this will calculate weak_sum if required. It will also determine
+ * the match_len.
+ *
+ * This routine could be modified to do xdelta style matches that would extend
+ * matches past block boundaries by matching backwards and forwards beyond the
+ * block boundaries. Extending backwards would require decrementing scoop_pos
+ * as appropriate. */
+static inline int rs_findmatch(rs_job_t *job, rs_long_t *match_pos,
+ size_t *match_len)
+{
+ const size_t block_len = job->signature->block_len;
+
+ /* calculate the weak_sum if we don't have one */
+ if (weaksum_count(&job->weak_sum) == 0) {
+ /* set match_len to min(block_len, scan_avail) */
+ *match_len = job->scoop_avail - job->scoop_pos;
+ if (*match_len > block_len) {
+ *match_len = block_len;
+ }
+ /* Update the weak_sum */
+ weaksum_update(&job->weak_sum, job->scoop_next + job->scoop_pos,
+ *match_len);
+ rs_trace("calculate weak sum from scratch length " FMT_SIZE "",
+ weaksum_count(&job->weak_sum));
+ } else {
+ /* set the match_len to the weak_sum count */
+ *match_len = weaksum_count(&job->weak_sum);
+ }
+ *match_pos =
+ rs_signature_find_match(job->signature, weaksum_digest(&job->weak_sum),
+ job->scoop_next + job->scoop_pos, *match_len);
+ return *match_pos != -1;
+}
+
+/** Append a match at match_pos of length match_len to the delta, extending a
+ * previous match if possible, or flushing any previous miss/match. */
+static inline rs_result rs_appendmatch(rs_job_t *job, rs_long_t match_pos,
+ size_t match_len)
+{
+ rs_result result = RS_DONE;
+
+ /* if last was a match that can be extended, extend it */
+ if (job->basis_len && (job->basis_pos + job->basis_len) == match_pos) {
+ job->basis_len += match_len;
+ } else {
+ /* else appendflush the last value */
+ result = rs_appendflush(job);
+ /* make this the new match value */
+ job->basis_pos = match_pos;
+ job->basis_len = match_len;
+ }
+ /* increment scoop_pos to point at next unscanned data */
+ job->scoop_pos += match_len;
+ /* we can only process from the scoop if output is not blocked */
+ if (result == RS_DONE) {
+ /* process the match data off the scoop */
+ result = rs_processmatch(job);
+ }
+ return result;
+}
+
+/** Append a miss of length miss_len to the delta, extending a previous miss
+ * if possible, or flushing any previous match.
+ *
+ * This also breaks misses up into 32KB segments to avoid accumulating too much
+ * in memory. */
+static inline rs_result rs_appendmiss(rs_job_t *job, size_t miss_len)
+{
+ const size_t max_miss = 32768; /* For 0.01% 3 command bytes overhead. */
+ rs_result result = RS_DONE;
+
+ /* If last was a match, or max_miss misses, appendflush it. */
+ if (job->basis_len || (job->scoop_pos >= max_miss)) {
+ result = rs_appendflush(job);
+ }
+ /* increment scoop_pos */
+ job->scoop_pos += miss_len;
+ return result;
+}
+
+/** Flush any accumulating hit or miss, appending it to the delta. */
+static inline rs_result rs_appendflush(rs_job_t *job)
+{
+ /* if last is a match, emit it and reset last by resetting basis_len */
+ if (job->basis_len) {
+ rs_trace("matched " FMT_LONG " bytes at " FMT_LONG "!", job->basis_len,
+ job->basis_pos);
+ rs_emit_copy_cmd(job, job->basis_pos, job->basis_len);
+ job->basis_len = 0;
+ return rs_processmatch(job);
+ /* else if last is a miss, emit and process it */
+ } else if (job->scoop_pos) {
+ rs_trace("got " FMT_SIZE " bytes of literal data", job->scoop_pos);
+ rs_emit_literal_cmd(job, (int)job->scoop_pos);
+ return rs_processmiss(job);
+ }
+ /* otherwise, nothing to flush so we are done */
+ return RS_DONE;
+}
+
+/** Process matching data in the scoop.
+ *
+ * The scoop contains match data at scoop_next of length scoop_pos. This
+ * function processes that match data, returning RS_DONE if it completes, or
+ * RS_BLOCKED if it gets blocked. After it completes scoop_pos is reset to
+ * still point at the next unscanned data.
+ *
+ * This function currently just removes data from the scoop and adjusts
+ * scoop_pos appropriately. In the future this could be used for something like
+ * context compressing of miss data. Note that it also calls rs_tube_catchup to
+ * output any pending output. */
+static inline rs_result rs_processmatch(rs_job_t *job)
+{
+ job->scoop_avail -= job->scoop_pos;
+ job->scoop_next += job->scoop_pos;
+ job->scoop_pos = 0;
+ return rs_tube_catchup(job);
+}
+
+/** Process miss data in the scoop.
+ *
+ * The scoop contains miss data at scoop_next of length scoop_pos. This
+ * function processes that miss data, returning RS_DONE if it completes, or
+ * RS_BLOCKED if it gets blocked. After it completes scoop_pos is reset to
+ * still point at the next unscanned data.
+ *
+ * This function uses rs_tube_copy to queue copying from the scoop into output.
+ * and uses rs_tube_catchup to do the copying. This automaticly removes data
+ * from the scoop, but this can block. While rs_tube_catchup is blocked,
+ * scoop_pos does not point at legit data, so scanning can also not proceed.
+ *
+ * In the future this could do compression of miss data before outputing it. */
+static inline rs_result rs_processmiss(rs_job_t *job)
+{
+ rs_tube_copy(job, job->scoop_pos);
+ job->scoop_pos = 0;
+ return rs_tube_catchup(job);
+}
+
+/** State function that does a slack delta containing only literal data to
+ * recreate the input. */
+static rs_result rs_delta_s_slack(rs_job_t *job)
+{
+ rs_buffers_t *const stream = job->stream;
+ size_t avail = stream->avail_in;
+
+ if (avail) {
+ rs_trace("emit slack delta for " FMT_SIZE " available bytes", avail);
+ rs_emit_literal_cmd(job, (int)avail);
+ rs_tube_copy(job, avail);
+ return RS_RUNNING;
+ } else if (rs_job_input_is_ending(job)) {
+ job->statefn = rs_delta_s_end;
+ return RS_RUNNING;
+ }
+ return RS_BLOCKED;
+}
+
+/** State function for writing out the header of the encoding job. */
+static rs_result rs_delta_s_header(rs_job_t *job)
+{
+ rs_emit_delta_header(job);
+ if (job->signature) {
+ job->statefn = rs_delta_s_scan;
+ } else {
+ rs_trace("no signature provided for delta, using slack deltas");
+ job->statefn = rs_delta_s_slack;
+ }
+ return RS_RUNNING;
+}
+
+rs_job_t *rs_delta_begin(rs_signature_t *sig)
+{
+ rs_job_t *job;
+
+ job = rs_job_new("delta", rs_delta_s_header);
+ /* Caller can pass NULL sig or empty sig for "slack deltas". */
+ if (sig && sig->count > 0) {
+ rs_signature_check(sig);
+ /* Caller must have called rs_build_hash_table() by now. */
+ assert(sig->hashtable);
+ job->signature = sig;
+ weaksum_init(&job->weak_sum, rs_signature_weaksum_kind(sig));
+ }
+ return job;
+}
diff --git a/src/emit.c b/src/emit.c
new file mode 100644
index 0000000..2379c71
--- /dev/null
+++ b/src/emit.c
@@ -0,0 +1,126 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- dynamic caching and delta update in HTTP
+ *
+ * Copyright (C) 2000, 2001, 2004 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** \file emit.c
+ * encoding output routines.
+ *
+ * \todo Pluggable encoding formats: gdiff-style, rsync 24, ed (text), Delta
+ * HTTP. */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include "librsync.h"
+#include "emit.h"
+#include "job.h"
+#include "netint.h"
+#include "command.h"
+#include "prototab.h"
+#include "trace.h"
+
+/** Write the magic for the start of a delta. */
+void rs_emit_delta_header(rs_job_t *job)
+{
+ rs_trace("emit DELTA magic");
+ rs_squirt_n4(job, RS_DELTA_MAGIC);
+}
+
+/** Write a LITERAL command. */
+void rs_emit_literal_cmd(rs_job_t *job, int len)
+{
+ int cmd;
+ int param_len = len <= 64 ? 0 : rs_int_len(len);
+
+ if (param_len == 0) {
+ cmd = len;
+ rs_trace("emit LITERAL_%d, cmd_byte=%#04x", len, cmd);
+ } else if (param_len == 1) {
+ cmd = RS_OP_LITERAL_N1;
+ rs_trace("emit LITERAL_N1(len=%d), cmd_byte=%#04x", len, cmd);
+ } else if (param_len == 2) {
+ cmd = RS_OP_LITERAL_N2;
+ rs_trace("emit LITERAL_N2(len=%d), cmd_byte=%#04x", len, cmd);
+ } else {
+ assert(param_len == 4);
+ cmd = RS_OP_LITERAL_N4;
+ rs_trace("emit LITERAL_N4(len=%d), cmd_byte=%#04x", len, cmd);
+ }
+
+ rs_squirt_byte(job, (rs_byte_t)cmd);
+ if (param_len)
+ rs_squirt_netint(job, len, param_len);
+
+ job->stats.lit_cmds++;
+ job->stats.lit_bytes += len;
+ job->stats.lit_cmdbytes += 1 + param_len;
+}
+
+/** Write a COPY command for given offset and length.
+ *
+ * There is a choice of variable-length encodings, depending on the size of
+ * representation for the parameters. */
+void rs_emit_copy_cmd(rs_job_t *job, rs_long_t where, rs_long_t len)
+{
+ int cmd;
+ rs_stats_t *stats = &job->stats;
+ const int where_bytes = rs_int_len(where);
+ const int len_bytes = rs_int_len(len);
+
+ /* Commands ascend (1,1), (1,2), ... (8, 8) */
+ if (where_bytes == 8)
+ cmd = RS_OP_COPY_N8_N1;
+ else if (where_bytes == 4)
+ cmd = RS_OP_COPY_N4_N1;
+ else if (where_bytes == 2)
+ cmd = RS_OP_COPY_N2_N1;
+ else {
+ assert(where_bytes == 1);
+ cmd = RS_OP_COPY_N1_N1;
+ }
+ if (len_bytes == 1) ;
+ else if (len_bytes == 2)
+ cmd += 1;
+ else if (len_bytes == 4)
+ cmd += 2;
+ else {
+ assert(len_bytes == 8);
+ cmd += 3;
+ }
+
+ rs_trace("emit COPY_N%d_N%d(where=" FMT_LONG ", len=" FMT_LONG
+ "), cmd_byte=%#04x", where_bytes, len_bytes, where, len, cmd);
+ rs_squirt_byte(job, (rs_byte_t)cmd);
+ rs_squirt_netint(job, where, where_bytes);
+ rs_squirt_netint(job, len, len_bytes);
+
+ stats->copy_cmds++;
+ stats->copy_bytes += len;
+ stats->copy_cmdbytes += 1 + where_bytes + len_bytes;
+}
+
+/** Write an END command. */
+void rs_emit_end_cmd(rs_job_t *job)
+{
+ int cmd = RS_OP_END;
+
+ rs_trace("emit END, cmd_byte=%#04x", cmd);
+ rs_squirt_byte(job, (rs_byte_t)cmd);
+}
diff --git a/src/emit.h b/src/emit.h
new file mode 100644
index 0000000..a7e6362
--- /dev/null
+++ b/src/emit.h
@@ -0,0 +1,28 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- dynamic caching and delta update in HTTP
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** \file emit.h
+ * How to emit commands to the client. */
+
+void rs_emit_delta_header(rs_job_t *);
+void rs_emit_literal_cmd(rs_job_t *, int len);
+void rs_emit_end_cmd(rs_job_t *);
+void rs_emit_copy_cmd(rs_job_t *job, rs_long_t where, rs_long_t len);
diff --git a/src/fileutil.c b/src/fileutil.c
new file mode 100644
index 0000000..2e7f069
--- /dev/null
+++ b/src/fileutil.c
@@ -0,0 +1,151 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- library for network deltas
+ *
+ * Copyright (C) 1999, 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 1999 by Andrew Tridgell <tridge@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_FILE_H
+# include <sys/file.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+#include "librsync.h"
+#include "trace.h"
+
+/* Use fseeko64, _fseeki64, or fseeko for long files if they exist. */
+#if defined(HAVE_FSEEKO64) && (SIZEOF_OFF_T < 8)
+# define fopen(f, m) fopen64((f), (m))
+# define fseek(f, o, w) fseeko64((f), (o), (w))
+#elif defined(HAVE__FSEEKI64)
+# define fseek(f, o, w) _fseeki64((f), (o), (w))
+#elif defined(HAVE_FSEEKO)
+# define fseek(f, o, w) fseeko((f), (o), (w))
+#endif
+
+/* Use fstat64 or _fstati64 for long file fstat if they exist. */
+#if defined(HAVE_FSTAT64) && (SIZEOF_OFF_T < 8)
+# define stat stat64
+# define fstat(f,s) fstat64((f), (s))
+#elif defined(HAVE__FSTATI64)
+# define stat _stati64
+# define fstat(f,s) _fstati64((f), (s))
+#endif
+
+/* Make sure S_ISREG is defined. */
+#ifndef S_ISREG
+# define S_ISREG(x) ((x) & _S_IFREG)
+#endif
+
+/* Use and prefer _fileno if it exists. */
+#ifdef HAVE__FILENO
+# define fileno(f) _fileno((f))
+#endif
+
+FILE *rs_file_open(char const *filename, char const *mode, int force)
+{
+ FILE *f;
+ int is_write;
+
+ is_write = mode[0] == 'w';
+
+ if (!filename || !strcmp("-", filename)) {
+ if (is_write) {
+#if _WIN32
+ _setmode(_fileno(stdout), _O_BINARY);
+#endif
+ return stdout;
+ } else {
+#if _WIN32
+ _setmode(_fileno(stdin), _O_BINARY);
+#endif
+ return stdin;
+ }
+ }
+
+ if (!force && is_write) {
+ if ((f = fopen(filename, "rb"))) {
+ // File exists
+ rs_error("File exists \"%s\", aborting!", filename);
+ fclose(f);
+ exit(RS_IO_ERROR);
+ }
+ }
+
+ if (!(f = fopen(filename, mode))) {
+ rs_error("Error opening \"%s\" for %s: %s", filename,
+ is_write ? "write" : "read", strerror(errno));
+ exit(RS_IO_ERROR);
+ }
+
+ return f;
+}
+
+int rs_file_close(FILE *f)
+{
+ if ((f == stdin) || (f == stdout))
+ return 0;
+ return fclose(f);
+}
+
+rs_long_t rs_file_size(FILE *f)
+{
+ struct stat st;
+ if ((fstat(fileno(f), &st) == 0) && (S_ISREG(st.st_mode)))
+ return st.st_size;
+ return -1;
+}
+
+rs_result rs_file_copy_cb(void *arg, rs_long_t pos, size_t *len, void **buf)
+{
+ FILE *f = (FILE *)arg;
+
+ if (fseek(f, pos, SEEK_SET)) {
+ rs_error("seek failed: %s", strerror(errno));
+ return RS_IO_ERROR;
+ }
+ *len = fread(*buf, 1, *len, f);
+ if (*len) {
+ return RS_DONE;
+ } else if (ferror(f)) {
+ rs_error("read error: %s", strerror(errno));
+ return RS_IO_ERROR;
+ } else {
+ rs_error("unexpected eof on fd%d", fileno(f));
+ return RS_INPUT_ENDED;
+ }
+}
diff --git a/src/hashtable.c b/src/hashtable.c
new file mode 100644
index 0000000..ff3f29c
--- /dev/null
+++ b/src/hashtable.c
@@ -0,0 +1,77 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * hashtable.c -- a generic hashtable implementation.
+ *
+ * Copyright (C) 2016 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <assert.h>
+#include <stdlib.h>
+#include "hashtable.h"
+
+/* Open addressing works best if it can take advantage of memory caches using
+ locality for probes of adjacent buckets on collisions. So we pack the keys
+ tightly together in their own key table and avoid referencing the element
+ table and elements as much as possible. Key value zero is reserved as a
+ marker for an empty bucket to avoid checking for NULL in the element table.
+ If we do get a hash value of zero, we -1 to wrap it around to 0xffff. */
+
+/* Use max 0.7 load factor to avoid bad open addressing performance. */
+#define HASHTABLE_LOADFACTOR_NUM 7
+#define HASHTABLE_LOADFACTOR_DEN 10
+
+hashtable_t *_hashtable_new(int size)
+{
+ hashtable_t *t;
+ unsigned size2, bits2;
+
+ /* Adjust requested size to account for max load factor. */
+ size = 1 + size * HASHTABLE_LOADFACTOR_DEN / HASHTABLE_LOADFACTOR_NUM;
+ /* Use next power of 2 larger than the requested size and get mask bits. */
+ for (size2 = 2, bits2 = 1; (int)size2 < size; size2 <<= 1, bits2++) ;
+ if (!(t = calloc(1, sizeof(hashtable_t)+ size2 * sizeof(unsigned))))
+ return NULL;
+ if (!(t->etable = calloc(size2, sizeof(void *)))) {
+ _hashtable_free(t);
+ return NULL;
+ }
+ t->size = (int)size2;
+ t->count = 0;
+ t->tmask = size2 - 1;
+#ifndef HASHTABLE_NBLOOM
+ if (!(t->kbloom = calloc((size2 + 7) / 8, sizeof(unsigned char)))) {
+ _hashtable_free(t);
+ return NULL;
+ }
+ t->bshift = (unsigned)sizeof(unsigned) * 8 - bits2;
+ assert(t->tmask == (unsigned)-1 >> t->bshift);
+#endif
+#ifndef HASHTABLE_NSTATS
+ t->find_count = t->match_count = t->hashcmp_count = t->entrycmp_count = 0;
+#endif
+ return t;
+}
+
+void _hashtable_free(hashtable_t *t)
+{
+ if (t) {
+ free(t->etable);
+#ifndef HASHTABLE_NBLOOM
+ free(t->kbloom);
+#endif
+ free(t);
+ }
+}
diff --git a/src/hashtable.h b/src/hashtable.h
new file mode 100644
index 0000000..8a88840
--- /dev/null
+++ b/src/hashtable.h
@@ -0,0 +1,409 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * hashtable.h -- a generic open addressing hashtable.
+ *
+ * Copyright (C) 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#ifndef _HASHTABLE_H_
+# define _HASHTABLE_H_
+
+# include <assert.h>
+# include <stdlib.h>
+# include <stdbool.h>
+
+/** \file hashtable.h
+ * A generic open addressing hashtable.
+ *
+ * This is a minimal hashtable containing pointers to arbitrary entries with
+ * configurable hashtable size and support for custom hash() and cmp() methods.
+ * The cmp() method can either be a simple comparison between two keys, or can
+ * be against a special match object containing additional mutable state. This
+ * allows for things like deferred and cached evaluation of costly comparison
+ * data. The hash() function doesn't need to avoid clustering behaviour.
+ *
+ * It uses open addressing with quadratic probing for collisions. The
+ * MurmurHash3 finalization function is optionally used on the hash() output to
+ * avoid clustering and can be disabled by setting HASHTABLE_NMIX32. There is
+ * no support for removing entries, only adding them. Multiple entries with the
+ * same key can be added, and you can use a fancy cmp() function to find
+ * particular entries by more than just their key. There is an iterator for
+ * iterating through all entries in the hashtable. There are optional
+ * NAME_find() find/match/hashcmp/entrycmp stats counters that can be disabled
+ * by defining HASHTABLE_NSTATS. There is an optional simple k=1 bloom filter
+ * for speed that can be disabled by defining HASHTABLE_NBLOOM.
+ *
+ * The types and methods of the hashtable and its contents are specified by
+ * using \#define parameters set to their basenames (the prefixes for the *_t
+ * type and *_func() methods) before doing \#include "hashtable.h". This
+ * produces static inline type-safe methods that are either application
+ * optimized for speed or wrappers around void* implementation methods for
+ * compactness.
+ *
+ * \param ENTRY - the entry type basename.
+ *
+ * \param KEY - optional key type basename (default: ENTRY).
+ *
+ * \param MATCH - optional match type basename (default: KEY).
+ *
+ * \param NAME - optional hashtable type basename (default: ENTRY_hashtable).
+ *
+ * Example: \code
+ * typedef ... mykey_t;
+ * int mykey_hash(mykey_t const *e);
+ * int mykey_cmp(mykey_t *e, mykey_t const *o);
+ *
+ * typedef struct myentry {
+ * mykey_t key; // Inherit from mykey_t.
+ * ...extra entry value data...
+ * } myentry_t;
+ * void myentry_init(myentry_t *e, ...);
+ *
+ * #define ENTRY myentry
+ * #define KEY mykey
+ * #include "hashtable.h"
+ *
+ * hashtable_t *t;
+ * myentry_t entries[300];
+ * mykey_t k;
+ * myentry_t *e;
+ *
+ * t = myentry_hashtable_new(300);
+ * myentry_init(&entries[5], ...);
+ * myentry_hashtable_add(t, &entries[5]);
+ * k = ...;
+ * e = myentry_hashtable_find(t, &k);
+ *
+ * int i;
+ * for (e = myentry_hashtable_iter(t, &i); e != NULL;
+ * e = myentry_hashtable_next(t, &i))
+ * ...
+ *
+ * myentry_hashtable_free(t);
+ * \endcode
+ *
+ * The mykey_hash() and mykey_cmp() fuctions will typically take pointers to
+ * mykey/myentry instances the same as the pointers stored in the hashtable.
+ * However it is also possible for them to take "match objects" that are a
+ * "subclass" of the entry type that contain additional state for complicated
+ * comparision operations.
+ *
+ * Example: \code
+ * typedef struct mymatch {
+ * mykey_t key; // Inherit from mykey_t;
+ * ...extra match criteria and state data...
+ * } mymatch_t;
+ * int mymatch_cmp(mymatch_t *m, myentry_t const *e);
+ *
+ * #define ENTRY myentry
+ * #define KEY mykey
+ * #define MATCH mymatch
+ * #include "hashtable.h"
+ *
+ * ...
+ * mymatch_t m;
+ *
+ * t = myentry_hashtable_new(300);
+ * ...
+ * m = ...;
+ * e = myentry_hashtable_find(t, &m);
+ * \endcode
+ *
+ * The mymatch_cmp() function is only called for finding hashtable entries and
+ * can mutate the mymatch_t object for doing things like deferred and cached
+ * evaluation of expensive match data. It can also access the whole myentry_t
+ * object to match against more than just the key. */
+
+/** The hashtable type. */
+typedef struct hashtable {
+ int size; /**< Size of allocated hashtable. */
+ int count; /**< Number of entries in hashtable. */
+ unsigned tmask; /**< Mask to get the hashtable index. */
+# ifndef HASHTABLE_NBLOOM
+ unsigned bshift; /**< Shift to get the bloomfilter index. */
+# endif
+# ifndef HASHTABLE_NSTATS
+ /* The following are for accumulating NAME_find() stats. */
+ long find_count; /**< The count of finds tried. */
+ long match_count; /**< The count of matches found. */
+ long hashcmp_count; /**< The count of hash compares done. */
+ long entrycmp_count; /**< The count of entry compares done. */
+# endif
+# ifndef HASHTABLE_NBLOOM
+ unsigned char *kbloom; /**< Bloom filter of hash keys with k=1. */
+# endif
+ void **etable; /**< Table of pointers to entries. */
+ unsigned ktable[]; /**< Table of hash keys. */
+} hashtable_t;
+
+/* void* implementations for the type-safe static inline wrappers below. */
+hashtable_t *_hashtable_new(int size);
+void _hashtable_free(hashtable_t *t);
+
+# ifndef HASHTABLE_NBLOOM
+static inline void hashtable_setbloom(hashtable_t *t, unsigned const h)
+{
+ /* Use upper bits for a "different hash". */
+ unsigned const i = h >> t->bshift;
+ t->kbloom[i / 8] |= (unsigned char)(1 << (i % 8));
+}
+
+static inline bool hashtable_getbloom(hashtable_t *t, unsigned const h)
+{
+ /* Use upper bits for a "different hash". */
+ unsigned const i = h >> t->bshift;
+ return (t->kbloom[i / 8] >> (i % 8)) & 1;
+}
+# endif
+
+/** MurmurHash3 finalization mix function. */
+static inline unsigned mix32(unsigned h)
+{
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+ return h;
+}
+
+/** Ensure hash's are never zero. */
+static inline unsigned nozero(unsigned h)
+{
+ return h ? h : (unsigned)-1;
+}
+
+#endif /* _HASHTABLE_H_ */
+
+/* If ENTRY is defined, define type-dependent static inline methods. */
+#ifdef ENTRY
+
+# define _JOIN2(x, y) x##y
+# define _JOIN(x, y) _JOIN2(x, y)
+
+# ifndef KEY
+# define KEY ENTRY
+# endif
+
+# ifndef MATCH
+# define MATCH KEY
+# endif
+
+# ifndef NAME
+# define NAME _JOIN(ENTRY, _hashtable)
+# endif
+
+# define ENTRY_t _JOIN(ENTRY, _t) /**< The entry type. */
+# define KEY_t _JOIN(KEY, _t) /**< The key type. */
+# define MATCH_t _JOIN(MATCH, _t) /**< The match type. */
+# define KEY_hash _JOIN(KEY, _hash) /**< The key hash(k) method. */
+# define MATCH_cmp _JOIN(MATCH, _cmp) /**< The match cmp(m, e) method. */
+/* The names for all the hashtable methods. */
+# define NAME_new _JOIN(NAME, _new)
+# define NAME_free _JOIN(NAME, _free)
+# define NAME_stats_init _JOIN(NAME, _stats_init)
+# define NAME_add _JOIN(NAME, _add)
+# define NAME_find _JOIN(NAME, _find)
+# define NAME_iter _JOIN(NAME, _iter)
+# define NAME_next _JOIN(NAME, _next)
+
+/* Modified hash() with/without mix32() and reserving zero for empty buckets. */
+# ifdef HASHTABLE_NMIX32
+# define _KEY_HASH(k) nozero(KEY_hash((KEY_t *)k))
+# else
+# define _KEY_HASH(k) nozero(mix32(KEY_hash((KEY_t *)k)))
+# endif
+
+/* Loop macro for probing table t for key hash hk, iterating with index i and
+ entry hash h, terminating at an empty bucket. */
+# define _for_probe(t, hk, i, h) \
+ unsigned const *const ktable = t->ktable;\
+ unsigned const tmask = t->tmask;\
+ unsigned i, s, h;\
+ for (i = hk & tmask, s = 0; (h = ktable[i]); i = (i + ++s) & tmask)
+
+/* Conditional macro for incrementing stats counters. */
+# ifndef HASHTABLE_NSTATS
+# define _stats_inc(c) (c++)
+# else
+# define _stats_inc(c)
+# endif
+
+/** Allocate and initialize a hashtable instance.
+ *
+ * The provided size is used as an indication of the number of entries you wish
+ * to add, but the allocated size will probably be larger depending on the
+ * implementation to enable optimisations or avoid degraded performance. It may
+ * be possible to fill the table beyond the requested size, but performance can
+ * start to degrade badly if it is over filled.
+ *
+ * \param size - The desired minimum size of the hash table.
+ *
+ * \return The initialized hashtable instance or NULL if it failed. */
+static inline hashtable_t *NAME_new(int size)
+{
+ return _hashtable_new(size);
+}
+
+/** Destroy and free a hashtable instance.
+ *
+ * This will free the hashtable, but will not free the entries in the
+ * hashtable. If you want to free the entries too, use a hashtable iterator to
+ * free the the entries first.
+ *
+ * \param *t - The hashtable to destroy and free. */
+static inline void NAME_free(hashtable_t *t)
+{
+ _hashtable_free(t);
+}
+
+/** Initialize hashtable stats counters.
+ *
+ * This will reset all the stats counters for the hashtable,
+ *
+ * \param *t - The hashtable to initializ stats for. */
+static inline void NAME_stats_init(hashtable_t *t)
+{
+# ifndef HASHTABLE_NSTATS
+ t->find_count = t->match_count = t->hashcmp_count = t->entrycmp_count = 0;
+# endif
+}
+
+/** Add an entry to a hashtable.
+ *
+ * This doesn't use MATCH_cmp() or do any checks for existing copies or
+ * instances, so it will add duplicates. If you want to avoid adding
+ * duplicates, use NAME_find() to check for existing entries first.
+ *
+ * \param *t - The hashtable to add to.
+ *
+ * \param *e - The entry object to add.
+ *
+ * \return The added entry, or NULL if the table is full. */
+static inline ENTRY_t *NAME_add(hashtable_t *t, ENTRY_t *e)
+{
+ unsigned he = _KEY_HASH(e);
+
+ assert(e != NULL);
+ if (t->count + 1 == t->size)
+ return NULL;
+# ifndef HASHTABLE_NBLOOM
+ hashtable_setbloom(t, he);
+# endif
+ _for_probe(t, he, i, h);
+ t->count++;
+ t->ktable[i] = he;
+ return t->etable[i] = e;
+}
+
+/** Find an entry in a hashtable.
+ *
+ * Uses MATCH_cmp() to find the first matching entry in the table in the same
+ * hash() bucket.
+ *
+ * \param *t - The hashtable to search.
+ *
+ * \param *m - The key or match object to search for.
+ *
+ * \return The first found entry, or NULL if nothing was found. */
+static inline ENTRY_t *NAME_find(hashtable_t *t, MATCH_t *m)
+{
+ assert(m != NULL);
+ unsigned hm = _KEY_HASH(m);
+ ENTRY_t *e;
+
+ _stats_inc(t->find_count);
+# ifndef HASHTABLE_NBLOOM
+ if (!hashtable_getbloom(t, hm))
+ return NULL;
+# endif
+ _for_probe(t, hm, i, he) {
+ _stats_inc(t->hashcmp_count);
+ if (hm == he) {
+ _stats_inc(t->entrycmp_count);
+ if (!MATCH_cmp(m, e = t->etable[i])) {
+ _stats_inc(t->match_count);
+ return e;
+ }
+ }
+ }
+ /* Also count the compare for the empty bucket. */
+ _stats_inc(t->hashcmp_count);
+ return NULL;
+}
+
+static inline ENTRY_t *NAME_next(hashtable_t *t, int *i);
+
+/** Initialize a iteration and return the first entry.
+ *
+ * This works together with NAME_next() for iterating through all entries in a
+ * hashtable.
+ *
+ * Example: \code
+ * for (e = NAME_iter(t, &i); e != NULL; e = NAME_next(t, &i))
+ * ...
+ * \endcode
+ *
+ * \param *t - the hashtable to iterate over.
+ *
+ * \param *i - the int iterator index to initialize.
+ *
+ * \return The first entry or NULL if the hashtable is empty. */
+static inline ENTRY_t *NAME_iter(hashtable_t *t, int *i)
+{
+ assert(t != NULL);
+ assert(i != NULL);
+ *i = 0;
+ return NAME_next(t, i);
+}
+
+/** Get the next entry from a hashtable iterator or NULL when finished.
+ *
+ * This works together with NAME_iter() for iterating through all entries in a
+ * hashtable.
+ *
+ * \param *t - the hashtable to iterate over.
+ *
+ * \param *i - the int iterator index to use.
+ *
+ * \return The next entry or NULL if the iterator is finished. */
+static inline ENTRY_t *NAME_next(hashtable_t *t, int *i)
+{
+ assert(t != NULL);
+ assert(i != NULL);
+ ENTRY_t *e = NULL;
+
+ while ((*i < t->size) && !(e = t->etable[(*i)++])) ;
+ return e;
+}
+
+# undef ENTRY
+# undef KEY
+# undef MATCH
+# undef NAME
+# undef ENTRY_t
+# undef KEY_t
+# undef MATCH_t
+# undef KEY_hash
+# undef MATCH_cmp
+# undef NAME_new
+# undef NAME_free
+# undef NAME_stats_init
+# undef NAME_add
+# undef NAME_find
+# undef NAME_iter
+# undef NAME_next
+# undef _KEY_HASH
+#endif /* ENTRY */
diff --git a/src/hex.c b/src/hex.c
new file mode 100644
index 0000000..ded93f4
--- /dev/null
+++ b/src/hex.c
@@ -0,0 +1,35 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include "librsync.h"
+
+void rs_hexify(char *to_buf, void const *from, int from_len)
+{
+ static const char hex_chars[] = "0123456789abcdef";
+ unsigned char const *from_buf = (unsigned char const *)from;
+
+ while (from_len-- > 0) {
+ *(to_buf++) = hex_chars[((*from_buf) >> 4) & 0xf];
+ *(to_buf++) = hex_chars[(*from_buf) & 0xf];
+ from_buf++;
+ }
+
+ *to_buf = 0;
+}
diff --git a/src/isprefix.c b/src/isprefix.c
new file mode 100644
index 0000000..e0fd2b0
--- /dev/null
+++ b/src/isprefix.c
@@ -0,0 +1,34 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ * librsync -- dynamic caching and delta update in HTTP
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "isprefix.h"
+
+/** Return true if TIP is a prefix of ICEBERG. */
+int isprefix(char const *tip, char const *iceberg)
+{
+ while (*tip) {
+ if (*tip != *iceberg)
+ return 0;
+ tip++;
+ iceberg++;
+ }
+
+ return 1;
+}
diff --git a/src/isprefix.h b/src/isprefix.h
new file mode 100644
index 0000000..e24b193
--- /dev/null
+++ b/src/isprefix.h
@@ -0,0 +1,22 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ * librsync -- dynamic caching and delta update in HTTP
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** Return true if TIP is a prefix of ICEBERG. */
+int isprefix(char const *tip, char const *iceberg);
diff --git a/src/job.c b/src/job.c
new file mode 100644
index 0000000..182ca4a
--- /dev/null
+++ b/src/job.c
@@ -0,0 +1,178 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | The hard, lifeless I covered up the
+ | warm, pulsing It; protecting and
+ | sheltering.
+ */
+
+/** \file job.c
+ * Generic state-machine interface.
+ *
+ * The point of this is that we need to be able to suspend and resume
+ * processing at any point at which the buffers may block.
+ *
+ * \sa \ref api_streaming \sa rs_job_iter() \sa ::rs_job */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <time.h>
+#include "librsync.h"
+#include "job.h"
+#include "stream.h"
+#include "trace.h"
+#include "util.h"
+
+static rs_result rs_job_work(rs_job_t *job, rs_buffers_t *buffers);
+
+rs_job_t *rs_job_new(char const *job_name, rs_result (*statefn)(rs_job_t *))
+{
+ rs_job_t *job;
+
+ job = rs_alloc_struct(rs_job_t);
+
+ job->job_name = job_name;
+ job->dogtag = RS_JOB_TAG;
+ job->statefn = statefn;
+
+ job->stats.op = job_name;
+ job->stats.start = time(NULL);
+
+ rs_trace("start %s job", job_name);
+
+ return job;
+}
+
+rs_result rs_job_free(rs_job_t *job)
+{
+ free(job->scoop_buf);
+ if (job->job_owns_sig)
+ rs_free_sumset(job->signature);
+ rs_bzero(job, sizeof *job);
+ free(job);
+
+ return RS_DONE;
+}
+
+static rs_result rs_job_complete(rs_job_t *job, rs_result result)
+{
+ rs_job_check(job);
+ assert(result != RS_RUNNING && result != RS_BLOCKED);
+ assert(rs_tube_is_idle(job) || result != RS_DONE);
+
+ job->final_result = result;
+ job->stats.end = time(NULL);
+ if (result != RS_DONE) {
+ rs_error("%s job failed: %s", job->job_name, rs_strerror(result));
+ } else {
+ rs_trace("%s job complete", job->job_name);
+ }
+ return result;
+}
+
+rs_result rs_job_iter(rs_job_t *job, rs_buffers_t *buffers)
+{
+ rs_result result;
+ size_t orig_in, orig_out;
+
+ rs_job_check(job);
+ assert(buffers);
+
+ orig_in = buffers->avail_in;
+ orig_out = buffers->avail_out;
+ result = rs_job_work(job, buffers);
+ if (result == RS_BLOCKED || result == RS_DONE)
+ if ((orig_in == buffers->avail_in) && (orig_out == buffers->avail_out)
+ && orig_in && orig_out) {
+ rs_error("internal error: job made no progress " "[orig_in="
+ FMT_SIZE ", orig_out=" FMT_SIZE ", final_in=" FMT_SIZE
+ ", final_out=" FMT_SIZE "]", orig_in, orig_out,
+ buffers->avail_in, buffers->avail_out);
+ return RS_INTERNAL_ERROR;
+ }
+ return result;
+}
+
+static rs_result rs_job_work(rs_job_t *job, rs_buffers_t *buffers)
+{
+ rs_result result;
+
+ rs_job_check(job);
+ assert(buffers);
+
+ job->stream = buffers;
+ while (1) {
+ result = rs_tube_catchup(job);
+ if (result == RS_DONE && job->statefn) {
+ result = job->statefn(job);
+ if (result == RS_DONE) {
+ /* The job is done so clear statefn. */
+ job->statefn = NULL;
+ /* There might be stuff in the tube, so keep running. */
+ continue;
+ }
+ }
+ if (result == RS_BLOCKED)
+ return result;
+ if (result != RS_RUNNING)
+ return rs_job_complete(job, result);
+ }
+}
+
+const rs_stats_t *rs_job_statistics(rs_job_t *job)
+{
+ return &job->stats;
+}
+
+int rs_job_input_is_ending(rs_job_t *job)
+{
+ return job->stream->eof_in;
+}
+
+rs_result rs_job_drive(rs_job_t *job, rs_buffers_t *buf, rs_driven_cb in_cb,
+ void *in_opaque, rs_driven_cb out_cb, void *out_opaque)
+{
+ rs_result result, iores;
+
+ rs_bzero(buf, sizeof *buf);
+
+ do {
+ if (!buf->eof_in && in_cb) {
+ iores = in_cb(job, buf, in_opaque);
+ if (iores != RS_DONE)
+ return iores;
+ }
+
+ result = rs_job_iter(job, buf);
+ if (result != RS_DONE && result != RS_BLOCKED)
+ return result;
+
+ if (out_cb) {
+ iores = (out_cb) (job, buf, out_opaque);
+ if (iores != RS_DONE)
+ return iores;
+ }
+ } while (result != RS_DONE);
+
+ return result;
+}
diff --git a/src/job.h b/src/job.h
new file mode 100644
index 0000000..061c4b4
--- /dev/null
+++ b/src/job.h
@@ -0,0 +1,112 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 2000, 2001, 2014 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "mdfour.h"
+#include "checksum.h"
+
+/** The contents of this structure are private. */
+struct rs_job {
+ int dogtag;
+
+ /** Human-readable job operation name. */
+ const char *job_name;
+
+ rs_buffers_t *stream;
+
+ /** Callback for each processing step. */
+ rs_result (*statefn)(rs_job_t *);
+
+ /** Final result of processing job. Used by rs_job_s_failed(). */
+ rs_result final_result;
+
+ /* Arguments for initializing the signature used by mksum.c and readsums.c.
+ */
+ int sig_magic;
+ int sig_block_len;
+ int sig_strong_len;
+
+ /** The size of the signature file if available. Used by loadsums.c when
+ * initializing the signature to preallocate memory. */
+ rs_long_t sig_fsize;
+
+ /** Pointer to the signature that's being used by the operation. */
+ rs_signature_t *signature;
+
+ /** Flag indicating signature should be destroyed with the job. */
+ int job_owns_sig;
+
+ /** Command byte currently being processed, if any. */
+ unsigned char op;
+
+ /** The weak signature digest used by readsums.c */
+ rs_weak_sum_t weak_sig;
+
+ /** The rollsum weak signature accumulator used by delta.c */
+ weaksum_t weak_sum;
+
+ /** Lengths of expected parameters. */
+ rs_long_t param1, param2;
+
+ struct rs_prototab_ent const *cmd;
+ rs_mdfour_t output_md4;
+
+ /** Encoding statistics. */
+ rs_stats_t stats;
+
+ /** Buffer of data in the scoop. Allocation is scoop_buf[0..scoop_alloc],
+ * and scoop_next[0..scoop_avail] contains data yet to be processed.
+ * scoop_next[scoop_pos..scoop_avail] is the data yet to be scanned. */
+ rs_byte_t *scoop_buf; /* the allocation pointer */
+ rs_byte_t *scoop_next; /* the data pointer */
+ size_t scoop_alloc; /* the allocation size */
+ size_t scoop_avail; /* the data size */
+ size_t scoop_pos; /* the scan position */
+
+ /** If USED is >0, then buf contains that much write data to be sent out. */
+ rs_byte_t write_buf[36];
+ size_t write_len;
+
+ /** If \p copy_len is >0, then that much data should be copied through
+ * from the input. */
+ size_t copy_len;
+
+ /** Copy from the basis position. */
+ rs_long_t basis_pos, basis_len;
+
+ /** Callback used to copy data from the basis into the output. */
+ rs_copy_cb *copy_cb;
+ void *copy_arg;
+};
+
+rs_job_t *rs_job_new(const char *, rs_result (*statefn)(rs_job_t *));
+
+int rs_job_input_is_ending(rs_job_t *job);
+
+/** Magic job tag number for checking jobs have been initialized. */
+#define RS_JOB_TAG 20010225
+
+/** Assert that a job is valid.
+ *
+ * We don't use a static inline function here so that assert failure output
+ * points at where rs_job_check() was called from. */
+#define rs_job_check(job) do {\
+ assert(job->dogtag == RS_JOB_TAG);\
+} while (0)
diff --git a/src/librsync.h b/src/librsync.h
new file mode 100644
index 0000000..e39e5ae
--- /dev/null
+++ b/src/librsync.h
@@ -0,0 +1,614 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- library for network deltas
+ *
+ * Copyright 2000, 2001, 2014, 2015 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | You should never wear your best
+ | trousers when you go out to fight for
+ | freedom and liberty.
+ | -- Henrik Ibsen
+ */
+
+/** \file librsync.h
+ * Public header for librsync. */
+#ifndef _RSYNC_H
+# define _RSYNC_H
+
+# include <stdio.h>
+# include <stdint.h>
+# include <time.h>
+# include "librsync_export.h"
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/** Library version string.
+ *
+ * \sa \ref versioning */
+LIBRSYNC_EXPORT extern char const rs_librsync_version[];
+
+typedef uint8_t rs_byte_t;
+typedef intmax_t rs_long_t;
+
+ /*=
+ | "The IETF already has more than enough
+ | RFCs that codify the obvious, make
+ | stupidity illegal, support truth,
+ | justice, and the IETF way, and generally
+ | demonstrate the author is a brilliant and
+ | valuable Contributor to The Standards
+ | Process."
+ | -- Vernon Schryver
+ */
+
+/** A uint32 magic number, emitted in bigendian/network order at the start of
+ * librsync files. */
+typedef enum {
+ /** A delta file.
+ *
+ * At present, there's only one delta format.
+ *
+ * The four-byte literal \c "rs\x026". */
+ RS_DELTA_MAGIC = 0x72730236,
+
+ /** A signature file with MD4 signatures.
+ *
+ * Backward compatible with librsync < 1.0, but strongly deprecated because
+ * it creates a security vulnerability on files containing partly untrusted
+ * data. See <https://github.com/librsync/librsync/issues/5>.
+ *
+ * The four-byte literal \c "rs\x016".
+ *
+ * \sa rs_sig_begin() */
+ RS_MD4_SIG_MAGIC = 0x72730136,
+
+ /** A signature file using the BLAKE2 hash. Supported from librsync 1.0.
+ *
+ * The four-byte literal \c "rs\x017".
+ *
+ * \sa rs_sig_begin() */
+ RS_BLAKE2_SIG_MAGIC = 0x72730137,
+
+ /** A signature file with RabinKarp rollsum and MD4 hash.
+ *
+ * Uses a faster/safer rollsum, but still strongly discouraged because of
+ * MD4's security vulnerability. Supported since librsync 2.2.0.
+ *
+ * The four-byte literal \c "rs\x01F".
+ *
+ * \sa rs_sig_begin() */
+ RS_RK_MD4_SIG_MAGIC = 0x72730146,
+
+ /** A signature file with RabinKarp rollsum and BLAKE2 hash.
+ *
+ * Uses a faster/safer rollsum together with the safer BLAKE2 hash. This is
+ * the recommended default supported since librsync 2.2.0.
+ *
+ * The four-byte literal \c "rs\x01G".
+ *
+ * \sa rs_sig_begin() */
+ RS_RK_BLAKE2_SIG_MAGIC = 0x72730147,
+
+} rs_magic_number;
+
+/** Log severity levels.
+ *
+ * These are the same as syslog, at least in glibc.
+ *
+ * \sa rs_trace_set_level() \sa \ref api_trace */
+typedef enum {
+ RS_LOG_EMERG = 0, /**< System is unusable */
+ RS_LOG_ALERT = 1, /**< Action must be taken immediately */
+ RS_LOG_CRIT = 2, /**< Critical conditions */
+ RS_LOG_ERR = 3, /**< Error conditions */
+ RS_LOG_WARNING = 4, /**< Warning conditions */
+ RS_LOG_NOTICE = 5, /**< Normal but significant condition */
+ RS_LOG_INFO = 6, /**< Informational */
+ RS_LOG_DEBUG = 7 /**< Debug-level messages */
+} rs_loglevel;
+
+/** Callback to write out log messages.
+ *
+ * \param level a syslog level.
+ *
+ * \param msg message to be logged.
+ *
+ * \sa \ref api_trace */
+typedef void rs_trace_fn_t(rs_loglevel level, char const *msg);
+
+/** Set the least important message severity that will be output.
+ *
+ * \sa \ref api_trace */
+LIBRSYNC_EXPORT void rs_trace_set_level(rs_loglevel level);
+
+/** Set trace callback.
+ *
+ * \sa \ref api_trace */
+LIBRSYNC_EXPORT void rs_trace_to(rs_trace_fn_t *);
+
+/** Default trace callback that writes to stderr.
+ *
+ * Implements ::rs_trace_fn_t, and may be passed to rs_trace_to().
+ *
+ * \sa \ref api_trace */
+LIBRSYNC_EXPORT void rs_trace_stderr(rs_loglevel level, char const *msg);
+
+/** Check whether the library was compiled with debugging trace.
+ *
+ * \returns True if the library contains trace code; otherwise false.
+ *
+ * If this returns false, then trying to turn trace on will achieve nothing.
+ *
+ * \sa \ref api_trace */
+LIBRSYNC_EXPORT int rs_supports_trace(void);
+
+/** Convert \p from_len bytes at \p from_buf into a hex representation in \p
+ * to_buf, which must be twice as long plus one byte for the null terminator. */
+LIBRSYNC_EXPORT void rs_hexify(char *to_buf, void const *from_buf,
+ int from_len);
+
+/** Decode a base64 buffer in place.
+ *
+ * \returns The number of binary bytes. */
+LIBRSYNC_EXPORT size_t rs_unbase64(char *s);
+
+/** Encode a buffer as base64. */
+LIBRSYNC_EXPORT void rs_base64(unsigned char const *buf, int n, char *out);
+
+/** Return codes from nonblocking rsync operations.
+ *
+ * \sa rs_strerror() \sa api_callbacks */
+typedef enum rs_result {
+ RS_DONE = 0, /**< Completed successfully. */
+ RS_BLOCKED = 1, /**< Blocked waiting for more data. */
+ RS_RUNNING = 2, /**< The job is still running, and not yet
+ * finished or blocked. (This value should
+ * never be seen by the application.) */
+ RS_TEST_SKIPPED = 77, /**< Test neither passed or failed. */
+ RS_IO_ERROR = 100, /**< Error in file or network IO. */
+ RS_SYNTAX_ERROR = 101, /**< Command line syntax error. */
+ RS_MEM_ERROR = 102, /**< Out of memory. */
+ RS_INPUT_ENDED = 103, /**< Unexpected end of input file, perhaps due
+ * to a truncated file or dropped network
+ * connection. */
+ RS_BAD_MAGIC = 104, /**< Bad magic number at start of stream.
+ * Probably not a librsync file, or possibly
+ * the wrong kind of file or from an
+ * incompatible library version. */
+ RS_UNIMPLEMENTED = 105, /**< Author is lazy. */
+ RS_CORRUPT = 106, /**< Unbelievable value in stream. */
+ RS_INTERNAL_ERROR = 107, /**< Probably a library bug. */
+ RS_PARAM_ERROR = 108 /**< Bad value passed in to library, probably
+ * an application bug. */
+} rs_result;
+
+/** Return an English description of a ::rs_result value. */
+LIBRSYNC_EXPORT char const *rs_strerror(rs_result r);
+
+/** Performance statistics from a librsync encoding or decoding operation.
+ *
+ * \sa api_stats \sa rs_format_stats() \sa rs_log_stats() */
+typedef struct rs_stats {
+ char const *op; /**< Human-readable name of current operation.
+ * For example, "delta". */
+ int lit_cmds; /**< Number of literal commands. */
+ rs_long_t lit_bytes; /**< Number of literal bytes. */
+ rs_long_t lit_cmdbytes; /**< Number of bytes used in literal command
+ * headers. */
+
+ rs_long_t copy_cmds, copy_bytes, copy_cmdbytes;
+ rs_long_t sig_cmds, sig_bytes;
+ int false_matches;
+
+ rs_long_t sig_blocks; /**< Number of blocks described by the
+ * signature. */
+
+ size_t block_len;
+
+ rs_long_t in_bytes; /**< Total bytes read from input. */
+ rs_long_t out_bytes; /**< Total bytes written to output. */
+
+ time_t start, end;
+} rs_stats_t;
+
+/** MD4 message-digest accumulator.
+ *
+ * \sa rs_mdfour(), rs_mdfour_begin(), rs_mdfour_update(), rs_mdfour_result() */
+typedef struct rs_mdfour rs_mdfour_t;
+
+LIBRSYNC_EXPORT extern const int RS_MD4_SUM_LENGTH, RS_BLAKE2_SUM_LENGTH;
+
+# define RS_MAX_STRONG_SUM_LENGTH 32
+
+typedef uint32_t rs_weak_sum_t;
+typedef unsigned char rs_strong_sum_t[RS_MAX_STRONG_SUM_LENGTH];
+
+LIBRSYNC_EXPORT void rs_mdfour(unsigned char *out, void const *in, size_t);
+LIBRSYNC_EXPORT void rs_mdfour_begin( /* @out@ */ rs_mdfour_t *md);
+
+/** Feed some data into the MD4 accumulator.
+ *
+ * \param md MD4 accumulator.
+ *
+ * \param in_void Data to add.
+ *
+ * \param n Number of bytes fed in. */
+LIBRSYNC_EXPORT void rs_mdfour_update(rs_mdfour_t *md, void const *in_void,
+ size_t n);
+LIBRSYNC_EXPORT void rs_mdfour_result(rs_mdfour_t *md, unsigned char *out);
+
+/** Return a human-readable representation of statistics.
+ *
+ * The string is truncated if it does not fit. 100 characters should be
+ * sufficient space.
+ *
+ * \param stats Statistics from an encoding or decoding operation.
+ *
+ * \param buf Buffer to receive result.
+ *
+ * \param size Size of buffer.
+ *
+ * \return \p buf.
+ *
+ * \sa \ref api_stats */
+LIBRSYNC_EXPORT char *rs_format_stats(rs_stats_t const *stats, char *buf,
+ size_t size);
+
+/** Write statistics into the current log as text.
+ *
+ * \sa \ref api_stats \sa \ref api_trace */
+LIBRSYNC_EXPORT int rs_log_stats(rs_stats_t const *stats);
+
+/** The signature datastructure type. */
+typedef struct rs_signature rs_signature_t;
+
+/** Log the rs_signature_delta match stats. */
+LIBRSYNC_EXPORT void rs_signature_log_stats(rs_signature_t const *sig);
+
+/** Deep deallocation of checksums. */
+LIBRSYNC_EXPORT void rs_free_sumset(rs_signature_t *);
+
+/** Dump signatures to the log. */
+LIBRSYNC_EXPORT void rs_sumset_dump(rs_signature_t const *);
+
+/** Description of input and output buffers.
+ *
+ * On each call to ::rs_job_iter(), the caller can make available
+ *
+ * - #avail_in bytes of input data at #next_in
+ *
+ * - #avail_out bytes of output space at #next_out
+ *
+ * - or some of both
+ *
+ * Buffers must be allocated and passed in by the caller.
+ *
+ * On input, the buffers structure must contain the address and length of the
+ * input and output buffers. The library updates these values to indicate the
+ * amount of \b remaining buffer. So, on return, #avail_out is not the amount
+ * of output data produced, but rather the amount of output buffer space still
+ * available.
+ *
+ * This means that the values on return are consistent with the values on
+ * entry, and suitable to be passed in on a second call, but they don't
+ * directly tell you how much output data was produced.
+ *
+ * Note also that if *#avail_in is nonzero on return, then not all of the input
+ * data has been consumed. The caller should either provide more output buffer
+ * space and call ::rs_job_iter() again passing the same #next_in and
+ * #avail_in, or put the remaining input data into some persistent buffer and
+ * call rs_job_iter() with it again when there is more output space.
+ *
+ * \sa rs_job_iter() */
+struct rs_buffers_s {
+ /** Next input byte.
+ *
+ * References a pointer which on entry should point to the start of the
+ * data to be encoded. Updated to point to the byte after the last one
+ * consumed. */
+ char *next_in;
+
+ /** Number of bytes available at next_in.
+ *
+ * References the length of available input. Updated to be the number of
+ * unused data bytes, which will be zero if all the input was consumed. May
+ * be zero if there is no new input, but the caller just wants to drain
+ * output. */
+ size_t avail_in;
+
+ /** True if there is no more data after this. */
+ int eof_in;
+
+ /** Next output byte should be put there.
+ *
+ * References a pointer which on entry points to the start of the output
+ * buffer. Updated to point to the byte after the last one filled. */
+ char *next_out;
+
+ /** Remaining free space at next_out.
+ *
+ * References the size of available output buffer. Updated to the size of
+ * unused output buffer. */
+ size_t avail_out;
+};
+
+/** \sa ::rs_buffers_s */
+typedef struct rs_buffers_s rs_buffers_t;
+
+/** Default block length, if not determined by any other factors.
+ *
+ * The 2K default assumes a typical file is about 4MB and should be OK for
+ * files up to 32G with more than 1GB ram. */
+# define RS_DEFAULT_BLOCK_LEN 2048
+
+/** Default minimum strong sum length, if the filesize is unknown.
+ *
+ * This is conservative, and should be safe for files less than 45TB with a 2KB
+ * block_len, assuming no collision attack with crafted data. */
+# define RS_DEFAULT_MIN_STRONG_LEN 12
+
+/** Job of work to be done.
+ *
+ * Created by functions such as rs_sig_begin(), and then iterated over by
+ * rs_job_iter().
+ *
+ * The contents are opaque to the application, and instances are always
+ * allocated by the library.
+ *
+ * \sa \ref api_streaming \sa rs_job */
+typedef struct rs_job rs_job_t;
+
+/** Run a ::rs_job state machine until it blocks (::RS_BLOCKED), returns an
+ * error, or completes (::RS_DONE).
+ *
+ * \param job Description of job state.
+ *
+ * \param buffers Pointer to structure describing input and output buffers.
+ *
+ * \return The ::rs_result that caused iteration to stop.
+ *
+ * \c buffers->eof_in should be true if there is no more data after what's in
+ * the input buffer. The final block checksum will run across whatever's in
+ * there, without trying to accumulate anything else.
+ *
+ * \sa \ref api_streaming */
+LIBRSYNC_EXPORT rs_result rs_job_iter(rs_job_t *job, rs_buffers_t *buffers);
+
+/** Type of application-supplied function for rs_job_drive().
+ *
+ * \sa \ref api_pull */
+typedef rs_result rs_driven_cb(rs_job_t *job, rs_buffers_t *buf,
+ void *opaque);
+
+/** Actively process a job, by making callbacks to fill and empty the buffers
+ * until the job is done. */
+LIBRSYNC_EXPORT rs_result rs_job_drive(rs_job_t *job, rs_buffers_t *buf,
+ rs_driven_cb in_cb, void *in_opaque,
+ rs_driven_cb out_cb, void *out_opaque);
+
+/** Return a pointer to the statistics in a job. */
+LIBRSYNC_EXPORT const rs_stats_t *rs_job_statistics(rs_job_t *job);
+
+/** Deallocate job state. */
+LIBRSYNC_EXPORT rs_result rs_job_free(rs_job_t *);
+
+/** Get or check signature arguments for a given file size.
+ *
+ * This can be used to get the recommended arguments for generating a
+ * signature. On calling, old_fsize should be set to the old file size or -1
+ * for "unknown". The magic and block_len arguments should be set to a valid
+ * value or 0 for "recommended". The strong_len input should be set to a valid
+ * value, 0 for "maximum", or -1 for "miniumum". Use strong_len=0 for the best
+ * protection against active hash collision attacks for the given magic type.
+ * Use strong_len=-1 for the smallest signature size that is safe against
+ * random hash collisions for the block_len and old_fsize. Use strong_len=20
+ * for something probably good enough against attacks with smaller signatures.
+ * On return the 0 or -1 input args will be set to recommended values and the
+ * returned result will indicate if any inputs were invalid.
+ *
+ * \param old_fsize - the original file size (-1 for "unknown").
+ *
+ * \param *magic - the magic type to use (0 for "recommended").
+ *
+ * \param *block_len - the block length to use (0 for "recommended").
+ *
+ * \param *strong_len - the strongsum length to use (0 for "maximum", -1 for
+ * "minimum").
+ *
+ * \return RS_DONE if all arguments are valid, otherwise an error code. */
+LIBRSYNC_EXPORT rs_result rs_sig_args(rs_long_t old_fsize,
+ rs_magic_number * magic,
+ size_t *block_len, size_t *strong_len);
+
+/** Start generating a signature.
+ *
+ * It's recommended you use rs_sig_args() to get the recommended arguments for
+ * this based on the original file size.
+ *
+ * \return A new rs_job_t into which the old file data can be passed.
+ *
+ * \param sig_magic Signature file format to generate (0 for "recommended").
+ * See ::rs_magic_number.
+ *
+ * \param block_len Checksum block size to use (0 for "recommended"). Larger
+ * values make the signature shorter, and the delta longer.
+ *
+ * \param strong_len Strongsum length in bytes to use (0 for "maximum", -1 for
+ * "minimum"). Smaller values make the signature shorter but increase the risk
+ * of corruption from hash collisions.
+ *
+ * \sa rs_sig_file() */
+LIBRSYNC_EXPORT rs_job_t *rs_sig_begin(size_t block_len, size_t strong_len,
+ rs_magic_number sig_magic);
+
+/** Prepare to compute a streaming delta.
+ *
+ * \todo Add a version of this that takes a ::rs_magic_number controlling the
+ * delta format. */
+LIBRSYNC_EXPORT rs_job_t *rs_delta_begin(rs_signature_t *);
+
+/** Read a signature from a file into an ::rs_signature structure in memory.
+ *
+ * Once there, it can be used to generate a delta to a newer version of the
+ * file.
+ *
+ * \note After loading the signatures, you must call \ref rs_build_hash_table()
+ * before you can use them. */
+LIBRSYNC_EXPORT rs_job_t *rs_loadsig_begin(rs_signature_t **);
+
+/** Call this after loading a signature to index it.
+ *
+ * Use rs_free_sumset() to release it after use. */
+LIBRSYNC_EXPORT rs_result rs_build_hash_table(rs_signature_t *sums);
+
+/** Callback used to retrieve parts of the basis file.
+ *
+ * \param pos Position where copying should begin.
+ *
+ * \param len On input, the amount of data that should be retrieved. Updated to
+ * show how much is actually available, but should not be greater than the
+ * input value.
+ *
+ * \param buf On input, a buffer of at least \p *len bytes. May be updated to
+ * point to a buffer allocated by the callback if it prefers. */
+typedef rs_result rs_copy_cb(void *opaque, rs_long_t pos, size_t *len,
+ void **buf);
+
+/** Apply a \a delta to a \a basis file to recreate the \a new file.
+ *
+ * This gives you back a ::rs_job_t object, which can be cranked by calling
+ * rs_job_iter() and updating the stream pointers. When finished, call
+ * rs_job_free() to dispose of it.
+ *
+ * \param copy_cb Callback used to retrieve content from the basis file.
+ *
+ * \param copy_arg Opaque environment pointer passed through to the callback.
+ *
+ * \todo As output is produced, accumulate the MD4 checksum of the output. Then
+ * if we find a CHECKSUM command we can check it's contents against the output.
+ *
+ * \todo Implement COPY commands.
+ *
+ * \sa rs_patch_file() \sa \ref api_streaming */
+LIBRSYNC_EXPORT rs_job_t *rs_patch_begin(rs_copy_cb * copy_cb, void *copy_arg);
+
+# ifndef RSYNC_NO_STDIO_INTERFACE
+# include <stdio.h>
+
+/** Open a file with special handling for stdin or stdout.
+ *
+ * This provides a platform independent way to open large binary files. A
+ * filename "" or "-" means use stdin for reading, or stdout for writing.
+ *
+ * \param filename - The filename to open.
+ *
+ * \param mode - fopen style mode string.
+ *
+ * \param force - bool to force overwriting of existing files. */
+LIBRSYNC_EXPORT FILE *rs_file_open(char const *filename, char const *mode,
+ int force);
+
+/** Close a file with special handling for stdin or stdout.
+ *
+ * This will not actually close the file if it is stdin or stdout.
+ *
+ * \param file - the stdio file to close. */
+LIBRSYNC_EXPORT int rs_file_close(FILE *file);
+
+/** Get the size of a file.
+ *
+ * This provides a platform independent way to get the size of large files. It
+ * will return -1 if the size cannot be determined because it is not a regular
+ * file.
+ *
+ * \param file - the stdio file to get the size of. */
+LIBRSYNC_EXPORT rs_long_t rs_file_size(FILE *file);
+
+/** ::rs_copy_cb that reads from a stdio file. */
+LIBRSYNC_EXPORT rs_result rs_file_copy_cb(void *arg, rs_long_t pos, size_t *len,
+ void **buf);
+
+/** Buffer sizes for file IO.
+ *
+ * The default 0 means use the recommended buffer size for the operation being
+ * performed, any other value will override the recommended sizes. You probably
+ * only need to change these in testing. */
+LIBRSYNC_EXPORT extern int rs_inbuflen, rs_outbuflen;
+
+/** Generate the signature of a basis file, and write it out to another.
+ *
+ * It's recommended you use rs_sig_args() to get the recommended arguments for
+ * this based on the original file size.
+ *
+ * \param old_file Stdio readable file whose signature will be generated.
+ *
+ * \param sig_file Writable stdio file to which the signature will be written./
+ *
+ * \param block_len Checksum block size to use (0 for "recommended"). Larger
+ * values make the signature shorter, and the delta longer.
+ *
+ * \param strong_len Strongsum length in bytes to use (0 for "maximum", -1 for
+ * "minimum"). Smaller values make the signature shorter but increase the risk
+ * of corruption from hash collisions.
+ *
+ * \param sig_magic Signature file format to generate (0 for "recommended").
+ * See ::rs_magic_number.
+ *
+ * \param stats Optional pointer to receive statistics.
+ *
+ * \sa \ref api_whole */
+LIBRSYNC_EXPORT rs_result rs_sig_file(FILE *old_file, FILE *sig_file,
+ size_t block_len, size_t strong_len,
+ rs_magic_number sig_magic,
+ rs_stats_t *stats);
+
+/** Load signatures from a signature file into memory.
+ *
+ * \param sig_file Readable stdio file from which the signature will be read.
+ *
+ * \param sumset on return points to the newly allocated structure.
+ *
+ * \param stats Optional pointer to receive statistics.
+ *
+ * \sa \ref api_whole */
+LIBRSYNC_EXPORT rs_result rs_loadsig_file(FILE *sig_file,
+ rs_signature_t **sumset,
+ rs_stats_t *stats);
+
+/** Generate a delta between a signature and a new file into a delta file.
+ *
+ * \sa \ref api_whole */
+LIBRSYNC_EXPORT rs_result rs_delta_file(rs_signature_t *, FILE *new_file,
+ FILE *delta_file, rs_stats_t *);
+
+/** Apply a patch, relative to a basis, into a new file.
+ *
+ * \sa \ref api_whole */
+LIBRSYNC_EXPORT rs_result rs_patch_file(FILE *basis_file, FILE *delta_file,
+ FILE *new_file, rs_stats_t *);
+# endif /* !RSYNC_NO_STDIO_INTERFACE */
+
+# ifdef __cplusplus
+} /* extern "C" */
+# endif
+
+#endif /* !_RSYNC_H */
diff --git a/src/librsync_export.h b/src/librsync_export.h
new file mode 100644
index 0000000..fd45e48
--- /dev/null
+++ b/src/librsync_export.h
@@ -0,0 +1,18 @@
+#ifndef LIBRSYNC_EXPORT_H
+# define LIBRSYNC_EXPORT_H
+
+# ifdef LIBRSYNC_STATIC_DEFINE
+# define LIBRSYNC_EXPORT
+# else
+# ifdef _WIN32
+# ifdef rsync_EXPORTS
+# define LIBRSYNC_EXPORT __declspec(dllexport)
+# else
+# define LIBRSYNC_EXPORT __declspec(dllimport)
+# endif
+# else
+# define LIBRSYNC_EXPORT __attribute__((visibility("default")))
+# endif
+# endif
+
+#endif /* LIBRSYNC_EXPORT_H */
diff --git a/src/mdfour.c b/src/mdfour.c
new file mode 100644
index 0000000..180cd80
--- /dev/null
+++ b/src/mdfour.c
@@ -0,0 +1,346 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 1997-1999 by Andrew Tridgell
+ * Copyright (C) 2002, 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** \file mdfour.c
+ * MD4 message digest algorithm.
+ *
+ * \todo Perhaps use the MD4 routine from OpenSSL if it's installed. It's
+ * probably not worth the trouble.
+ *
+ * This was originally written by Andrew Tridgell for use in Samba. It was then
+ * modified by;
+ *
+ * 2002-06-xx: Robert Weber <robert.weber@Colorado.edu> optimisations and fixed
+ * >512M support.
+ *
+ * 2002-06-27: Donovan Baarda <abo@minkirri.apana.org.au> further optimisations
+ * and cleanups.
+ *
+ * 2004-09-09: Simon Law <sfllaw@debian.org> handle little-endian machines that
+ * can't do unaligned access (e.g. ia64, pa-risc). */
+
+#include "config.h"
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include "librsync.h"
+#include "mdfour.h"
+
+#define F(X,Y,Z) (((X)&(Y)) | ((~(X))&(Z)))
+#define G(X,Y,Z) (((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)))
+#define H(X,Y,Z) ((X)^(Y)^(Z))
+#define lshift(x,s) (((x)<<(s)) | ((x)>>(32-(s))))
+
+#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
+#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + 0x5A827999U, s)
+#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + 0x6ED9EBA1U, s)
+
+/** padding data used for finalising */
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static void rs_mdfour_block(rs_mdfour_t *md, void const *p);
+
+/** Update an MD4 accumulator from a 64-byte chunk.
+ *
+ * This cannot be used for the last chunk of the file, which must be padded and
+ * contain the file length. rs_mdfour_tail() is used for that.
+ *
+ * \todo Recode to be fast, and to use system integer types. Perhaps if we can
+ * find an mdfour implementation already on the system (e.g. in OpenSSL) then
+ * we should use it instead of our own?
+ *
+ * \param *m An rs_mdfour_t instance to accumulate with.
+ *
+ * \param *p An array of uint32 integers, as read little-endian from the file. */
+static void rs_mdfour64(rs_mdfour_t *m, const void *p)
+{
+ uint32_t AA, BB, CC, DD;
+ uint32_t A, B, C, D;
+ const uint32_t *X = (const uint32_t *)p;
+
+ A = m->A;
+ B = m->B;
+ C = m->C;
+ D = m->D;
+ AA = A;
+ BB = B;
+ CC = C;
+ DD = D;
+
+ ROUND1(A, B, C, D, 0, 3);
+ ROUND1(D, A, B, C, 1, 7);
+ ROUND1(C, D, A, B, 2, 11);
+ ROUND1(B, C, D, A, 3, 19);
+ ROUND1(A, B, C, D, 4, 3);
+ ROUND1(D, A, B, C, 5, 7);
+ ROUND1(C, D, A, B, 6, 11);
+ ROUND1(B, C, D, A, 7, 19);
+ ROUND1(A, B, C, D, 8, 3);
+ ROUND1(D, A, B, C, 9, 7);
+ ROUND1(C, D, A, B, 10, 11);
+ ROUND1(B, C, D, A, 11, 19);
+ ROUND1(A, B, C, D, 12, 3);
+ ROUND1(D, A, B, C, 13, 7);
+ ROUND1(C, D, A, B, 14, 11);
+ ROUND1(B, C, D, A, 15, 19);
+
+ ROUND2(A, B, C, D, 0, 3);
+ ROUND2(D, A, B, C, 4, 5);
+ ROUND2(C, D, A, B, 8, 9);
+ ROUND2(B, C, D, A, 12, 13);
+ ROUND2(A, B, C, D, 1, 3);
+ ROUND2(D, A, B, C, 5, 5);
+ ROUND2(C, D, A, B, 9, 9);
+ ROUND2(B, C, D, A, 13, 13);
+ ROUND2(A, B, C, D, 2, 3);
+ ROUND2(D, A, B, C, 6, 5);
+ ROUND2(C, D, A, B, 10, 9);
+ ROUND2(B, C, D, A, 14, 13);
+ ROUND2(A, B, C, D, 3, 3);
+ ROUND2(D, A, B, C, 7, 5);
+ ROUND2(C, D, A, B, 11, 9);
+ ROUND2(B, C, D, A, 15, 13);
+
+ ROUND3(A, B, C, D, 0, 3);
+ ROUND3(D, A, B, C, 8, 9);
+ ROUND3(C, D, A, B, 4, 11);
+ ROUND3(B, C, D, A, 12, 15);
+ ROUND3(A, B, C, D, 2, 3);
+ ROUND3(D, A, B, C, 10, 9);
+ ROUND3(C, D, A, B, 6, 11);
+ ROUND3(B, C, D, A, 14, 15);
+ ROUND3(A, B, C, D, 1, 3);
+ ROUND3(D, A, B, C, 9, 9);
+ ROUND3(C, D, A, B, 5, 11);
+ ROUND3(B, C, D, A, 13, 15);
+ ROUND3(A, B, C, D, 3, 3);
+ ROUND3(D, A, B, C, 11, 9);
+ ROUND3(C, D, A, B, 7, 11);
+ ROUND3(B, C, D, A, 15, 15);
+
+ A += AA;
+ B += BB;
+ C += CC;
+ D += DD;
+
+ m->A = A;
+ m->B = B;
+ m->C = C;
+ m->D = D;
+}
+
+/** These next routines are necessary because MD4 is specified in terms of
+ * little-endian int32s, but we have a byte buffer. On little-endian platforms,
+ * I think we can just use the buffer pointer directly.
+ *
+ * There are some nice endianness routines in glib, including assembler
+ * variants. If we ever depended on glib, then it could be good to use them
+ * instead. */
+inline static void copy4( /* @out@ */ unsigned char *out, uint32_t const x)
+{
+ out[0] = (unsigned char)(x);
+ out[1] = (unsigned char)(x >> 8);
+ out[2] = (unsigned char)(x >> 16);
+ out[3] = (unsigned char)(x >> 24);
+}
+
+/* We need this if there is a uint64 */
+/* --robert.weber@Colorado.edu */
+#ifdef UINT64_MAX
+inline static void copy8( /* @out@ */ unsigned char *out, uint64_t const x)
+{
+ out[0] = (unsigned char)(x);
+ out[1] = (unsigned char)(x >> 8);
+ out[2] = (unsigned char)(x >> 16);
+ out[3] = (unsigned char)(x >> 24);
+ out[4] = (unsigned char)(x >> 32);
+ out[5] = (unsigned char)(x >> 40);
+ out[6] = (unsigned char)(x >> 48);
+ out[7] = (unsigned char)(x >> 56);
+}
+#endif /* UINT64_MAX */
+
+/* We only need this if we are big-endian */
+#ifdef WORDS_BIGENDIAN
+inline static void copy64( /* @out@ */ uint32_t *M, unsigned char const *in)
+{
+ int i = 16;
+
+ while (i--) {
+ *M++ =
+ (((uint32_t)in[3] << 24) | ((uint32_t)in[2] << 16) |
+ ((uint32_t)in[1] << 8) | (uint32_t)in[0]);
+ in += 4;
+ }
+}
+
+/** Accumulate a block, making appropriate conversions for bigendian machines.
+ */
+inline static void rs_mdfour_block(rs_mdfour_t *md, void const *p)
+{
+ uint32_t M[16];
+
+ copy64(M, p);
+ rs_mdfour64(md, M);
+}
+
+#else /* WORDS_BIGENDIAN */
+
+# ifdef __i386__
+
+/* If we are on an IA-32 machine, we can process directly. */
+inline static void rs_mdfour_block(rs_mdfour_t *md, void const *p)
+{
+ rs_mdfour64(md, p);
+}
+
+# else /* !WORDS_BIGENDIAN && !__i386__ */
+
+/* We are little-endian, but not on i386 and therefore may not be able to do
+ unaligned access safely/quickly.
+
+ So if the input is not already aligned correctly, copy it to an aligned
+ buffer first. */
+inline static void rs_mdfour_block(rs_mdfour_t *md, void const *p)
+{
+ if ((uintptr_t)p & 3) {
+ uint32_t M[16];
+
+ memcpy(M, p, 16 * sizeof(uint32_t));
+ rs_mdfour64(md, M);
+ } else {
+ rs_mdfour64(md, (const uint32_t *)p);
+ }
+}
+
+# endif /* !__i386__ */
+#endif /* WORDS_BIGENDIAN */
+
+void rs_mdfour_begin(rs_mdfour_t *md)
+{
+ memset(md, 0, sizeof(*md));
+ md->A = 0x67452301U;
+ md->B = 0xefcdab89U;
+ md->C = 0x98badcfeU;
+ md->D = 0x10325476U;
+#ifdef UINT64_MAX
+ md->totalN = 0;
+#else
+ md->totalN_hi = md->totalN_lo = 0;
+#endif
+}
+
+/** Handle special behaviour for processing the last block of a file when
+ * calculating its MD4 checksum.
+ *
+ * This must be called exactly once per file.
+ *
+ * Modified by Robert Weber to use uint64 in order that we can sum files > 2^29
+ * = 512 MB. --Robert.Weber@colorado.edu */
+static void rs_mdfour_tail(rs_mdfour_t *m)
+{
+#ifdef UINT64_MAX
+ uint64_t b;
+#else /* UINT64_MAX */
+ uint32_t b[2];
+#endif /* UINT64_MAX */
+ unsigned char buf[8];
+ size_t pad_len;
+
+ /* convert the totalN byte count into a bit count buffer */
+#ifdef UINT64_MAX
+ b = m->totalN << 3;
+ copy8(buf, b);
+#else /* UINT64_MAX */
+ b[0] = m->totalN_lo << 3;
+ b[1] = ((m->totalN_hi << 3) | (m->totalN_lo >> 29));
+ copy4(buf, b[0]);
+ copy4(buf + 4, b[1]);
+#endif /* UINT64_MAX */
+
+ /* calculate length and process the padding data */
+ pad_len = (m->tail_len < 56) ? (56 - m->tail_len) : (120 - m->tail_len);
+ rs_mdfour_update(m, PADDING, pad_len);
+ /* process the bit count */
+ rs_mdfour_update(m, buf, 8);
+}
+
+void rs_mdfour_update(rs_mdfour_t *md, void const *in_void, size_t n)
+{
+ unsigned char const *in = (unsigned char const *)in_void;
+
+ /* increment totalN */
+#ifdef UINT64_MAX
+ md->totalN += n;
+#else /* UINT64_MAX */
+ if ((md->totalN_lo += n) < n)
+ md->totalN_hi++;
+#endif /* UINT64_MAX */
+
+ /* If there's any leftover data in the tail buffer, then first we have to
+ make it up to a whole block to process it. */
+ if (md->tail_len) {
+ size_t tail_gap = 64 - md->tail_len;
+ if (tail_gap <= n) {
+ memcpy(&md->tail[md->tail_len], in, tail_gap);
+ rs_mdfour_block(md, md->tail);
+ in += tail_gap;
+ n -= tail_gap;
+ md->tail_len = 0;
+ }
+ }
+ /* process complete blocks of input */
+ while (n >= 64) {
+ rs_mdfour_block(md, in);
+ in += 64;
+ n -= 64;
+ }
+ /* Put remaining bytes onto tail */
+ if (n) {
+ memcpy(&md->tail[md->tail_len], in, n);
+ md->tail_len += (int)n;
+ }
+}
+
+void rs_mdfour_result(rs_mdfour_t *md, unsigned char *out)
+{
+ rs_mdfour_tail(md);
+
+ copy4(out, md->A);
+ copy4(out + 4, md->B);
+ copy4(out + 8, md->C);
+ copy4(out + 12, md->D);
+}
+
+void rs_mdfour(unsigned char *out, void const *in, size_t n)
+{
+ rs_mdfour_t md;
+
+ rs_mdfour_begin(&md);
+ rs_mdfour_update(&md, in, n);
+ rs_mdfour_result(&md, out);
+}
diff --git a/src/mdfour.h b/src/mdfour.h
new file mode 100644
index 0000000..41af810
--- /dev/null
+++ b/src/mdfour.h
@@ -0,0 +1,33 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 2002, 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** \private Internal state while computing an MD4 hash. */
+struct rs_mdfour {
+ unsigned int A, B, C, D;
+#ifdef UINT64_MAX
+ uint64_t totalN;
+#else
+ uint32_t totalN_hi, totalN_lo;
+#endif
+ int tail_len;
+ unsigned char tail[64];
+};
diff --git a/src/mksum.c b/src/mksum.c
new file mode 100644
index 0000000..9eb11eb
--- /dev/null
+++ b/src/mksum.c
@@ -0,0 +1,123 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- library for network deltas
+ *
+ * Copyright 1999-2001, 2014, 2015 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 1999 by Andrew Tridgell <tridge@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** \file mksum.c
+ * Generate file signatures.
+ *
+ * Generating checksums is pretty easy, since we can always just process
+ * whatever data is available. When a whole block has arrived, or we've reached
+ * the end of the file, we write the checksum out. */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include "librsync.h"
+#include "job.h"
+#include "sumset.h"
+#include "stream.h"
+#include "netint.h"
+#include "trace.h"
+#include "util.h"
+
+/* Possible state functions for signature generation. */
+static rs_result rs_sig_s_header(rs_job_t *);
+static rs_result rs_sig_s_generate(rs_job_t *);
+
+/** State of trying to send the signature header. \private */
+static rs_result rs_sig_s_header(rs_job_t *job)
+{
+ rs_signature_t *sig = job->signature;
+ rs_result result;
+
+ if ((result =
+ rs_signature_init(sig, job->sig_magic, job->sig_block_len,
+ job->sig_strong_len, 0)) != RS_DONE)
+ return result;
+ rs_squirt_n4(job, sig->magic);
+ rs_squirt_n4(job, sig->block_len);
+ rs_squirt_n4(job, sig->strong_sum_len);
+ rs_trace("sent header (magic %#x, block len = %d, strong sum len = %d)",
+ sig->magic, sig->block_len, sig->strong_sum_len);
+ job->stats.block_len = sig->block_len;
+
+ job->statefn = rs_sig_s_generate;
+ return RS_RUNNING;
+}
+
+/** Generate the checksums for a block and write it out. Called when we
+ * already know we have enough data in memory at \p block. \private */
+static rs_result rs_sig_do_block(rs_job_t *job, const void *block, size_t len)
+{
+ rs_signature_t *sig = job->signature;
+ rs_weak_sum_t weak_sum;
+ rs_strong_sum_t strong_sum;
+
+ weak_sum = rs_signature_calc_weak_sum(sig, block, len);
+ rs_signature_calc_strong_sum(sig, block, len, &strong_sum);
+ rs_squirt_n4(job, weak_sum);
+ rs_tube_write(job, strong_sum, sig->strong_sum_len);
+ if (rs_trace_enabled()) {
+ char strong_sum_hex[RS_MAX_STRONG_SUM_LENGTH * 2 + 1];
+ rs_hexify(strong_sum_hex, strong_sum, sig->strong_sum_len);
+ rs_trace("sent block: weak=" FMT_WEAKSUM ", strong=%s", weak_sum,
+ strong_sum_hex);
+ }
+ job->stats.sig_blocks++;
+ return RS_RUNNING;
+}
+
+/** State of reading a block and trying to generate its sum. \private */
+static rs_result rs_sig_s_generate(rs_job_t *job)
+{
+ rs_result result;
+ size_t len;
+ void *block;
+
+ /* must get a whole block, otherwise try again */
+ len = job->signature->block_len;
+ result = rs_scoop_read(job, len, &block);
+ /* If we are near EOF, get whatever is left. */
+ if (result == RS_INPUT_ENDED)
+ result = rs_scoop_read_rest(job, &len, &block);
+ if (result == RS_INPUT_ENDED) {
+ return RS_DONE;
+ } else if (result != RS_DONE) {
+ rs_trace("generate stopped: %s", rs_strerror(result));
+ return result;
+ }
+ rs_trace("got " FMT_SIZE " byte block", len);
+ return rs_sig_do_block(job, block, len);
+}
+
+rs_job_t *rs_sig_begin(size_t block_len, size_t strong_len,
+ rs_magic_number sig_magic)
+{
+ rs_job_t *job;
+
+ job = rs_job_new("signature", rs_sig_s_header);
+ job->signature = rs_alloc_struct(rs_signature_t);
+ job->job_owns_sig = 1;
+ job->sig_magic = sig_magic;
+ job->sig_block_len = (int)block_len;
+ job->sig_strong_len = (int)strong_len;
+ return job;
+}
diff --git a/src/msg.c b/src/msg.c
new file mode 100644
index 0000000..9b7b001
--- /dev/null
+++ b/src/msg.c
@@ -0,0 +1,75 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | Welcome to Arco AM/PM Mini-Market. We
+ | would like to advise our customers
+ | that any individual who offers to
+ | pump gas, wash windows or solicit
+ | products is not employed by or
+ | associated with this facility. We
+ | discourage any contact with these
+ | individuals and ask that you report
+ | any problems to uniformed personal
+ | inside. Thankyou for shopping at
+ | Arco, and have a nice day.
+ */
+
+/** \file msg.c
+ * error messages for re_result values.
+ *
+ * \todo (Suggestion by tridge) Add a function which outputs a complete text
+ * description of a job, including only the fields relevant to the current
+ * encoding function. */
+
+#include "config.h"
+#include "librsync.h"
+
+char const *rs_strerror(rs_result r)
+{
+ switch (r) {
+ case RS_DONE:
+ return "OK";
+ case RS_RUNNING:
+ return "still running";
+ case RS_BLOCKED:
+ return "blocked waiting for input or output buffers";
+ case RS_BAD_MAGIC:
+ return "bad magic number at start of stream";
+ case RS_INPUT_ENDED:
+ return "unexpected end of input";
+ case RS_CORRUPT:
+ return "stream corrupt";
+ case RS_UNIMPLEMENTED:
+ return "unimplemented case";
+ case RS_MEM_ERROR:
+ return "out of memory";
+ case RS_IO_ERROR:
+ return "IO error";
+ case RS_SYNTAX_ERROR:
+ return "bad command line syntax";
+ case RS_INTERNAL_ERROR:
+ return "library internal error";
+
+ default:
+ return "unexplained problem";
+ }
+}
diff --git a/src/netint.c b/src/netint.c
new file mode 100644
index 0000000..0ee716e
--- /dev/null
+++ b/src/netint.c
@@ -0,0 +1,130 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- library for network deltas
+ *
+ * Copyright (C) 1999, 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 1999 by Andrew Tridgell <tridge@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | Ummm, well, OK. The network's the
+ | network, the computer's the
+ | computer. Sorry for the confusion.
+ | -- Sun Microsystems
+ */
+
+/** \file netint.c
+ * Network-byte-order output to the tube.
+ *
+ * All the `suck' routines return a result code. The most common values are
+ * RS_DONE if they have enough data, or RS_BLOCKED if there is not enough input
+ * to proceed.
+ *
+ * The `squirt` routines also return a result code which in theory could be
+ * RS_BLOCKED if there is not enough output space to proceed, but in practice
+ * is always RS_DONE. */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include "librsync.h"
+#include "netint.h"
+#include "stream.h"
+
+#define RS_MAX_INT_BYTES 8
+
+/** Write a single byte to a stream output. */
+rs_result rs_squirt_byte(rs_job_t *job, rs_byte_t val)
+{
+ rs_tube_write(job, &val, 1);
+ return RS_DONE;
+}
+
+/** Write a variable-length integer to a stream.
+ *
+ * \param job - Job of data.
+ *
+ * \param val - Value to write out.
+ *
+ * \param len - Length of integer, in bytes. */
+rs_result rs_squirt_netint(rs_job_t *job, rs_long_t val, int len)
+{
+ rs_byte_t buf[RS_MAX_INT_BYTES];
+ int i;
+
+ assert(len <= RS_MAX_INT_BYTES);
+ /* Fill the output buffer with a bigendian representation of the number. */
+ for (i = len - 1; i >= 0; i--) {
+ buf[i] = (rs_byte_t)val; /* truncated */
+ val >>= 8;
+ }
+ rs_tube_write(job, buf, len);
+ return RS_DONE;
+}
+
+rs_result rs_squirt_n4(rs_job_t *job, int val)
+{
+ return rs_squirt_netint(job, val, 4);
+}
+
+rs_result rs_suck_byte(rs_job_t *job, rs_byte_t *val)
+{
+ rs_result result;
+ rs_byte_t *buf;
+
+ if ((result = rs_scoop_read(job, 1, (void **)&buf)) == RS_DONE)
+ *val = *buf;
+ return result;
+}
+
+rs_result rs_suck_netint(rs_job_t *job, rs_long_t *val, int len)
+{
+ rs_result result;
+ rs_byte_t *buf;
+ int i;
+
+ assert(len <= RS_MAX_INT_BYTES);
+ if ((result = rs_scoop_read(job, len, (void **)&buf)) == RS_DONE) {
+ *val = 0;
+ for (i = 0; i < len; i++)
+ *val = (*val << 8) | (rs_long_t)buf[i];
+ }
+ return result;
+}
+
+rs_result rs_suck_n4(rs_job_t *job, int *val)
+{
+ rs_result result;
+ rs_long_t buf;
+
+ if ((result = rs_suck_netint(job, &buf, 4)) == RS_DONE)
+ *val = (int)buf;
+ return result;
+}
+
+int rs_int_len(rs_long_t val)
+{
+ assert(val >= 0);
+ if (!(val & ~(rs_long_t)0xff))
+ return 1;
+ if (!(val & ~(rs_long_t)0xffff))
+ return 2;
+ if (!(val & ~(rs_long_t)0xffffffff))
+ return 4;
+ assert(!(val & ~(rs_long_t)0xffffffffffffffff));
+ return 8;
+}
diff --git a/src/netint.h b/src/netint.h
new file mode 100644
index 0000000..b8a05f8
--- /dev/null
+++ b/src/netint.h
@@ -0,0 +1,31 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- library for network deltas
+ *
+ * Copyright (C) 1999, 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 1999 by Andrew Tridgell <tridge@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+rs_result rs_squirt_byte(rs_job_t *job, rs_byte_t val);
+rs_result rs_squirt_netint(rs_job_t *job, rs_long_t val, int len);
+rs_result rs_squirt_n4(rs_job_t *job, int val);
+
+rs_result rs_suck_byte(rs_job_t *job, rs_byte_t *val);
+rs_result rs_suck_netint(rs_job_t *job, rs_long_t *val, int len);
+rs_result rs_suck_n4(rs_job_t *job, int *val);
+
+int rs_int_len(rs_long_t val);
diff --git a/src/patch.c b/src/patch.c
new file mode 100644
index 0000000..7f51470
--- /dev/null
+++ b/src/patch.c
@@ -0,0 +1,225 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | This is Tranquility Base.
+ */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "librsync.h"
+#include "job.h"
+#include "netint.h"
+#include "stream.h"
+#include "command.h"
+#include "prototab.h"
+#include "trace.h"
+
+static rs_result rs_patch_s_cmdbyte(rs_job_t *);
+static rs_result rs_patch_s_params(rs_job_t *);
+static rs_result rs_patch_s_run(rs_job_t *);
+static rs_result rs_patch_s_literal(rs_job_t *);
+static rs_result rs_patch_s_copy(rs_job_t *);
+static rs_result rs_patch_s_copying(rs_job_t *);
+
+/** State of trying to read the first byte of a command. Once we've taken that
+ * in, we can know how much data to read to get the arguments. */
+static rs_result rs_patch_s_cmdbyte(rs_job_t *job)
+{
+ rs_result result;
+
+ if ((result = rs_suck_byte(job, &job->op)) != RS_DONE)
+ return result;
+ job->cmd = &rs_prototab[job->op];
+ rs_trace("got command %#04x (%s), len_1=%d, len_2=%d", job->op,
+ rs_op_kind_name(job->cmd->kind), job->cmd->len_1, job->cmd->len_2);
+ if (job->cmd->len_1)
+ job->statefn = rs_patch_s_params;
+ else {
+ job->param1 = job->cmd->immediate;
+ job->statefn = rs_patch_s_run;
+ }
+ return RS_RUNNING;
+}
+
+/** Called after reading a command byte to pull in its parameters and then
+ * setup to execute the command. */
+static rs_result rs_patch_s_params(rs_job_t *job)
+{
+ rs_result result;
+ const size_t len = (size_t)(job->cmd->len_1 + job->cmd->len_2);
+ void *p;
+
+ assert(len);
+ result = rs_scoop_readahead(job, len, &p);
+ if (result != RS_DONE)
+ return result;
+ /* we now must have LEN bytes buffered */
+ result = rs_suck_netint(job, &job->param1, job->cmd->len_1);
+ /* shouldn't fail, since we already checked */
+ assert(result == RS_DONE);
+ if (job->cmd->len_2) {
+ result = rs_suck_netint(job, &job->param2, job->cmd->len_2);
+ assert(result == RS_DONE);
+ }
+ job->statefn = rs_patch_s_run;
+ return RS_RUNNING;
+}
+
+/** Called when we've read in the whole command and we need to execute it. */
+static rs_result rs_patch_s_run(rs_job_t *job)
+{
+ rs_trace("running command %#04x", job->op);
+ switch (job->cmd->kind) {
+ case RS_KIND_LITERAL:
+ job->statefn = rs_patch_s_literal;
+ return RS_RUNNING;
+ case RS_KIND_END:
+ return RS_DONE;
+ /* so we exit here; trying to continue causes an error */
+ case RS_KIND_COPY:
+ job->statefn = rs_patch_s_copy;
+ return RS_RUNNING;
+ default:
+ rs_error("bogus command %#04x", job->op);
+ return RS_CORRUPT;
+ }
+}
+
+/** Called when trying to copy through literal data. */
+static rs_result rs_patch_s_literal(rs_job_t *job)
+{
+ const rs_long_t len = job->param1;
+ rs_stats_t *stats = &job->stats;
+
+ rs_trace("LITERAL(length=" FMT_LONG ")", len);
+ if (len <= 0 || len > SIZE_MAX) {
+ rs_error("invalid length=" FMT_LONG " on LITERAL command", len);
+ return RS_CORRUPT;
+ }
+ stats->lit_cmds++;
+ stats->lit_bytes += len;
+ stats->lit_cmdbytes += 1 + job->cmd->len_1;
+ rs_tube_copy(job, (size_t)len);
+ job->statefn = rs_patch_s_cmdbyte;
+ return RS_RUNNING;
+}
+
+static rs_result rs_patch_s_copy(rs_job_t *job)
+{
+ const rs_long_t pos = job->param1;
+ const rs_long_t len = job->param2;
+ rs_stats_t *stats = &job->stats;
+
+ rs_trace("COPY(position=" FMT_LONG ", length=" FMT_LONG ")", pos, len);
+ if (len <= 0) {
+ rs_error("invalid length=" FMT_LONG " on COPY command", len);
+ return RS_CORRUPT;
+ }
+ if (pos < 0) {
+ rs_error("invalid position=" FMT_LONG " on COPY command", pos);
+ return RS_CORRUPT;
+ }
+ stats->copy_cmds++;
+ stats->copy_bytes += len;
+ stats->copy_cmdbytes += 1 + job->cmd->len_1 + job->cmd->len_2;
+ job->basis_pos = pos;
+ job->basis_len = len;
+ job->statefn = rs_patch_s_copying;
+ return RS_RUNNING;
+}
+
+/** Called when we're executing a COPY command and waiting for all the data to
+ * be retrieved from the callback. */
+static rs_result rs_patch_s_copying(rs_job_t *job)
+{
+ rs_result result;
+ rs_buffers_t *buffs = job->stream;
+ rs_long_t req = job->basis_len;
+ size_t len = buffs->avail_out;
+ void *ptr = buffs->next_out;
+
+ /* We are blocked if there is no space left to copy into. */
+ if (!len)
+ return RS_BLOCKED;
+ /* Adjust request to min of amount requested and space available. */
+ if (len < req)
+ req = (rs_long_t)len;
+ rs_trace("copy " FMT_LONG " bytes from basis at offset " FMT_LONG "", req,
+ job->basis_pos);
+ len = (size_t)req;
+ result = (job->copy_cb) (job->copy_arg, job->basis_pos, &len, &ptr);
+ if (result != RS_DONE) {
+ rs_trace("copy callback returned %s", rs_strerror(result));
+ return result;
+ }
+ rs_trace("got " FMT_SIZE " bytes back from basis callback", len);
+ /* Actual copied length cannot be greater than requested length. */
+ assert(len <= req);
+ /* Backwards-compatible defensively handle this for NDEBUG builds. */
+ if (len > req) {
+ rs_warn("copy_cb() returned more than the requested length");
+ len = (size_t)req;
+ }
+ /* copy back to out buffer only if the callback has used its own buffer */
+ if (ptr != buffs->next_out)
+ memcpy(buffs->next_out, ptr, len);
+ /* Update buffs and copy for copied data. */
+ buffs->next_out += len;
+ buffs->avail_out -= len;
+ job->basis_pos += (rs_long_t)len;
+ job->basis_len -= (rs_long_t)len;
+ if (!job->basis_len) {
+ /* Nothing left to copy, we are done! */
+ job->statefn = rs_patch_s_cmdbyte;
+ }
+ return RS_RUNNING;
+}
+
+/** Called while we're trying to read the header of the patch. */
+static rs_result rs_patch_s_header(rs_job_t *job)
+{
+ int v;
+ rs_result result;
+
+ if ((result = rs_suck_n4(job, &v)) != RS_DONE)
+ return result;
+ if (v != RS_DELTA_MAGIC) {
+ rs_error("got magic number %#x rather than expected value %#x", v,
+ RS_DELTA_MAGIC);
+ return RS_BAD_MAGIC;
+ } else
+ rs_trace("got patch magic %#x", v);
+ job->statefn = rs_patch_s_cmdbyte;
+ return RS_RUNNING;
+}
+
+rs_job_t *rs_patch_begin(rs_copy_cb * copy_cb, void *copy_arg)
+{
+ rs_job_t *job = rs_job_new("patch", rs_patch_s_header);
+
+ job->copy_cb = copy_cb;
+ job->copy_arg = copy_arg;
+ rs_mdfour_begin(&job->output_md4);
+ return job;
+}
diff --git a/src/prototab.c b/src/prototab.c
new file mode 100644
index 0000000..c09fde8
--- /dev/null
+++ b/src/prototab.c
@@ -0,0 +1,292 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- library for network deltas
+ *
+ * Copyright 2000, 2001, 2014, 2015 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** \file prototab.c
+ * Delta file commands.
+ *
+ * This file defines an array mapping command IDs to the operation kind,
+ * implied literal value, and length of the first and second parameters. The
+ * implied value is only used if the first parameter length is zero. */
+
+#include "config.h"
+#include "librsync.h"
+#include "command.h"
+#include "prototab.h"
+
+const struct rs_prototab_ent rs_prototab[] = {
+ {RS_KIND_END, 0, 0, 0}, /* RS_OP_END = 0 */
+ {RS_KIND_LITERAL, 1, 0, 0}, /* RS_OP_LITERAL_1 = 0x1 */
+ {RS_KIND_LITERAL, 2, 0, 0}, /* RS_OP_LITERAL_2 = 0x2 */
+ {RS_KIND_LITERAL, 3, 0, 0}, /* RS_OP_LITERAL_3 = 0x3 */
+ {RS_KIND_LITERAL, 4, 0, 0}, /* RS_OP_LITERAL_4 = 0x4 */
+ {RS_KIND_LITERAL, 5, 0, 0}, /* RS_OP_LITERAL_5 = 0x5 */
+ {RS_KIND_LITERAL, 6, 0, 0}, /* RS_OP_LITERAL_6 = 0x6 */
+ {RS_KIND_LITERAL, 7, 0, 0}, /* RS_OP_LITERAL_7 = 0x7 */
+ {RS_KIND_LITERAL, 8, 0, 0}, /* RS_OP_LITERAL_8 = 0x8 */
+ {RS_KIND_LITERAL, 9, 0, 0}, /* RS_OP_LITERAL_9 = 0x9 */
+ {RS_KIND_LITERAL, 10, 0, 0}, /* RS_OP_LITERAL_10 = 0xa */
+ {RS_KIND_LITERAL, 11, 0, 0}, /* RS_OP_LITERAL_11 = 0xb */
+ {RS_KIND_LITERAL, 12, 0, 0}, /* RS_OP_LITERAL_12 = 0xc */
+ {RS_KIND_LITERAL, 13, 0, 0}, /* RS_OP_LITERAL_13 = 0xd */
+ {RS_KIND_LITERAL, 14, 0, 0}, /* RS_OP_LITERAL_14 = 0xe */
+ {RS_KIND_LITERAL, 15, 0, 0}, /* RS_OP_LITERAL_15 = 0xf */
+ {RS_KIND_LITERAL, 16, 0, 0}, /* RS_OP_LITERAL_16 = 0x10 */
+ {RS_KIND_LITERAL, 17, 0, 0}, /* RS_OP_LITERAL_17 = 0x11 */
+ {RS_KIND_LITERAL, 18, 0, 0}, /* RS_OP_LITERAL_18 = 0x12 */
+ {RS_KIND_LITERAL, 19, 0, 0}, /* RS_OP_LITERAL_19 = 0x13 */
+ {RS_KIND_LITERAL, 20, 0, 0}, /* RS_OP_LITERAL_20 = 0x14 */
+ {RS_KIND_LITERAL, 21, 0, 0}, /* RS_OP_LITERAL_21 = 0x15 */
+ {RS_KIND_LITERAL, 22, 0, 0}, /* RS_OP_LITERAL_22 = 0x16 */
+ {RS_KIND_LITERAL, 23, 0, 0}, /* RS_OP_LITERAL_23 = 0x17 */
+ {RS_KIND_LITERAL, 24, 0, 0}, /* RS_OP_LITERAL_24 = 0x18 */
+ {RS_KIND_LITERAL, 25, 0, 0}, /* RS_OP_LITERAL_25 = 0x19 */
+ {RS_KIND_LITERAL, 26, 0, 0}, /* RS_OP_LITERAL_26 = 0x1a */
+ {RS_KIND_LITERAL, 27, 0, 0}, /* RS_OP_LITERAL_27 = 0x1b */
+ {RS_KIND_LITERAL, 28, 0, 0}, /* RS_OP_LITERAL_28 = 0x1c */
+ {RS_KIND_LITERAL, 29, 0, 0}, /* RS_OP_LITERAL_29 = 0x1d */
+ {RS_KIND_LITERAL, 30, 0, 0}, /* RS_OP_LITERAL_30 = 0x1e */
+ {RS_KIND_LITERAL, 31, 0, 0}, /* RS_OP_LITERAL_31 = 0x1f */
+ {RS_KIND_LITERAL, 32, 0, 0}, /* RS_OP_LITERAL_32 = 0x20 */
+ {RS_KIND_LITERAL, 33, 0, 0}, /* RS_OP_LITERAL_33 = 0x21 */
+ {RS_KIND_LITERAL, 34, 0, 0}, /* RS_OP_LITERAL_34 = 0x22 */
+ {RS_KIND_LITERAL, 35, 0, 0}, /* RS_OP_LITERAL_35 = 0x23 */
+ {RS_KIND_LITERAL, 36, 0, 0}, /* RS_OP_LITERAL_36 = 0x24 */
+ {RS_KIND_LITERAL, 37, 0, 0}, /* RS_OP_LITERAL_37 = 0x25 */
+ {RS_KIND_LITERAL, 38, 0, 0}, /* RS_OP_LITERAL_38 = 0x26 */
+ {RS_KIND_LITERAL, 39, 0, 0}, /* RS_OP_LITERAL_39 = 0x27 */
+ {RS_KIND_LITERAL, 40, 0, 0}, /* RS_OP_LITERAL_40 = 0x28 */
+ {RS_KIND_LITERAL, 41, 0, 0}, /* RS_OP_LITERAL_41 = 0x29 */
+ {RS_KIND_LITERAL, 42, 0, 0}, /* RS_OP_LITERAL_42 = 0x2a */
+ {RS_KIND_LITERAL, 43, 0, 0}, /* RS_OP_LITERAL_43 = 0x2b */
+ {RS_KIND_LITERAL, 44, 0, 0}, /* RS_OP_LITERAL_44 = 0x2c */
+ {RS_KIND_LITERAL, 45, 0, 0}, /* RS_OP_LITERAL_45 = 0x2d */
+ {RS_KIND_LITERAL, 46, 0, 0}, /* RS_OP_LITERAL_46 = 0x2e */
+ {RS_KIND_LITERAL, 47, 0, 0}, /* RS_OP_LITERAL_47 = 0x2f */
+ {RS_KIND_LITERAL, 48, 0, 0}, /* RS_OP_LITERAL_48 = 0x30 */
+ {RS_KIND_LITERAL, 49, 0, 0}, /* RS_OP_LITERAL_49 = 0x31 */
+ {RS_KIND_LITERAL, 50, 0, 0}, /* RS_OP_LITERAL_50 = 0x32 */
+ {RS_KIND_LITERAL, 51, 0, 0}, /* RS_OP_LITERAL_51 = 0x33 */
+ {RS_KIND_LITERAL, 52, 0, 0}, /* RS_OP_LITERAL_52 = 0x34 */
+ {RS_KIND_LITERAL, 53, 0, 0}, /* RS_OP_LITERAL_53 = 0x35 */
+ {RS_KIND_LITERAL, 54, 0, 0}, /* RS_OP_LITERAL_54 = 0x36 */
+ {RS_KIND_LITERAL, 55, 0, 0}, /* RS_OP_LITERAL_55 = 0x37 */
+ {RS_KIND_LITERAL, 56, 0, 0}, /* RS_OP_LITERAL_56 = 0x38 */
+ {RS_KIND_LITERAL, 57, 0, 0}, /* RS_OP_LITERAL_57 = 0x39 */
+ {RS_KIND_LITERAL, 58, 0, 0}, /* RS_OP_LITERAL_58 = 0x3a */
+ {RS_KIND_LITERAL, 59, 0, 0}, /* RS_OP_LITERAL_59 = 0x3b */
+ {RS_KIND_LITERAL, 60, 0, 0}, /* RS_OP_LITERAL_60 = 0x3c */
+ {RS_KIND_LITERAL, 61, 0, 0}, /* RS_OP_LITERAL_61 = 0x3d */
+ {RS_KIND_LITERAL, 62, 0, 0}, /* RS_OP_LITERAL_62 = 0x3e */
+ {RS_KIND_LITERAL, 63, 0, 0}, /* RS_OP_LITERAL_63 = 0x3f */
+ {RS_KIND_LITERAL, 64, 0, 0}, /* RS_OP_LITERAL_64 = 0x40 */
+ {RS_KIND_LITERAL, 0, 1, 0}, /* RS_OP_LITERAL_N1 = 0x41 */
+ {RS_KIND_LITERAL, 0, 2, 0}, /* RS_OP_LITERAL_N2 = 0x42 */
+ {RS_KIND_LITERAL, 0, 4, 0}, /* RS_OP_LITERAL_N4 = 0x43 */
+ {RS_KIND_LITERAL, 0, 8, 0}, /* RS_OP_LITERAL_N8 = 0x44 */
+ {RS_KIND_COPY, 0, 1, 1}, /* RS_OP_COPY_N1_N1 = 0x45 */
+ {RS_KIND_COPY, 0, 1, 2}, /* RS_OP_COPY_N1_N2 = 0x46 */
+ {RS_KIND_COPY, 0, 1, 4}, /* RS_OP_COPY_N1_N4 = 0x47 */
+ {RS_KIND_COPY, 0, 1, 8}, /* RS_OP_COPY_N1_N8 = 0x48 */
+ {RS_KIND_COPY, 0, 2, 1}, /* RS_OP_COPY_N2_N1 = 0x49 */
+ {RS_KIND_COPY, 0, 2, 2}, /* RS_OP_COPY_N2_N2 = 0x4a */
+ {RS_KIND_COPY, 0, 2, 4}, /* RS_OP_COPY_N2_N4 = 0x4b */
+ {RS_KIND_COPY, 0, 2, 8}, /* RS_OP_COPY_N2_N8 = 0x4c */
+ {RS_KIND_COPY, 0, 4, 1}, /* RS_OP_COPY_N4_N1 = 0x4d */
+ {RS_KIND_COPY, 0, 4, 2}, /* RS_OP_COPY_N4_N2 = 0x4e */
+ {RS_KIND_COPY, 0, 4, 4}, /* RS_OP_COPY_N4_N4 = 0x4f */
+ {RS_KIND_COPY, 0, 4, 8}, /* RS_OP_COPY_N4_N8 = 0x50 */
+ {RS_KIND_COPY, 0, 8, 1}, /* RS_OP_COPY_N8_N1 = 0x51 */
+ {RS_KIND_COPY, 0, 8, 2}, /* RS_OP_COPY_N8_N2 = 0x52 */
+ {RS_KIND_COPY, 0, 8, 4}, /* RS_OP_COPY_N8_N4 = 0x53 */
+ {RS_KIND_COPY, 0, 8, 8}, /* RS_OP_COPY_N8_N8 = 0x54 */
+ {RS_KIND_RESERVED, 85, 0, 0}, /* RS_OP_RESERVED_85 = 0x55 */
+ {RS_KIND_RESERVED, 86, 0, 0}, /* RS_OP_RESERVED_86 = 0x56 */
+ {RS_KIND_RESERVED, 87, 0, 0}, /* RS_OP_RESERVED_87 = 0x57 */
+ {RS_KIND_RESERVED, 88, 0, 0}, /* RS_OP_RESERVED_88 = 0x58 */
+ {RS_KIND_RESERVED, 89, 0, 0}, /* RS_OP_RESERVED_89 = 0x59 */
+ {RS_KIND_RESERVED, 90, 0, 0}, /* RS_OP_RESERVED_90 = 0x5a */
+ {RS_KIND_RESERVED, 91, 0, 0}, /* RS_OP_RESERVED_91 = 0x5b */
+ {RS_KIND_RESERVED, 92, 0, 0}, /* RS_OP_RESERVED_92 = 0x5c */
+ {RS_KIND_RESERVED, 93, 0, 0}, /* RS_OP_RESERVED_93 = 0x5d */
+ {RS_KIND_RESERVED, 94, 0, 0}, /* RS_OP_RESERVED_94 = 0x5e */
+ {RS_KIND_RESERVED, 95, 0, 0}, /* RS_OP_RESERVED_95 = 0x5f */
+ {RS_KIND_RESERVED, 96, 0, 0}, /* RS_OP_RESERVED_96 = 0x60 */
+ {RS_KIND_RESERVED, 97, 0, 0}, /* RS_OP_RESERVED_97 = 0x61 */
+ {RS_KIND_RESERVED, 98, 0, 0}, /* RS_OP_RESERVED_98 = 0x62 */
+ {RS_KIND_RESERVED, 99, 0, 0}, /* RS_OP_RESERVED_99 = 0x63 */
+ {RS_KIND_RESERVED, 100, 0, 0}, /* RS_OP_RESERVED_100 = 0x64 */
+ {RS_KIND_RESERVED, 101, 0, 0}, /* RS_OP_RESERVED_101 = 0x65 */
+ {RS_KIND_RESERVED, 102, 0, 0}, /* RS_OP_RESERVED_102 = 0x66 */
+ {RS_KIND_RESERVED, 103, 0, 0}, /* RS_OP_RESERVED_103 = 0x67 */
+ {RS_KIND_RESERVED, 104, 0, 0}, /* RS_OP_RESERVED_104 = 0x68 */
+ {RS_KIND_RESERVED, 105, 0, 0}, /* RS_OP_RESERVED_105 = 0x69 */
+ {RS_KIND_RESERVED, 106, 0, 0}, /* RS_OP_RESERVED_106 = 0x6a */
+ {RS_KIND_RESERVED, 107, 0, 0}, /* RS_OP_RESERVED_107 = 0x6b */
+ {RS_KIND_RESERVED, 108, 0, 0}, /* RS_OP_RESERVED_108 = 0x6c */
+ {RS_KIND_RESERVED, 109, 0, 0}, /* RS_OP_RESERVED_109 = 0x6d */
+ {RS_KIND_RESERVED, 110, 0, 0}, /* RS_OP_RESERVED_110 = 0x6e */
+ {RS_KIND_RESERVED, 111, 0, 0}, /* RS_OP_RESERVED_111 = 0x6f */
+ {RS_KIND_RESERVED, 112, 0, 0}, /* RS_OP_RESERVED_112 = 0x70 */
+ {RS_KIND_RESERVED, 113, 0, 0}, /* RS_OP_RESERVED_113 = 0x71 */
+ {RS_KIND_RESERVED, 114, 0, 0}, /* RS_OP_RESERVED_114 = 0x72 */
+ {RS_KIND_RESERVED, 115, 0, 0}, /* RS_OP_RESERVED_115 = 0x73 */
+ {RS_KIND_RESERVED, 116, 0, 0}, /* RS_OP_RESERVED_116 = 0x74 */
+ {RS_KIND_RESERVED, 117, 0, 0}, /* RS_OP_RESERVED_117 = 0x75 */
+ {RS_KIND_RESERVED, 118, 0, 0}, /* RS_OP_RESERVED_118 = 0x76 */
+ {RS_KIND_RESERVED, 119, 0, 0}, /* RS_OP_RESERVED_119 = 0x77 */
+ {RS_KIND_RESERVED, 120, 0, 0}, /* RS_OP_RESERVED_120 = 0x78 */
+ {RS_KIND_RESERVED, 121, 0, 0}, /* RS_OP_RESERVED_121 = 0x79 */
+ {RS_KIND_RESERVED, 122, 0, 0}, /* RS_OP_RESERVED_122 = 0x7a */
+ {RS_KIND_RESERVED, 123, 0, 0}, /* RS_OP_RESERVED_123 = 0x7b */
+ {RS_KIND_RESERVED, 124, 0, 0}, /* RS_OP_RESERVED_124 = 0x7c */
+ {RS_KIND_RESERVED, 125, 0, 0}, /* RS_OP_RESERVED_125 = 0x7d */
+ {RS_KIND_RESERVED, 126, 0, 0}, /* RS_OP_RESERVED_126 = 0x7e */
+ {RS_KIND_RESERVED, 127, 0, 0}, /* RS_OP_RESERVED_127 = 0x7f */
+ {RS_KIND_RESERVED, 128, 0, 0}, /* RS_OP_RESERVED_128 = 0x80 */
+ {RS_KIND_RESERVED, 129, 0, 0}, /* RS_OP_RESERVED_129 = 0x81 */
+ {RS_KIND_RESERVED, 130, 0, 0}, /* RS_OP_RESERVED_130 = 0x82 */
+ {RS_KIND_RESERVED, 131, 0, 0}, /* RS_OP_RESERVED_131 = 0x83 */
+ {RS_KIND_RESERVED, 132, 0, 0}, /* RS_OP_RESERVED_132 = 0x84 */
+ {RS_KIND_RESERVED, 133, 0, 0}, /* RS_OP_RESERVED_133 = 0x85 */
+ {RS_KIND_RESERVED, 134, 0, 0}, /* RS_OP_RESERVED_134 = 0x86 */
+ {RS_KIND_RESERVED, 135, 0, 0}, /* RS_OP_RESERVED_135 = 0x87 */
+ {RS_KIND_RESERVED, 136, 0, 0}, /* RS_OP_RESERVED_136 = 0x88 */
+ {RS_KIND_RESERVED, 137, 0, 0}, /* RS_OP_RESERVED_137 = 0x89 */
+ {RS_KIND_RESERVED, 138, 0, 0}, /* RS_OP_RESERVED_138 = 0x8a */
+ {RS_KIND_RESERVED, 139, 0, 0}, /* RS_OP_RESERVED_139 = 0x8b */
+ {RS_KIND_RESERVED, 140, 0, 0}, /* RS_OP_RESERVED_140 = 0x8c */
+ {RS_KIND_RESERVED, 141, 0, 0}, /* RS_OP_RESERVED_141 = 0x8d */
+ {RS_KIND_RESERVED, 142, 0, 0}, /* RS_OP_RESERVED_142 = 0x8e */
+ {RS_KIND_RESERVED, 143, 0, 0}, /* RS_OP_RESERVED_143 = 0x8f */
+ {RS_KIND_RESERVED, 144, 0, 0}, /* RS_OP_RESERVED_144 = 0x90 */
+ {RS_KIND_RESERVED, 145, 0, 0}, /* RS_OP_RESERVED_145 = 0x91 */
+ {RS_KIND_RESERVED, 146, 0, 0}, /* RS_OP_RESERVED_146 = 0x92 */
+ {RS_KIND_RESERVED, 147, 0, 0}, /* RS_OP_RESERVED_147 = 0x93 */
+ {RS_KIND_RESERVED, 148, 0, 0}, /* RS_OP_RESERVED_148 = 0x94 */
+ {RS_KIND_RESERVED, 149, 0, 0}, /* RS_OP_RESERVED_149 = 0x95 */
+ {RS_KIND_RESERVED, 150, 0, 0}, /* RS_OP_RESERVED_150 = 0x96 */
+ {RS_KIND_RESERVED, 151, 0, 0}, /* RS_OP_RESERVED_151 = 0x97 */
+ {RS_KIND_RESERVED, 152, 0, 0}, /* RS_OP_RESERVED_152 = 0x98 */
+ {RS_KIND_RESERVED, 153, 0, 0}, /* RS_OP_RESERVED_153 = 0x99 */
+ {RS_KIND_RESERVED, 154, 0, 0}, /* RS_OP_RESERVED_154 = 0x9a */
+ {RS_KIND_RESERVED, 155, 0, 0}, /* RS_OP_RESERVED_155 = 0x9b */
+ {RS_KIND_RESERVED, 156, 0, 0}, /* RS_OP_RESERVED_156 = 0x9c */
+ {RS_KIND_RESERVED, 157, 0, 0}, /* RS_OP_RESERVED_157 = 0x9d */
+ {RS_KIND_RESERVED, 158, 0, 0}, /* RS_OP_RESERVED_158 = 0x9e */
+ {RS_KIND_RESERVED, 159, 0, 0}, /* RS_OP_RESERVED_159 = 0x9f */
+ {RS_KIND_RESERVED, 160, 0, 0}, /* RS_OP_RESERVED_160 = 0xa0 */
+ {RS_KIND_RESERVED, 161, 0, 0}, /* RS_OP_RESERVED_161 = 0xa1 */
+ {RS_KIND_RESERVED, 162, 0, 0}, /* RS_OP_RESERVED_162 = 0xa2 */
+ {RS_KIND_RESERVED, 163, 0, 0}, /* RS_OP_RESERVED_163 = 0xa3 */
+ {RS_KIND_RESERVED, 164, 0, 0}, /* RS_OP_RESERVED_164 = 0xa4 */
+ {RS_KIND_RESERVED, 165, 0, 0}, /* RS_OP_RESERVED_165 = 0xa5 */
+ {RS_KIND_RESERVED, 166, 0, 0}, /* RS_OP_RESERVED_166 = 0xa6 */
+ {RS_KIND_RESERVED, 167, 0, 0}, /* RS_OP_RESERVED_167 = 0xa7 */
+ {RS_KIND_RESERVED, 168, 0, 0}, /* RS_OP_RESERVED_168 = 0xa8 */
+ {RS_KIND_RESERVED, 169, 0, 0}, /* RS_OP_RESERVED_169 = 0xa9 */
+ {RS_KIND_RESERVED, 170, 0, 0}, /* RS_OP_RESERVED_170 = 0xaa */
+ {RS_KIND_RESERVED, 171, 0, 0}, /* RS_OP_RESERVED_171 = 0xab */
+ {RS_KIND_RESERVED, 172, 0, 0}, /* RS_OP_RESERVED_172 = 0xac */
+ {RS_KIND_RESERVED, 173, 0, 0}, /* RS_OP_RESERVED_173 = 0xad */
+ {RS_KIND_RESERVED, 174, 0, 0}, /* RS_OP_RESERVED_174 = 0xae */
+ {RS_KIND_RESERVED, 175, 0, 0}, /* RS_OP_RESERVED_175 = 0xaf */
+ {RS_KIND_RESERVED, 176, 0, 0}, /* RS_OP_RESERVED_176 = 0xb0 */
+ {RS_KIND_RESERVED, 177, 0, 0}, /* RS_OP_RESERVED_177 = 0xb1 */
+ {RS_KIND_RESERVED, 178, 0, 0}, /* RS_OP_RESERVED_178 = 0xb2 */
+ {RS_KIND_RESERVED, 179, 0, 0}, /* RS_OP_RESERVED_179 = 0xb3 */
+ {RS_KIND_RESERVED, 180, 0, 0}, /* RS_OP_RESERVED_180 = 0xb4 */
+ {RS_KIND_RESERVED, 181, 0, 0}, /* RS_OP_RESERVED_181 = 0xb5 */
+ {RS_KIND_RESERVED, 182, 0, 0}, /* RS_OP_RESERVED_182 = 0xb6 */
+ {RS_KIND_RESERVED, 183, 0, 0}, /* RS_OP_RESERVED_183 = 0xb7 */
+ {RS_KIND_RESERVED, 184, 0, 0}, /* RS_OP_RESERVED_184 = 0xb8 */
+ {RS_KIND_RESERVED, 185, 0, 0}, /* RS_OP_RESERVED_185 = 0xb9 */
+ {RS_KIND_RESERVED, 186, 0, 0}, /* RS_OP_RESERVED_186 = 0xba */
+ {RS_KIND_RESERVED, 187, 0, 0}, /* RS_OP_RESERVED_187 = 0xbb */
+ {RS_KIND_RESERVED, 188, 0, 0}, /* RS_OP_RESERVED_188 = 0xbc */
+ {RS_KIND_RESERVED, 189, 0, 0}, /* RS_OP_RESERVED_189 = 0xbd */
+ {RS_KIND_RESERVED, 190, 0, 0}, /* RS_OP_RESERVED_190 = 0xbe */
+ {RS_KIND_RESERVED, 191, 0, 0}, /* RS_OP_RESERVED_191 = 0xbf */
+ {RS_KIND_RESERVED, 192, 0, 0}, /* RS_OP_RESERVED_192 = 0xc0 */
+ {RS_KIND_RESERVED, 193, 0, 0}, /* RS_OP_RESERVED_193 = 0xc1 */
+ {RS_KIND_RESERVED, 194, 0, 0}, /* RS_OP_RESERVED_194 = 0xc2 */
+ {RS_KIND_RESERVED, 195, 0, 0}, /* RS_OP_RESERVED_195 = 0xc3 */
+ {RS_KIND_RESERVED, 196, 0, 0}, /* RS_OP_RESERVED_196 = 0xc4 */
+ {RS_KIND_RESERVED, 197, 0, 0}, /* RS_OP_RESERVED_197 = 0xc5 */
+ {RS_KIND_RESERVED, 198, 0, 0}, /* RS_OP_RESERVED_198 = 0xc6 */
+ {RS_KIND_RESERVED, 199, 0, 0}, /* RS_OP_RESERVED_199 = 0xc7 */
+ {RS_KIND_RESERVED, 200, 0, 0}, /* RS_OP_RESERVED_200 = 0xc8 */
+ {RS_KIND_RESERVED, 201, 0, 0}, /* RS_OP_RESERVED_201 = 0xc9 */
+ {RS_KIND_RESERVED, 202, 0, 0}, /* RS_OP_RESERVED_202 = 0xca */
+ {RS_KIND_RESERVED, 203, 0, 0}, /* RS_OP_RESERVED_203 = 0xcb */
+ {RS_KIND_RESERVED, 204, 0, 0}, /* RS_OP_RESERVED_204 = 0xcc */
+ {RS_KIND_RESERVED, 205, 0, 0}, /* RS_OP_RESERVED_205 = 0xcd */
+ {RS_KIND_RESERVED, 206, 0, 0}, /* RS_OP_RESERVED_206 = 0xce */
+ {RS_KIND_RESERVED, 207, 0, 0}, /* RS_OP_RESERVED_207 = 0xcf */
+ {RS_KIND_RESERVED, 208, 0, 0}, /* RS_OP_RESERVED_208 = 0xd0 */
+ {RS_KIND_RESERVED, 209, 0, 0}, /* RS_OP_RESERVED_209 = 0xd1 */
+ {RS_KIND_RESERVED, 210, 0, 0}, /* RS_OP_RESERVED_210 = 0xd2 */
+ {RS_KIND_RESERVED, 211, 0, 0}, /* RS_OP_RESERVED_211 = 0xd3 */
+ {RS_KIND_RESERVED, 212, 0, 0}, /* RS_OP_RESERVED_212 = 0xd4 */
+ {RS_KIND_RESERVED, 213, 0, 0}, /* RS_OP_RESERVED_213 = 0xd5 */
+ {RS_KIND_RESERVED, 214, 0, 0}, /* RS_OP_RESERVED_214 = 0xd6 */
+ {RS_KIND_RESERVED, 215, 0, 0}, /* RS_OP_RESERVED_215 = 0xd7 */
+ {RS_KIND_RESERVED, 216, 0, 0}, /* RS_OP_RESERVED_216 = 0xd8 */
+ {RS_KIND_RESERVED, 217, 0, 0}, /* RS_OP_RESERVED_217 = 0xd9 */
+ {RS_KIND_RESERVED, 218, 0, 0}, /* RS_OP_RESERVED_218 = 0xda */
+ {RS_KIND_RESERVED, 219, 0, 0}, /* RS_OP_RESERVED_219 = 0xdb */
+ {RS_KIND_RESERVED, 220, 0, 0}, /* RS_OP_RESERVED_220 = 0xdc */
+ {RS_KIND_RESERVED, 221, 0, 0}, /* RS_OP_RESERVED_221 = 0xdd */
+ {RS_KIND_RESERVED, 222, 0, 0}, /* RS_OP_RESERVED_222 = 0xde */
+ {RS_KIND_RESERVED, 223, 0, 0}, /* RS_OP_RESERVED_223 = 0xdf */
+ {RS_KIND_RESERVED, 224, 0, 0}, /* RS_OP_RESERVED_224 = 0xe0 */
+ {RS_KIND_RESERVED, 225, 0, 0}, /* RS_OP_RESERVED_225 = 0xe1 */
+ {RS_KIND_RESERVED, 226, 0, 0}, /* RS_OP_RESERVED_226 = 0xe2 */
+ {RS_KIND_RESERVED, 227, 0, 0}, /* RS_OP_RESERVED_227 = 0xe3 */
+ {RS_KIND_RESERVED, 228, 0, 0}, /* RS_OP_RESERVED_228 = 0xe4 */
+ {RS_KIND_RESERVED, 229, 0, 0}, /* RS_OP_RESERVED_229 = 0xe5 */
+ {RS_KIND_RESERVED, 230, 0, 0}, /* RS_OP_RESERVED_230 = 0xe6 */
+ {RS_KIND_RESERVED, 231, 0, 0}, /* RS_OP_RESERVED_231 = 0xe7 */
+ {RS_KIND_RESERVED, 232, 0, 0}, /* RS_OP_RESERVED_232 = 0xe8 */
+ {RS_KIND_RESERVED, 233, 0, 0}, /* RS_OP_RESERVED_233 = 0xe9 */
+ {RS_KIND_RESERVED, 234, 0, 0}, /* RS_OP_RESERVED_234 = 0xea */
+ {RS_KIND_RESERVED, 235, 0, 0}, /* RS_OP_RESERVED_235 = 0xeb */
+ {RS_KIND_RESERVED, 236, 0, 0}, /* RS_OP_RESERVED_236 = 0xec */
+ {RS_KIND_RESERVED, 237, 0, 0}, /* RS_OP_RESERVED_237 = 0xed */
+ {RS_KIND_RESERVED, 238, 0, 0}, /* RS_OP_RESERVED_238 = 0xee */
+ {RS_KIND_RESERVED, 239, 0, 0}, /* RS_OP_RESERVED_239 = 0xef */
+ {RS_KIND_RESERVED, 240, 0, 0}, /* RS_OP_RESERVED_240 = 0xf0 */
+ {RS_KIND_RESERVED, 241, 0, 0}, /* RS_OP_RESERVED_241 = 0xf1 */
+ {RS_KIND_RESERVED, 242, 0, 0}, /* RS_OP_RESERVED_242 = 0xf2 */
+ {RS_KIND_RESERVED, 243, 0, 0}, /* RS_OP_RESERVED_243 = 0xf3 */
+ {RS_KIND_RESERVED, 244, 0, 0}, /* RS_OP_RESERVED_244 = 0xf4 */
+ {RS_KIND_RESERVED, 245, 0, 0}, /* RS_OP_RESERVED_245 = 0xf5 */
+ {RS_KIND_RESERVED, 246, 0, 0}, /* RS_OP_RESERVED_246 = 0xf6 */
+ {RS_KIND_RESERVED, 247, 0, 0}, /* RS_OP_RESERVED_247 = 0xf7 */
+ {RS_KIND_RESERVED, 248, 0, 0}, /* RS_OP_RESERVED_248 = 0xf8 */
+ {RS_KIND_RESERVED, 249, 0, 0}, /* RS_OP_RESERVED_249 = 0xf9 */
+ {RS_KIND_RESERVED, 250, 0, 0}, /* RS_OP_RESERVED_250 = 0xfa */
+ {RS_KIND_RESERVED, 251, 0, 0}, /* RS_OP_RESERVED_251 = 0xfb */
+ {RS_KIND_RESERVED, 252, 0, 0}, /* RS_OP_RESERVED_252 = 0xfc */
+ {RS_KIND_RESERVED, 253, 0, 0}, /* RS_OP_RESERVED_253 = 0xfd */
+ {RS_KIND_RESERVED, 254, 0, 0}, /* RS_OP_RESERVED_254 = 0xfe */
+ {RS_KIND_RESERVED, 255, 0, 0}, /* RS_OP_RESERVED_255 = 0xff */
+};
diff --git a/src/prototab.h b/src/prototab.h
new file mode 100644
index 0000000..7195d53
--- /dev/null
+++ b/src/prototab.h
@@ -0,0 +1,299 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- library for network deltas
+ *
+ * Copyright 2000, 2001, 2014, 2015 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | I think if you've ordered
+ | somebody to do something you
+ | should probably resist the urge
+ | to thank them.
+ | -- http://abc.net.au/thegames/
+ */
+
+/** \file prototab.h
+ * Delta file commands. */
+
+typedef struct rs_prototab_ent {
+ enum rs_op_kind kind;
+ int immediate;
+ int len_1, len_2;
+} rs_prototab_ent_t;
+
+extern const rs_prototab_ent_t rs_prototab[];
+
+enum {
+ RS_OP_END = 0,
+ RS_OP_LITERAL_1 = 0x1,
+ RS_OP_LITERAL_2 = 0x2,
+ RS_OP_LITERAL_3 = 0x3,
+ RS_OP_LITERAL_4 = 0x4,
+ RS_OP_LITERAL_5 = 0x5,
+ RS_OP_LITERAL_6 = 0x6,
+ RS_OP_LITERAL_7 = 0x7,
+ RS_OP_LITERAL_8 = 0x8,
+ RS_OP_LITERAL_9 = 0x9,
+ RS_OP_LITERAL_10 = 0xa,
+ RS_OP_LITERAL_11 = 0xb,
+ RS_OP_LITERAL_12 = 0xc,
+ RS_OP_LITERAL_13 = 0xd,
+ RS_OP_LITERAL_14 = 0xe,
+ RS_OP_LITERAL_15 = 0xf,
+ RS_OP_LITERAL_16 = 0x10,
+ RS_OP_LITERAL_17 = 0x11,
+ RS_OP_LITERAL_18 = 0x12,
+ RS_OP_LITERAL_19 = 0x13,
+ RS_OP_LITERAL_20 = 0x14,
+ RS_OP_LITERAL_21 = 0x15,
+ RS_OP_LITERAL_22 = 0x16,
+ RS_OP_LITERAL_23 = 0x17,
+ RS_OP_LITERAL_24 = 0x18,
+ RS_OP_LITERAL_25 = 0x19,
+ RS_OP_LITERAL_26 = 0x1a,
+ RS_OP_LITERAL_27 = 0x1b,
+ RS_OP_LITERAL_28 = 0x1c,
+ RS_OP_LITERAL_29 = 0x1d,
+ RS_OP_LITERAL_30 = 0x1e,
+ RS_OP_LITERAL_31 = 0x1f,
+ RS_OP_LITERAL_32 = 0x20,
+ RS_OP_LITERAL_33 = 0x21,
+ RS_OP_LITERAL_34 = 0x22,
+ RS_OP_LITERAL_35 = 0x23,
+ RS_OP_LITERAL_36 = 0x24,
+ RS_OP_LITERAL_37 = 0x25,
+ RS_OP_LITERAL_38 = 0x26,
+ RS_OP_LITERAL_39 = 0x27,
+ RS_OP_LITERAL_40 = 0x28,
+ RS_OP_LITERAL_41 = 0x29,
+ RS_OP_LITERAL_42 = 0x2a,
+ RS_OP_LITERAL_43 = 0x2b,
+ RS_OP_LITERAL_44 = 0x2c,
+ RS_OP_LITERAL_45 = 0x2d,
+ RS_OP_LITERAL_46 = 0x2e,
+ RS_OP_LITERAL_47 = 0x2f,
+ RS_OP_LITERAL_48 = 0x30,
+ RS_OP_LITERAL_49 = 0x31,
+ RS_OP_LITERAL_50 = 0x32,
+ RS_OP_LITERAL_51 = 0x33,
+ RS_OP_LITERAL_52 = 0x34,
+ RS_OP_LITERAL_53 = 0x35,
+ RS_OP_LITERAL_54 = 0x36,
+ RS_OP_LITERAL_55 = 0x37,
+ RS_OP_LITERAL_56 = 0x38,
+ RS_OP_LITERAL_57 = 0x39,
+ RS_OP_LITERAL_58 = 0x3a,
+ RS_OP_LITERAL_59 = 0x3b,
+ RS_OP_LITERAL_60 = 0x3c,
+ RS_OP_LITERAL_61 = 0x3d,
+ RS_OP_LITERAL_62 = 0x3e,
+ RS_OP_LITERAL_63 = 0x3f,
+ RS_OP_LITERAL_64 = 0x40,
+ RS_OP_LITERAL_N1 = 0x41,
+ RS_OP_LITERAL_N2 = 0x42,
+ RS_OP_LITERAL_N4 = 0x43,
+ RS_OP_LITERAL_N8 = 0x44,
+ RS_OP_COPY_N1_N1 = 0x45,
+ RS_OP_COPY_N1_N2 = 0x46,
+ RS_OP_COPY_N1_N4 = 0x47,
+ RS_OP_COPY_N1_N8 = 0x48,
+ RS_OP_COPY_N2_N1 = 0x49,
+ RS_OP_COPY_N2_N2 = 0x4a,
+ RS_OP_COPY_N2_N4 = 0x4b,
+ RS_OP_COPY_N2_N8 = 0x4c,
+ RS_OP_COPY_N4_N1 = 0x4d,
+ RS_OP_COPY_N4_N2 = 0x4e,
+ RS_OP_COPY_N4_N4 = 0x4f,
+ RS_OP_COPY_N4_N8 = 0x50,
+ RS_OP_COPY_N8_N1 = 0x51,
+ RS_OP_COPY_N8_N2 = 0x52,
+ RS_OP_COPY_N8_N4 = 0x53,
+ RS_OP_COPY_N8_N8 = 0x54,
+ RS_OP_RESERVED_85 = 0x55,
+ RS_OP_RESERVED_86 = 0x56,
+ RS_OP_RESERVED_87 = 0x57,
+ RS_OP_RESERVED_88 = 0x58,
+ RS_OP_RESERVED_89 = 0x59,
+ RS_OP_RESERVED_90 = 0x5a,
+ RS_OP_RESERVED_91 = 0x5b,
+ RS_OP_RESERVED_92 = 0x5c,
+ RS_OP_RESERVED_93 = 0x5d,
+ RS_OP_RESERVED_94 = 0x5e,
+ RS_OP_RESERVED_95 = 0x5f,
+ RS_OP_RESERVED_96 = 0x60,
+ RS_OP_RESERVED_97 = 0x61,
+ RS_OP_RESERVED_98 = 0x62,
+ RS_OP_RESERVED_99 = 0x63,
+ RS_OP_RESERVED_100 = 0x64,
+ RS_OP_RESERVED_101 = 0x65,
+ RS_OP_RESERVED_102 = 0x66,
+ RS_OP_RESERVED_103 = 0x67,
+ RS_OP_RESERVED_104 = 0x68,
+ RS_OP_RESERVED_105 = 0x69,
+ RS_OP_RESERVED_106 = 0x6a,
+ RS_OP_RESERVED_107 = 0x6b,
+ RS_OP_RESERVED_108 = 0x6c,
+ RS_OP_RESERVED_109 = 0x6d,
+ RS_OP_RESERVED_110 = 0x6e,
+ RS_OP_RESERVED_111 = 0x6f,
+ RS_OP_RESERVED_112 = 0x70,
+ RS_OP_RESERVED_113 = 0x71,
+ RS_OP_RESERVED_114 = 0x72,
+ RS_OP_RESERVED_115 = 0x73,
+ RS_OP_RESERVED_116 = 0x74,
+ RS_OP_RESERVED_117 = 0x75,
+ RS_OP_RESERVED_118 = 0x76,
+ RS_OP_RESERVED_119 = 0x77,
+ RS_OP_RESERVED_120 = 0x78,
+ RS_OP_RESERVED_121 = 0x79,
+ RS_OP_RESERVED_122 = 0x7a,
+ RS_OP_RESERVED_123 = 0x7b,
+ RS_OP_RESERVED_124 = 0x7c,
+ RS_OP_RESERVED_125 = 0x7d,
+ RS_OP_RESERVED_126 = 0x7e,
+ RS_OP_RESERVED_127 = 0x7f,
+ RS_OP_RESERVED_128 = 0x80,
+ RS_OP_RESERVED_129 = 0x81,
+ RS_OP_RESERVED_130 = 0x82,
+ RS_OP_RESERVED_131 = 0x83,
+ RS_OP_RESERVED_132 = 0x84,
+ RS_OP_RESERVED_133 = 0x85,
+ RS_OP_RESERVED_134 = 0x86,
+ RS_OP_RESERVED_135 = 0x87,
+ RS_OP_RESERVED_136 = 0x88,
+ RS_OP_RESERVED_137 = 0x89,
+ RS_OP_RESERVED_138 = 0x8a,
+ RS_OP_RESERVED_139 = 0x8b,
+ RS_OP_RESERVED_140 = 0x8c,
+ RS_OP_RESERVED_141 = 0x8d,
+ RS_OP_RESERVED_142 = 0x8e,
+ RS_OP_RESERVED_143 = 0x8f,
+ RS_OP_RESERVED_144 = 0x90,
+ RS_OP_RESERVED_145 = 0x91,
+ RS_OP_RESERVED_146 = 0x92,
+ RS_OP_RESERVED_147 = 0x93,
+ RS_OP_RESERVED_148 = 0x94,
+ RS_OP_RESERVED_149 = 0x95,
+ RS_OP_RESERVED_150 = 0x96,
+ RS_OP_RESERVED_151 = 0x97,
+ RS_OP_RESERVED_152 = 0x98,
+ RS_OP_RESERVED_153 = 0x99,
+ RS_OP_RESERVED_154 = 0x9a,
+ RS_OP_RESERVED_155 = 0x9b,
+ RS_OP_RESERVED_156 = 0x9c,
+ RS_OP_RESERVED_157 = 0x9d,
+ RS_OP_RESERVED_158 = 0x9e,
+ RS_OP_RESERVED_159 = 0x9f,
+ RS_OP_RESERVED_160 = 0xa0,
+ RS_OP_RESERVED_161 = 0xa1,
+ RS_OP_RESERVED_162 = 0xa2,
+ RS_OP_RESERVED_163 = 0xa3,
+ RS_OP_RESERVED_164 = 0xa4,
+ RS_OP_RESERVED_165 = 0xa5,
+ RS_OP_RESERVED_166 = 0xa6,
+ RS_OP_RESERVED_167 = 0xa7,
+ RS_OP_RESERVED_168 = 0xa8,
+ RS_OP_RESERVED_169 = 0xa9,
+ RS_OP_RESERVED_170 = 0xaa,
+ RS_OP_RESERVED_171 = 0xab,
+ RS_OP_RESERVED_172 = 0xac,
+ RS_OP_RESERVED_173 = 0xad,
+ RS_OP_RESERVED_174 = 0xae,
+ RS_OP_RESERVED_175 = 0xaf,
+ RS_OP_RESERVED_176 = 0xb0,
+ RS_OP_RESERVED_177 = 0xb1,
+ RS_OP_RESERVED_178 = 0xb2,
+ RS_OP_RESERVED_179 = 0xb3,
+ RS_OP_RESERVED_180 = 0xb4,
+ RS_OP_RESERVED_181 = 0xb5,
+ RS_OP_RESERVED_182 = 0xb6,
+ RS_OP_RESERVED_183 = 0xb7,
+ RS_OP_RESERVED_184 = 0xb8,
+ RS_OP_RESERVED_185 = 0xb9,
+ RS_OP_RESERVED_186 = 0xba,
+ RS_OP_RESERVED_187 = 0xbb,
+ RS_OP_RESERVED_188 = 0xbc,
+ RS_OP_RESERVED_189 = 0xbd,
+ RS_OP_RESERVED_190 = 0xbe,
+ RS_OP_RESERVED_191 = 0xbf,
+ RS_OP_RESERVED_192 = 0xc0,
+ RS_OP_RESERVED_193 = 0xc1,
+ RS_OP_RESERVED_194 = 0xc2,
+ RS_OP_RESERVED_195 = 0xc3,
+ RS_OP_RESERVED_196 = 0xc4,
+ RS_OP_RESERVED_197 = 0xc5,
+ RS_OP_RESERVED_198 = 0xc6,
+ RS_OP_RESERVED_199 = 0xc7,
+ RS_OP_RESERVED_200 = 0xc8,
+ RS_OP_RESERVED_201 = 0xc9,
+ RS_OP_RESERVED_202 = 0xca,
+ RS_OP_RESERVED_203 = 0xcb,
+ RS_OP_RESERVED_204 = 0xcc,
+ RS_OP_RESERVED_205 = 0xcd,
+ RS_OP_RESERVED_206 = 0xce,
+ RS_OP_RESERVED_207 = 0xcf,
+ RS_OP_RESERVED_208 = 0xd0,
+ RS_OP_RESERVED_209 = 0xd1,
+ RS_OP_RESERVED_210 = 0xd2,
+ RS_OP_RESERVED_211 = 0xd3,
+ RS_OP_RESERVED_212 = 0xd4,
+ RS_OP_RESERVED_213 = 0xd5,
+ RS_OP_RESERVED_214 = 0xd6,
+ RS_OP_RESERVED_215 = 0xd7,
+ RS_OP_RESERVED_216 = 0xd8,
+ RS_OP_RESERVED_217 = 0xd9,
+ RS_OP_RESERVED_218 = 0xda,
+ RS_OP_RESERVED_219 = 0xdb,
+ RS_OP_RESERVED_220 = 0xdc,
+ RS_OP_RESERVED_221 = 0xdd,
+ RS_OP_RESERVED_222 = 0xde,
+ RS_OP_RESERVED_223 = 0xdf,
+ RS_OP_RESERVED_224 = 0xe0,
+ RS_OP_RESERVED_225 = 0xe1,
+ RS_OP_RESERVED_226 = 0xe2,
+ RS_OP_RESERVED_227 = 0xe3,
+ RS_OP_RESERVED_228 = 0xe4,
+ RS_OP_RESERVED_229 = 0xe5,
+ RS_OP_RESERVED_230 = 0xe6,
+ RS_OP_RESERVED_231 = 0xe7,
+ RS_OP_RESERVED_232 = 0xe8,
+ RS_OP_RESERVED_233 = 0xe9,
+ RS_OP_RESERVED_234 = 0xea,
+ RS_OP_RESERVED_235 = 0xeb,
+ RS_OP_RESERVED_236 = 0xec,
+ RS_OP_RESERVED_237 = 0xed,
+ RS_OP_RESERVED_238 = 0xee,
+ RS_OP_RESERVED_239 = 0xef,
+ RS_OP_RESERVED_240 = 0xf0,
+ RS_OP_RESERVED_241 = 0xf1,
+ RS_OP_RESERVED_242 = 0xf2,
+ RS_OP_RESERVED_243 = 0xf3,
+ RS_OP_RESERVED_244 = 0xf4,
+ RS_OP_RESERVED_245 = 0xf5,
+ RS_OP_RESERVED_246 = 0xf6,
+ RS_OP_RESERVED_247 = 0xf7,
+ RS_OP_RESERVED_248 = 0xf8,
+ RS_OP_RESERVED_249 = 0xf9,
+ RS_OP_RESERVED_250 = 0xfa,
+ RS_OP_RESERVED_251 = 0xfb,
+ RS_OP_RESERVED_252 = 0xfc,
+ RS_OP_RESERVED_253 = 0xfd,
+ RS_OP_RESERVED_254 = 0xfe,
+ RS_OP_RESERVED_255 = 0xff
+};
diff --git a/src/rabinkarp.c b/src/rabinkarp.c
new file mode 100644
index 0000000..085b549
--- /dev/null
+++ b/src/rabinkarp.c
@@ -0,0 +1,104 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * rabinkarp -- The RabinKarp rolling checksum.
+ *
+ * Copyright (C) 2019 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "rabinkarp.h"
+
+/* Constant for RABINKARP_MULT^2. */
+#define RABINKARP_MULT2 0xa5b71959U
+
+/* Macros for doing 16 bytes with 2 mults that can be done in parallel. Testing
+ showed this as a performance sweet spot vs 16x1, 8x2, 4x4 1x16 alternative
+ arrangements. */
+#define PAR2X1(hash,buf,i) (RABINKARP_MULT2*(hash) + \
+ RABINKARP_MULT*buf[i] + \
+ buf[i+1])
+#define PAR2X2(hash,buf,i) PAR2X1(PAR2X1(hash,buf,i),buf,i+2)
+#define PAR2X4(hash,buf,i) PAR2X2(PAR2X2(hash,buf,i),buf,i+4)
+#define PAR2X8(hash,buf) PAR2X4(PAR2X4(hash,buf,0),buf,8)
+
+/* Table of RABINKARP_MULT^(2^(i+1)) for power lookups. */
+const static uint32_t RABINKARP_MULT_POW2[32] = {
+ 0x08104225U,
+ 0xa5b71959U,
+ 0xf9c080f1U,
+ 0x7c71e2e1U,
+ 0x0bb409c1U,
+ 0x4dc72381U,
+ 0xd17a8701U,
+ 0x96260e01U,
+ 0x55101c01U,
+ 0x2d303801U,
+ 0x66a07001U,
+ 0xfe40e001U,
+ 0xc081c001U,
+ 0x91038001U,
+ 0x62070001U,
+ 0xc40e0001U,
+ 0x881c0001U,
+ 0x10380001U,
+ 0x20700001U,
+ 0x40e00001U,
+ 0x81c00001U,
+ 0x03800001U,
+ 0x07000001U,
+ 0x0e000001U,
+ 0x1c000001U,
+ 0x38000001U,
+ 0x70000001U,
+ 0xe0000001U,
+ 0xc0000001U,
+ 0x80000001U,
+ 0x00000001U,
+ 0x00000001U
+};
+
+/* Get the value of RABINKARP_MULT^n. */
+static inline uint32_t rabinkarp_pow(uint32_t n)
+{
+ const uint32_t *m = RABINKARP_MULT_POW2;
+ uint32_t ans = 1;
+ while (n) {
+ if (n & 1) {
+ ans *= *m;
+ }
+ m++;
+ n >>= 1;
+ }
+ return ans;
+}
+
+void rabinkarp_update(rabinkarp_t *sum, const unsigned char *buf, size_t len)
+{
+ size_t n = len;
+ uint32_t hash = sum->hash;
+
+ while (n >= 16) {
+ hash = PAR2X8(hash, buf);
+ buf += 16;
+ n -= 16;
+ }
+ while (n) {
+ hash = RABINKARP_MULT * hash + *buf++;
+ n--;
+ }
+ sum->hash = hash;
+ sum->count += len;
+ sum->mult *= rabinkarp_pow((uint32_t)len);
+}
diff --git a/src/rabinkarp.h b/src/rabinkarp.h
new file mode 100644
index 0000000..76e6447
--- /dev/null
+++ b/src/rabinkarp.h
@@ -0,0 +1,94 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * rabinkarp -- The RabinKarp rolling checksum.
+ *
+ * Copyright (C) 2019 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _RABINKARP_H_
+# define _RABINKARP_H_
+
+# include <stddef.h>
+# include <stdint.h>
+
+/** The RabinKarp seed value.
+ *
+ * The seed ensures different length zero blocks have different hashes. It
+ * effectively encodes the length into the hash. */
+# define RABINKARP_SEED 1
+
+/** The RabinKarp multiplier.
+ *
+ * This multiplier has a bit pattern of 1's getting sparser with significance,
+ * is the product of 2 large primes, and matches the characterstics for a good
+ * LCG multiplier. */
+# define RABINKARP_MULT 0x08104225U
+
+/** The RabinKarp inverse multiplier.
+ *
+ * This is the inverse of RABINKARP_MULT modular 2^32. Multiplying by this is
+ * equivalent to dividing by RABINKARP_MULT. */
+# define RABINKARP_INVM 0x98f009adU
+
+/** The RabinKarp seed adjustment.
+ *
+ * This is a factor used to adjust for the seed when rolling out values. It's
+ * equal to; (RABINKARP_MULT - 1) * RABINKARP_SEED */
+# define RABINKARP_ADJ 0x08104224U
+
+/** The rabinkarp_t state type. */
+typedef struct _rabinkarp {
+ size_t count; /**< Count of bytes included in sum. */
+ uint32_t hash; /**< The accumulated hash value. */
+ uint32_t mult; /**< The value of RABINKARP_MULT^count. */
+} rabinkarp_t;
+
+static inline void rabinkarp_init(rabinkarp_t *sum)
+{
+ sum->count = 0;
+ sum->hash = RABINKARP_SEED;
+ sum->mult = 1;
+}
+
+void rabinkarp_update(rabinkarp_t *sum, const unsigned char *buf, size_t len);
+
+static inline void rabinkarp_rotate(rabinkarp_t *sum, unsigned char out,
+ unsigned char in)
+{
+ sum->hash =
+ sum->hash * RABINKARP_MULT + in - sum->mult * (out + RABINKARP_ADJ);
+}
+
+static inline void rabinkarp_rollin(rabinkarp_t *sum, unsigned char in)
+{
+ sum->hash = sum->hash * RABINKARP_MULT + in;
+ sum->count++;
+ sum->mult *= RABINKARP_MULT;
+}
+
+static inline void rabinkarp_rollout(rabinkarp_t *sum, unsigned char out)
+{
+ sum->count--;
+ sum->mult *= RABINKARP_INVM;
+ sum->hash -= sum->mult * (out + RABINKARP_ADJ);
+}
+
+static inline uint32_t rabinkarp_digest(rabinkarp_t *sum)
+{
+ return sum->hash;
+}
+
+#endif /* _RABINKARP_H_ */
diff --git a/src/rdiff.c b/src/rdiff.c
new file mode 100644
index 0000000..d3ea32d
--- /dev/null
+++ b/src/rdiff.c
@@ -0,0 +1,366 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 1999, 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | .. after a year and a day, mourning is
+ | dangerous to the survivor and troublesome
+ | to the dead.
+ | -- Harold Bloom
+ */
+
+/** \file rdiff.c
+ * Command-line network-delta tool.
+ *
+ * \todo Add a -z option to gzip/gunzip patches. This would be somewhat useful,
+ * but more importantly a good test of the streaming API. Also add -I for
+ * bzip2.
+ *
+ * \todo If built with debug support and we have mcheck, then turn it on.
+ * (Optionally?)
+ *
+ * \todo popt doesn't handle single dashes very well at the moment: we'd like
+ * to use them as arguments to indicate stdin/stdout, but it turns them into
+ * options. I sent a patch to the popt maintainers; hopefully it will be fixed
+ * in the future.
+ *
+ * \todo Add an option for delta to check whether the files are identical. */
+
+#include "config.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <popt.h>
+#include "librsync.h"
+#include "isprefix.h"
+
+static int block_len = 0;
+static int strong_len = 0;
+
+static int show_stats = 0;
+
+static int bzip2_level = 0;
+static int gzip_level = 0;
+static int file_force = 0;
+
+enum {
+ OPT_GZIP = 1069, OPT_BZIP2
+};
+
+char *rs_hash_name;
+char *rs_rollsum_name;
+
+static void rdiff_usage(const char *error, ...)
+{
+ va_list va;
+ char buf[256];
+
+ va_start(va, error);
+ vsnprintf(buf, sizeof(buf), error, va);
+ va_end(va);
+ fprintf(stderr, "rdiff: %s\n\nTry `rdiff --help' for more information.\n",
+ buf);
+}
+
+static void rdiff_no_more_args(poptContext opcon)
+{
+ if (poptGetArg(opcon)) {
+ rdiff_usage("Too many arguments.");
+ exit(RS_SYNTAX_ERROR);
+ }
+}
+
+static void bad_option(poptContext opcon, int error)
+{
+ rdiff_usage("%s: %s", poptStrerror(error), poptBadOption(opcon, 0));
+ exit(RS_SYNTAX_ERROR);
+}
+
+static void help(void)
+{
+ printf("Usage: rdiff [OPTIONS] signature [BASIS [SIGNATURE]]\n"
+ " [OPTIONS] delta SIGNATURE [NEWFILE [DELTA]]\n"
+ " [OPTIONS] patch BASIS [DELTA [NEWFILE]]\n" "\n"
+ "Options:\n"
+ " -v, --verbose Trace internal processing\n"
+ " -V, --version Show program version\n"
+ " -?, --help Show this help message\n"
+ " -s, --statistics Show performance statistics\n"
+ " -f, --force Force overwriting existing files\n"
+ "Signature generation options:\n"
+ " -H, --hash=ALG Hash algorithm: blake2 (default), md4\n"
+ " -R, --rollsum=ALG Rollsum algorithm: rabinkarp (default), rollsum\n"
+ "Delta-encoding options:\n"
+ " -b, --block-size=BYTES Signature block size, 0 (default) for recommended\n"
+ " -S, --sum-size=BYTES Signature strength, 0 (default) for max, -1 for min\n"
+ "IO options:\n" " -I, --input-size=BYTES Input buffer size\n"
+ " -O, --output-size=BYTES Output buffer size\n"
+ " -z, --gzip[=LEVEL] gzip-compress deltas\n"
+ " -i, --bzip2[=LEVEL] bzip2-compress deltas\n");
+}
+
+static void rdiff_show_version(void)
+{
+ char const *bzlib = "", *zlib = "", *trace = "";
+
+#if 0
+ /* Compression isn't implemented so don't mention it. */
+# ifdef HAVE_LIBZ
+ zlib = ", gzip";
+# endif
+
+# ifdef HAVE_LIBBZ2
+ bzlib = ", bzip2";
+# endif
+#endif
+
+#ifndef DO_RS_TRACE
+ trace = ", trace disabled";
+#endif
+
+ printf("rdiff (%s)\n"
+ "Copyright (C) 1997-2016 by Martin Pool, Andrew Tridgell and others.\n"
+ "http://librsync.sourcefrog.net/\n"
+ "Capabilities: %ld bit files%s%s%s\n" "\n"
+ "librsync comes with NO WARRANTY, to the extent permitted by law.\n"
+ "You may redistribute copies of librsync under the terms of the GNU\n"
+ "Lesser General Public License. For more information about these\n"
+ "matters, see the files named COPYING.\n", rs_librsync_version,
+ (long)(8 * sizeof(rs_long_t)), zlib, bzlib, trace);
+}
+
+static void rdiff_options(poptContext opcon)
+{
+ int c;
+ char const *a;
+
+ while ((c = poptGetNextOpt(opcon)) != -1) {
+ switch (c) {
+ case 'h':
+ help();
+ exit(RS_DONE);
+ case 'V':
+ rdiff_show_version();
+ exit(RS_DONE);
+ case 'v':
+ if (!rs_supports_trace()) {
+ fprintf(stderr, "rdiff: Library does not support trace.\n");
+ }
+ rs_trace_set_level(RS_LOG_DEBUG);
+ break;
+
+ case OPT_GZIP:
+ case OPT_BZIP2:
+ if ((a = poptGetOptArg(opcon))) {
+ int l = atoi(a);
+ if (c == OPT_GZIP)
+ gzip_level = l;
+ else
+ bzip2_level = l;
+ } else {
+ if (c == OPT_GZIP)
+ gzip_level = -1; /* library default */
+ else
+ bzip2_level = 9; /* demand the best */
+ }
+ rdiff_usage("Sorry, compression is not implemented yet.");
+ exit(RS_UNIMPLEMENTED);
+
+ default:
+ bad_option(opcon, c);
+ }
+ }
+}
+
+/** Generate signature from remaining command line arguments. */
+static rs_result rdiff_sig(poptContext opcon)
+{
+ FILE *basis_file, *sig_file;
+ rs_stats_t stats;
+ rs_result result;
+ rs_magic_number sig_magic;
+
+ basis_file = rs_file_open(poptGetArg(opcon), "rb", file_force);
+ sig_file = rs_file_open(poptGetArg(opcon), "wb", file_force);
+
+ rdiff_no_more_args(opcon);
+
+ if (!rs_hash_name || !strcmp(rs_hash_name, "blake2")) {
+ sig_magic = RS_BLAKE2_SIG_MAGIC;
+ } else if (!strcmp(rs_hash_name, "md4")) {
+ sig_magic = RS_MD4_SIG_MAGIC;
+ } else {
+ rdiff_usage("Unknown hash algorithm '%s'.", rs_hash_name);
+ exit(RS_SYNTAX_ERROR);
+ }
+ if (!rs_rollsum_name || !strcmp(rs_rollsum_name, "rabinkarp")) {
+ /* The RabinKarp magics are 0x10 greater than the rollsum magics. */
+ sig_magic += 0x10;
+ } else if (strcmp(rs_rollsum_name, "rollsum")) {
+ rdiff_usage("Unknown rollsum algorithm '%s'.", rs_rollsum_name);
+ exit(RS_SYNTAX_ERROR);
+ }
+
+ result =
+ rs_sig_file(basis_file, sig_file, block_len, strong_len, sig_magic,
+ &stats);
+
+ rs_file_close(sig_file);
+ rs_file_close(basis_file);
+ if (result != RS_DONE)
+ return result;
+
+ if (show_stats)
+ rs_log_stats(&stats);
+
+ return result;
+}
+
+static rs_result rdiff_delta(poptContext opcon)
+{
+ FILE *sig_file, *new_file, *delta_file;
+ char const *sig_name;
+ rs_result result;
+ rs_signature_t *sumset;
+ rs_stats_t stats;
+
+ if (!(sig_name = poptGetArg(opcon))) {
+ rdiff_usage("Usage for delta: "
+ "rdiff [OPTIONS] delta SIGNATURE [NEWFILE [DELTA]]");
+ exit(RS_SYNTAX_ERROR);
+ }
+
+ sig_file = rs_file_open(sig_name, "rb", file_force);
+ new_file = rs_file_open(poptGetArg(opcon), "rb", file_force);
+ delta_file = rs_file_open(poptGetArg(opcon), "wb", file_force);
+
+ rdiff_no_more_args(opcon);
+
+ result = rs_loadsig_file(sig_file, &sumset, &stats);
+ if (result != RS_DONE)
+ return result;
+
+ if (show_stats)
+ rs_log_stats(&stats);
+
+ if ((result = rs_build_hash_table(sumset)) != RS_DONE)
+ return result;
+
+ result = rs_delta_file(sumset, new_file, delta_file, &stats);
+
+ rs_file_close(delta_file);
+ rs_file_close(new_file);
+ rs_file_close(sig_file);
+
+ if (show_stats) {
+ rs_signature_log_stats(sumset);
+ rs_log_stats(&stats);
+ }
+
+ rs_free_sumset(sumset);
+
+ return result;
+}
+
+static rs_result rdiff_patch(poptContext opcon)
+{
+ /* patch BASIS [DELTA [NEWFILE]] */
+ FILE *basis_file, *delta_file, *new_file;
+ char const *basis_name;
+ rs_stats_t stats;
+ rs_result result;
+
+ if (!(basis_name = poptGetArg(opcon))) {
+ rdiff_usage("Usage for patch: "
+ "rdiff [OPTIONS] patch BASIS [DELTA [NEW]]");
+ exit(RS_SYNTAX_ERROR);
+ }
+
+ basis_file = rs_file_open(basis_name, "rb", file_force);
+ delta_file = rs_file_open(poptGetArg(opcon), "rb", file_force);
+ new_file = rs_file_open(poptGetArg(opcon), "wb", file_force);
+
+ rdiff_no_more_args(opcon);
+
+ result = rs_patch_file(basis_file, delta_file, new_file, &stats);
+
+ rs_file_close(new_file);
+ rs_file_close(delta_file);
+ rs_file_close(basis_file);
+
+ if (show_stats)
+ rs_log_stats(&stats);
+
+ return result;
+}
+
+static rs_result rdiff_action(poptContext opcon)
+{
+ const char *action;
+
+ action = poptGetArg(opcon);
+ if (!action) ;
+ else if (isprefix(action, "signature"))
+ return rdiff_sig(opcon);
+ else if (isprefix(action, "delta"))
+ return rdiff_delta(opcon);
+ else if (isprefix(action, "patch"))
+ return rdiff_patch(opcon);
+
+ rdiff_usage
+ ("You must specify an action: `signature', `delta', or `patch'.");
+ exit(RS_SYNTAX_ERROR);
+}
+
+int main(const int argc, const char *argv[])
+{
+ /* Initialize opts at runtime to avoid unknown address values. */
+ const struct poptOption opts[] = {
+ {"verbose", 'v', POPT_ARG_NONE, 0, 'v'},
+ {"version", 'V', POPT_ARG_NONE, 0, 'V'},
+ {"input-size", 'I', POPT_ARG_INT, &rs_inbuflen},
+ {"output-size", 'O', POPT_ARG_INT, &rs_outbuflen},
+ {"hash", 'H', POPT_ARG_STRING, &rs_hash_name},
+ {"rollsum", 'R', POPT_ARG_STRING, &rs_rollsum_name},
+ {"help", '?', POPT_ARG_NONE, 0, 'h'},
+ {0, 'h', POPT_ARG_NONE, 0, 'h'},
+ {"block-size", 'b', POPT_ARG_INT, &block_len},
+ {"sum-size", 'S', POPT_ARG_INT, &strong_len},
+ {"statistics", 's', POPT_ARG_NONE, &show_stats},
+ {"stats", 0, POPT_ARG_NONE, &show_stats},
+ {"gzip", 'z', POPT_ARG_NONE, 0, OPT_GZIP},
+ {"bzip2", 'i', POPT_ARG_NONE, 0, OPT_BZIP2},
+ {"force", 'f', POPT_ARG_NONE, &file_force},
+ {0}
+ };
+
+ poptContext opcon;
+ rs_result result;
+
+ opcon = poptGetContext("rdiff", argc, argv, opts, 0);
+ rdiff_options(opcon);
+ result = rdiff_action(opcon);
+
+ if (result != RS_DONE)
+ fprintf(stderr, "rdiff: Failed, %s.\n", rs_strerror(result));
+
+ poptFreeContext(opcon);
+ return result;
+}
diff --git a/src/rdiff.magic b/src/rdiff.magic
new file mode 100644
index 0000000..8a9ada6
--- /dev/null
+++ b/src/rdiff.magic
@@ -0,0 +1,25 @@
+# Supplementary magic data for the file(1) command to support
+# rdiff(1). The format is described in magic(5).
+#
+# librsync -- the library for network deltas
+#
+# Copyright 2001, 2014 by Martin Pool. You may do whatever you want with
+# this file.
+
+0 belong 0x72730236 rdiff network-delta data
+
+0 belong 0x72730136 rdiff network-delta signature data (Rollsum, MD4,
+>4 belong x block length=%d,
+>8 belong x signature strength=%d)
+
+0 belong 0x72730137 rdiff network-delta signature data (Rollsum, BLAKE2,
+>4 belong x block length=%d,
+>8 belong x signature strength=%d)
+
+0 belong 0x72730146 rdiff network-delta signature data (RabinKarp, MD4,
+>4 belong x block length=%d,
+>8 belong x signature strength=%d)
+
+0 belong 0x72730147 rdiff network-delta signature data (RabinKarp, BLAKE2,
+>4 belong x block length=%d,
+>8 belong x signature strength=%d)
diff --git a/src/readsums.c b/src/readsums.c
new file mode 100644
index 0000000..18d8190
--- /dev/null
+++ b/src/readsums.c
@@ -0,0 +1,144 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 1999, 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 1999 by Andrew Tridgell <tridge@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** \file readsums.c
+ * Load signatures from a file. */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include "librsync.h"
+#include "job.h"
+#include "sumset.h"
+#include "stream.h"
+#include "netint.h"
+#include "trace.h"
+#include "util.h"
+
+static rs_result rs_loadsig_s_weak(rs_job_t *job);
+static rs_result rs_loadsig_s_strong(rs_job_t *job);
+
+/** Add a just-read-in checksum pair to the signature block. */
+static rs_result rs_loadsig_add_sum(rs_job_t *job, rs_strong_sum_t *strong)
+{
+ rs_signature_t *sig = job->signature;
+
+ if (rs_trace_enabled()) {
+ char hexbuf[RS_MAX_STRONG_SUM_LENGTH * 2 + 2];
+ rs_hexify(hexbuf, strong, sig->strong_sum_len);
+ rs_trace("got block: weak=" FMT_WEAKSUM ", strong=%s", job->weak_sig,
+ hexbuf);
+ }
+ rs_signature_add_block(job->signature, job->weak_sig, strong);
+ job->stats.sig_blocks++;
+ return RS_RUNNING;
+}
+
+static rs_result rs_loadsig_s_weak(rs_job_t *job)
+{
+ int l;
+ rs_result result;
+
+ if ((result = rs_suck_n4(job, &l)) != RS_DONE) {
+ if (result == RS_INPUT_ENDED) /* ending here is OK */
+ return RS_DONE;
+ return result;
+ }
+ job->weak_sig = l;
+ job->statefn = rs_loadsig_s_strong;
+ return RS_RUNNING;
+}
+
+static rs_result rs_loadsig_s_strong(rs_job_t *job)
+{
+ rs_result result;
+ rs_strong_sum_t *strongsum;
+
+ if ((result =
+ rs_scoop_read(job, job->signature->strong_sum_len,
+ (void **)&strongsum)) != RS_DONE)
+ return result;
+ job->statefn = rs_loadsig_s_weak;
+ return rs_loadsig_add_sum(job, strongsum);
+}
+
+static rs_result rs_loadsig_s_stronglen(rs_job_t *job)
+{
+ int l;
+ rs_result result;
+
+ if ((result = rs_suck_n4(job, &l)) != RS_DONE)
+ return result;
+ if (l < 0 || l > RS_MAX_STRONG_SUM_LENGTH) {
+ rs_error("strong sum length %d is implausible", l);
+ return RS_CORRUPT;
+ }
+ rs_trace("got strong sum length %d", l);
+ job->sig_strong_len = l;
+ /* Initialize the signature. */
+ if ((result =
+ rs_signature_init(job->signature, job->sig_magic, job->sig_block_len,
+ job->sig_strong_len, job->sig_fsize)) != RS_DONE)
+ return result;
+ job->statefn = rs_loadsig_s_weak;
+ return RS_RUNNING;
+}
+
+static rs_result rs_loadsig_s_blocklen(rs_job_t *job)
+{
+ int l;
+ rs_result result;
+
+ if ((result = rs_suck_n4(job, &l)) != RS_DONE)
+ return result;
+ if (l < 1) {
+ rs_error("block length of %d is bogus", l);
+ return RS_CORRUPT;
+ }
+ rs_trace("got block length %d", l);
+ job->sig_block_len = l;
+ job->stats.block_len = l;
+ job->statefn = rs_loadsig_s_stronglen;
+ return RS_RUNNING;
+}
+
+static rs_result rs_loadsig_s_magic(rs_job_t *job)
+{
+ int l;
+ rs_result result;
+
+ if ((result = rs_suck_n4(job, &l)) != RS_DONE)
+ return result;
+ rs_trace("got signature magic %#x", l);
+ job->sig_magic = l;
+ job->statefn = rs_loadsig_s_blocklen;
+ return RS_RUNNING;
+}
+
+rs_job_t *rs_loadsig_begin(rs_signature_t **signature)
+{
+ rs_job_t *job;
+
+ job = rs_job_new("loadsig", rs_loadsig_s_magic);
+ *signature = job->signature = rs_alloc_struct(rs_signature_t);
+ return job;
+}
diff --git a/src/rollsum.c b/src/rollsum.c
new file mode 100644
index 0000000..03d450e
--- /dev/null
+++ b/src/rollsum.c
@@ -0,0 +1,54 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * rollsum -- the librsync rolling checksum
+ *
+ * Copyright (C) 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ * based on work, Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "rollsum.h"
+
+#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+void RollsumUpdate(Rollsum *sum, const unsigned char *buf, size_t len)
+{
+ /* ANSI C says no overflow for unsigned. zlib's adler32 goes to extra
+ effort to avoid overflow for its mod prime, which we don't have. */
+ size_t n = len;
+ uint_fast16_t s1 = sum->s1;
+ uint_fast16_t s2 = sum->s2;
+
+ while (n >= 16) {
+ DO16(buf);
+ buf += 16;
+ n -= 16;
+ }
+ while (n != 0) {
+ s1 += *buf++;
+ s2 += s1;
+ n--;
+ }
+ /* Increment s1 and s2 by the amounts added by the char offset. */
+ s1 += len * ROLLSUM_CHAR_OFFSET;
+ s2 += ((len * (len + 1)) / 2) * ROLLSUM_CHAR_OFFSET;
+ sum->count += len; /* Increment sum count. */
+ sum->s1 = s1;
+ sum->s2 = s2;
+}
diff --git a/src/rollsum.h b/src/rollsum.h
new file mode 100644
index 0000000..218e7a8
--- /dev/null
+++ b/src/rollsum.h
@@ -0,0 +1,74 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * rollsum -- the librsync rolling checksum
+ *
+ * Copyright (C) 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ * based on work, Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _ROLLSUM_H_
+# define _ROLLSUM_H_
+
+# include <stddef.h>
+# include <stdint.h>
+
+/* We should make this something other than zero to improve the checksum
+ algorithm: tridge suggests a prime number. */
+# define ROLLSUM_CHAR_OFFSET 31
+
+/** The Rollsum struct type \private. */
+typedef struct _Rollsum {
+ size_t count; /* count of bytes included in sum */
+ uint_fast16_t s1; /* s1 part of sum */
+ uint_fast16_t s2; /* s2 part of sum */
+} Rollsum;
+
+void RollsumUpdate(Rollsum *sum, const unsigned char *buf, size_t len);
+
+/* static inline implementations of simple routines */
+
+static inline void RollsumInit(Rollsum *sum)
+{
+ sum->count = sum->s1 = sum->s2 = 0;
+}
+
+static inline void RollsumRotate(Rollsum *sum, unsigned char out,
+ unsigned char in)
+{
+ sum->s1 += in - out;
+ sum->s2 += sum->s1 - sum->count * (out + ROLLSUM_CHAR_OFFSET);
+}
+
+static inline void RollsumRollin(Rollsum *sum, unsigned char in)
+{
+ sum->s1 += in + ROLLSUM_CHAR_OFFSET;
+ sum->s2 += sum->s1;
+ sum->count++;
+}
+
+static inline void RollsumRollout(Rollsum *sum, unsigned char out)
+{
+ sum->s1 -= out + ROLLSUM_CHAR_OFFSET;
+ sum->s2 -= sum->count * (out + ROLLSUM_CHAR_OFFSET);
+ sum->count--;
+}
+
+static inline uint32_t RollsumDigest(Rollsum *sum)
+{
+ return ((uint32_t)sum->s2 << 16) | ((uint32_t)sum->s1 & 0xffff);
+}
+
+#endif /* _ROLLSUM_H_ */
diff --git a/src/scoop.c b/src/scoop.c
new file mode 100644
index 0000000..19c5b74
--- /dev/null
+++ b/src/scoop.c
@@ -0,0 +1,230 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | To walk on water you've gotta sink
+ | in the ice.
+ | -- Shihad, `The General Electric'.
+ */
+
+/** \file scoop.c
+ * This file deals with readahead from caller-supplied buffers.
+ *
+ * Many functions require a certain minimum amount of input to do their
+ * processing. For example, to calculate a strong checksum of a block we need
+ * at least a block of input.
+ *
+ * Since we put the buffers completely under the control of the caller, we
+ * can't count on ever getting this much data all in one go. We can't simply
+ * wait, because the caller might have a smaller buffer than we require and so
+ * we'll never get it. For the same reason we must always accept all the data
+ * we're given.
+ *
+ * So, stream input data that's required for readahead is put into a special
+ * buffer, from which the caller can then read. It's essentially like an
+ * internal pipe, which on any given read request may or may not be able to
+ * actually supply the data.
+ *
+ * As a future optimization, we might try to take data directly from the input
+ * buffer if there's already enough there.
+ *
+ * \todo We probably know a maximum amount of data that can be scooped up, so
+ * we could just avoid dynamic allocation. However that can't be fixed at
+ * compile time, because when generating a delta it needs to be large enough to
+ * hold one full block. Perhaps we can set it up when the job is allocated? It
+ * would be kind of nice to not do any memory allocation after startup, as
+ * bzlib does this. */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "librsync.h"
+#include "job.h"
+#include "stream.h"
+#include "trace.h"
+#include "util.h"
+
+/** Try to accept a from the input buffer to get LEN bytes in the scoop. */
+void rs_scoop_input(rs_job_t *job, size_t len)
+{
+ rs_buffers_t *stream = job->stream;
+ size_t tocopy;
+
+ assert(len > job->scoop_avail);
+
+ if (job->scoop_alloc < len) {
+ /* Need to allocate a larger scoop. */
+ rs_byte_t *newbuf;
+ size_t newsize;
+ for (newsize = 64; newsize < len; newsize <<= 1) ;
+ newbuf = rs_alloc(newsize, "scoop buffer");
+ if (job->scoop_avail)
+ memcpy(newbuf, job->scoop_next, job->scoop_avail);
+ if (job->scoop_buf)
+ free(job->scoop_buf);
+ job->scoop_buf = job->scoop_next = newbuf;
+ rs_trace("resized scoop buffer to " FMT_SIZE " bytes from " FMT_SIZE "",
+ newsize, job->scoop_alloc);
+ job->scoop_alloc = newsize;
+ } else if (job->scoop_buf != job->scoop_next) {
+ /* Move existing data to the front of the scoop. */
+ rs_trace("moving scoop " FMT_SIZE " bytes to reuse " FMT_SIZE " bytes",
+ job->scoop_avail, (size_t)(job->scoop_next - job->scoop_buf));
+ memmove(job->scoop_buf, job->scoop_next, job->scoop_avail);
+ job->scoop_next = job->scoop_buf;
+ }
+ /* take as much input as is available, to give up to LEN bytes in the
+ scoop. */
+ tocopy = len - job->scoop_avail;
+ if (tocopy > stream->avail_in)
+ tocopy = stream->avail_in;
+ assert(tocopy + job->scoop_avail <= job->scoop_alloc);
+
+ memcpy(job->scoop_next + job->scoop_avail, stream->next_in, tocopy);
+ rs_trace("accepted " FMT_SIZE " bytes from input to scoop", tocopy);
+ job->scoop_avail += tocopy;
+ stream->next_in += tocopy;
+ stream->avail_in -= tocopy;
+}
+
+/** Advance the input cursor forward \p len bytes.
+ *
+ * This is used after doing readahead, when you decide you want to keep it. \p
+ * len must be no more than the amount of available data, so you can't cheat.
+ *
+ * So when creating a delta, we require one block of readahead. But after
+ * examining that block, we might decide to advance over all of it (if there is
+ * a match), or just one byte (if not). */
+void rs_scoop_advance(rs_job_t *job, size_t len)
+{
+ rs_buffers_t *stream = job->stream;
+
+ /* It never makes sense to advance over a mixture of bytes from the scoop
+ and input, because you couldn't possibly have looked at them all at the
+ same time. */
+ if (job->scoop_avail) {
+ /* reading from the scoop buffer */
+ rs_trace("advance over " FMT_SIZE " bytes from scoop", len);
+ assert(len <= job->scoop_avail);
+ job->scoop_avail -= len;
+ job->scoop_next += len;
+ } else {
+ rs_trace("advance over " FMT_SIZE " bytes from input buffer", len);
+ assert(len <= stream->avail_in);
+ stream->avail_in -= len;
+ stream->next_in += len;
+ }
+}
+
+/** Read from scoop without advancing.
+ *
+ * Ask for LEN bytes of input from the stream. If that much data is available,
+ * then return a pointer to it in PTR, advance the stream input pointer over
+ * the data, and return RS_DONE. If there's not enough data, then accept
+ * whatever is there into a buffer, advance over it, and return RS_BLOCKED.
+ *
+ * The data is not actually removed from the input, so this function lets you
+ * do readahead. If you want to keep any of the data, you should also call
+ * rs_scoop_advance() to skip over it. */
+rs_result rs_scoop_readahead(rs_job_t *job, size_t len, void **ptr)
+{
+ rs_buffers_t *stream = job->stream;
+ rs_job_check(job);
+
+ if (!job->scoop_avail && stream->avail_in >= len) {
+ /* The scoop is empty and there's enough data in the input. */
+ *ptr = stream->next_in;
+ rs_trace("got " FMT_SIZE " bytes direct from input", len);
+ return RS_DONE;
+ } else if (job->scoop_avail < len && stream->avail_in) {
+ /* There is not enough data in the scoop. */
+ rs_trace("scoop has less than " FMT_SIZE " bytes, scooping from "
+ FMT_SIZE " input bytes", len, stream->avail_in);
+ rs_scoop_input(job, len);
+ }
+ if (job->scoop_avail >= len) {
+ /* There is enough data in the scoop now. */
+ rs_trace("scoop has at least " FMT_SIZE " bytes, this is enough",
+ job->scoop_avail);
+ *ptr = job->scoop_next;
+ return RS_DONE;
+ } else if (stream->eof_in) {
+ /* Not enough input data and at EOF. */
+ rs_trace("reached end of input stream");
+ return RS_INPUT_ENDED;
+ } else {
+ /* Not enough input data yet. */
+ rs_trace("blocked with insufficient input data");
+ return RS_BLOCKED;
+ }
+}
+
+/** Read LEN bytes if possible, and remove them from the input scoop.
+ *
+ * \param *job An rs_job_t pointer to the job instance.
+ *
+ * \param len The length of the data in the ptr buffer.
+ *
+ * \param **ptr will be updated to point to a read-only buffer holding the
+ * data, if enough is available.
+ *
+ * \return RS_DONE if there was enough data, RS_BLOCKED if there was not enough
+ * data yet, or RS_INPUT_ENDED if there was not enough data and at EOF. */
+rs_result rs_scoop_read(rs_job_t *job, size_t len, void **ptr)
+{
+ rs_result result;
+
+ result = rs_scoop_readahead(job, len, ptr);
+ if (result == RS_DONE)
+ rs_scoop_advance(job, len);
+ return result;
+}
+
+/** Read whatever data remains in the input stream.
+ *
+ * \param *job The rs_job_t instance the job instance.
+ *
+ * \param *len will be updated to the length of the available data.
+ *
+ * \param **ptr will point at the available data.
+ *
+ * \return RS_DONE if there was data, RS_INPUT_ENDED if there was no data and
+ * at EOF, RS_BLOCKED if there was no data and not at EOF. */
+rs_result rs_scoop_read_rest(rs_job_t *job, size_t *len, void **ptr)
+{
+ rs_buffers_t *stream = job->stream;
+
+ *len = job->scoop_avail + stream->avail_in;
+ if (*len)
+ return rs_scoop_read(job, *len, ptr);
+ else if (stream->eof_in)
+ return RS_INPUT_ENDED;
+ else
+ return RS_BLOCKED;
+}
+
+/** Return the total number of bytes available including the scoop and input
+ * buffer. */
+size_t rs_scoop_total_avail(rs_job_t *job)
+{
+ return job->scoop_avail + job->stream->avail_in;
+}
diff --git a/src/stats.c b/src/stats.c
new file mode 100644
index 0000000..faacc59
--- /dev/null
+++ b/src/stats.c
@@ -0,0 +1,93 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** \file stats.c
+ * stats reporting functions.
+ *
+ * \todo Other things to show in statistics: number of input and output bytes,
+ * number of times we blocked waiting for input or output, number of blocks. */
+
+#include "config.h"
+#include <stdio.h>
+#include "librsync.h"
+#include "trace.h"
+
+int rs_log_stats(rs_stats_t const *stats)
+{
+ char buf[1000];
+
+ rs_format_stats(stats, buf, sizeof buf - 1);
+ rs_log(RS_LOG_INFO | RS_LOG_NONAME, "%s", buf);
+ return 0;
+}
+
+char *rs_format_stats(rs_stats_t const *stats, char *buf, size_t size)
+{
+ char const *op = stats->op;
+ int len, sec;
+ double mb_in, mb_out;
+
+ if (!op)
+ op = "noop";
+
+ len = snprintf(buf, size, "%s statistics: ", op);
+
+ if (stats->lit_cmds) {
+ len +=
+ snprintf(buf + len, size - (size_t)len,
+ "literal[%d cmds, " FMT_LONG " bytes, " FMT_LONG
+ " cmdbytes] ", stats->lit_cmds, stats->lit_bytes,
+ stats->lit_cmdbytes);
+ }
+
+ if (stats->sig_cmds) {
+ len +=
+ snprintf(buf + len, size - (size_t)len,
+ "in-place-signature[" FMT_LONG " cmds, " FMT_LONG
+ " bytes] ", stats->sig_cmds, stats->sig_bytes);
+ }
+
+ if (stats->copy_cmds || stats->false_matches) {
+ len +=
+ snprintf(buf + len, size - (size_t)len,
+ "copy[" FMT_LONG " cmds, " FMT_LONG " bytes, " FMT_LONG
+ " cmdbytes, %d false]", stats->copy_cmds,
+ stats->copy_bytes, stats->copy_cmdbytes,
+ stats->false_matches);
+ }
+
+ if (stats->sig_blocks) {
+ len +=
+ snprintf(buf + len, size - (size_t)len,
+ "signature[" FMT_LONG " blocks, " FMT_SIZE
+ " bytes per block]", stats->sig_blocks, stats->block_len);
+ }
+
+ sec = (int)(stats->end - stats->start);
+ if (sec == 0)
+ sec = 1; // avoid division by zero
+ mb_in = (double)stats->in_bytes / 1e6;
+ mb_out = (double)stats->out_bytes / 1e6;
+ len +=
+ snprintf(buf + len, size - (size_t)len,
+ " speed[%.1f MB (%.1f MB/s) in, %.1f MB (%.1f MB/s) out, %d sec]",
+ mb_in, mb_in / sec, mb_out, mb_out / sec, sec);
+
+ return buf;
+}
diff --git a/src/stream.h b/src/stream.h
new file mode 100644
index 0000000..61a75b9
--- /dev/null
+++ b/src/stream.h
@@ -0,0 +1,89 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- library for network deltas
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | Two wars in a lifetime bear hard on the little places.
+ | In winter when storms come rushing out of the dark,
+ | And the bay boils like a cauldron of sharks,
+ | The old remember the trenches at Paschendale
+ | And sons who died on the Burma Railway.
+ */
+
+/** \file stream.h
+ * Manage librsync streams of IO.
+ *
+ * See \sa scoop.c and \sa tube.c for related code for input and output
+ * respectively.
+ *
+ * OK, so I'll admit IO here is a little complex. The most important player
+ * here is the stream, which is an object for managing filter operations. It
+ * has both input and output sides, both of which is just a (pointer,len) pair
+ * into a buffer provided by the client. The code controlling the stream
+ * handles however much data it wants, and the client provides or accepts
+ * however much is convenient.
+ *
+ * At the same time as being friendly to the client, we also try to be very
+ * friendly to the internal code. It wants to be able to ask for arbitrary
+ * amounts of input or output and get it without having to keep track of
+ * partial completion. So there are functions which either complete, or queue
+ * whatever was not sent and return RS_BLOCKED.
+ *
+ * The output buffer is a little more clever than simply a data buffer. Instead
+ * it knows that we can send either literal data, or data copied through from
+ * the input of the stream.
+ *
+ * In buf.c you will find functions that then map buffers onto stdio files.
+ *
+ * So on return from an encoding function, either the input or the output or
+ * possibly both will have no more bytes available.
+ *
+ * librsync never does IO or memory allocation, but relies on the caller. This
+ * is very nice for integration, but means that we have to be fairly flexible
+ * as to when we can `read' or `write' stuff internally.
+ *
+ * librsync basically does two types of IO. It reads network integers of
+ * various lengths which encode command and control information such as
+ * versions and signatures. It also does bulk data transfer.
+ *
+ * IO of network integers is internally buffered, because higher levels of the
+ * code need to see them transmitted atomically: it's no good to read half of a
+ * uint32. So there is a small and fixed length internal buffer which
+ * accumulates these. Unlike previous versions of the library, we don't require
+ * that the caller hold the start until the whole thing has arrived, which
+ * guarantees that we can always make progress.
+ *
+ * On each call into a stream iterator, it should begin by trying to flush
+ * output. This may well use up all the remaining stream space, in which case
+ * nothing else can be done. */
+
+size_t rs_buffers_copy(rs_buffers_t *stream, size_t len);
+
+rs_result rs_tube_catchup(rs_job_t *job);
+int rs_tube_is_idle(rs_job_t const *job);
+void rs_tube_write(rs_job_t *job, void const *buf, size_t len);
+void rs_tube_copy(rs_job_t *job, size_t len);
+
+void rs_scoop_input(rs_job_t *job, size_t len);
+void rs_scoop_advance(rs_job_t *job, size_t len);
+rs_result rs_scoop_readahead(rs_job_t *job, size_t len, void **ptr);
+rs_result rs_scoop_read(rs_job_t *job, size_t len, void **ptr);
+rs_result rs_scoop_read_rest(rs_job_t *job, size_t *len, void **ptr);
+size_t rs_scoop_total_avail(rs_job_t *job);
diff --git a/src/sumset.c b/src/sumset.c
new file mode 100644
index 0000000..8860762
--- /dev/null
+++ b/src/sumset.c
@@ -0,0 +1,318 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- library for network deltas
+ *
+ * Copyright (C) 1999, 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 1999 by Andrew Tridgell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "librsync.h"
+#include "sumset.h"
+#include "trace.h"
+#include "util.h"
+
+static void rs_block_sig_init(rs_block_sig_t *sig, rs_weak_sum_t weak_sum,
+ rs_strong_sum_t *strong_sum, int strong_len)
+{
+ sig->weak_sum = weak_sum;
+ if (strong_sum)
+ memcpy(sig->strong_sum, strong_sum, (size_t)strong_len);
+}
+
+static inline unsigned rs_block_sig_hash(const rs_block_sig_t *sig)
+{
+ return (unsigned)sig->weak_sum;
+}
+
+typedef struct rs_block_match {
+ rs_block_sig_t block_sig;
+ rs_signature_t *signature;
+ const void *buf;
+ size_t len;
+} rs_block_match_t;
+
+static void rs_block_match_init(rs_block_match_t *match, rs_signature_t *sig,
+ rs_weak_sum_t weak_sum,
+ rs_strong_sum_t *strong_sum, const void *buf,
+ size_t len)
+{
+ rs_block_sig_init(&match->block_sig, weak_sum, strong_sum,
+ sig->strong_sum_len);
+ match->signature = sig;
+ match->buf = buf;
+ match->len = len;
+}
+
+static inline int rs_block_match_cmp(rs_block_match_t *match,
+ const rs_block_sig_t *block_sig)
+{
+ /* If buf is not NULL, the strong sum is yet to be calculated. */
+ if (match->buf) {
+#ifndef HASHTABLE_NSTATS
+ match->signature->calc_strong_count++;
+#endif
+ rs_signature_calc_strong_sum(match->signature, match->buf, match->len,
+ &(match->block_sig.strong_sum));
+ match->buf = NULL;
+ }
+ return memcmp(&match->block_sig.strong_sum, &block_sig->strong_sum,
+ (size_t)match->signature->strong_sum_len);
+}
+
+/* Disable mix32() in the hashtable because RabinKarp doesn't need it. We
+ manually apply mix32() to rollsums before using them in the hashtable. */
+#define HASHTABLE_NMIX32
+/* Instantiate hashtable for rs_block_sig and rs_block_match. */
+#define ENTRY rs_block_sig
+#define MATCH rs_block_match
+#define NAME hashtable
+#include "hashtable.h"
+
+/* Get the size of a packed rs_block_sig_t. */
+static inline size_t rs_block_sig_size(const rs_signature_t *sig)
+{
+ /* Round up to multiple of sizeof(weak_sum) to align memory correctly. */
+ const size_t mask = sizeof(rs_weak_sum_t)- 1;
+ return (offsetof(rs_block_sig_t, strong_sum) +
+ (((size_t)sig->strong_sum_len + mask) & ~mask));
+}
+
+/* Get the pointer to the block_sig_t from a block index. */
+static inline rs_block_sig_t *rs_block_sig_ptr(const rs_signature_t *sig,
+ int block_idx)
+{
+ return (rs_block_sig_t *)((char *)sig->block_sigs +
+ block_idx * rs_block_sig_size(sig));
+}
+
+/* Get the index of a block from a block_sig_t pointer. */
+static inline int rs_block_sig_idx(const rs_signature_t *sig,
+ rs_block_sig_t *block_sig)
+{
+ return (int)(((char *)block_sig -
+ (char *)sig->block_sigs) / rs_block_sig_size(sig));
+}
+
+rs_result rs_sig_args(rs_long_t old_fsize, rs_magic_number * magic,
+ size_t *block_len, size_t *strong_len)
+{
+ size_t rec_block_len; /* the recomended block_len for the given
+ old_fsize. */
+ size_t min_strong_len; /* the minimum strong_len for the given
+ old_fsize and block_len. */
+ size_t max_strong_len; /* the maximum strong_len for the given magic. */
+
+ /* Check and set default arguments. */
+ *magic = *magic ? *magic : RS_RK_BLAKE2_SIG_MAGIC;
+ switch (*magic) {
+ case RS_BLAKE2_SIG_MAGIC:
+ case RS_RK_BLAKE2_SIG_MAGIC:
+ max_strong_len = RS_BLAKE2_SUM_LENGTH;
+ break;
+ case RS_MD4_SIG_MAGIC:
+ case RS_RK_MD4_SIG_MAGIC:
+ max_strong_len = RS_MD4_SUM_LENGTH;
+ break;
+ default:
+ rs_error("invalid magic %#x", *magic);
+ return RS_BAD_MAGIC;
+ }
+ /* The recommended block_len is sqrt(old_fsize) with a 256 min size rounded
+ down to a multiple of the 128 byte blake2b blocksize to give a
+ reasonable compromise between signature size, delta size, and
+ performance. If the old_fsize is unknown, we use the default. */
+ if (old_fsize < 0) {
+ rec_block_len = RS_DEFAULT_BLOCK_LEN;
+ } else {
+ rec_block_len =
+ old_fsize <= 256 * 256 ? 256 : rs_long_sqrt(old_fsize) & ~127;
+ }
+ if (*block_len == 0)
+ *block_len = rec_block_len;
+ /* The recommended strong_len assumes the worst case new_fsize = old_fsize
+ + 16MB with no matches. This results in comparing a block at every byte
+ offset against all the blocks in the signature, or new_fsize*block_num
+ comparisons. With N bits in the blocksig, there is a 1/2^N chance per
+ comparison of a hash colision. So with 2^N attempts there would be a
+ fair chance of having a collision. So we want to round up to the next
+ byte, add an extra 2 bytes (16 bits) in the strongsum, and assume the
+ weaksum is worth another 16 bits, for at least 32 bits extra, giving a
+ worst case 1/2^32 chance of having a hash collision per delta. If
+ old_fsize is unknown we use a conservative default. */
+ if (old_fsize < 0) {
+ min_strong_len = RS_DEFAULT_MIN_STRONG_LEN;
+ } else {
+ min_strong_len =
+ 2 + (rs_long_ln2(old_fsize + ((rs_long_t)1 << 24)) +
+ rs_long_ln2(old_fsize / *block_len + 1) + 7) / 8;
+ }
+ if (*strong_len == 0)
+ *strong_len = max_strong_len;
+ else if (*strong_len == -1)
+ *strong_len = min_strong_len;
+ else if (old_fsize >= 0 && *strong_len < min_strong_len) {
+ rs_warn("strong_len=" FMT_SIZE " smaller than recommended minimum "
+ FMT_SIZE " for old_fsize=" FMT_LONG " with block_len=" FMT_SIZE,
+ *strong_len, min_strong_len, old_fsize, *block_len);
+ } else if (*strong_len > max_strong_len) {
+ rs_error("invalid strong_len=" FMT_SIZE " for magic=%#x", *strong_len,
+ (int)*magic);
+ return RS_PARAM_ERROR;
+ }
+ rs_sig_args_check(*magic, *block_len, *strong_len);
+ return RS_DONE;
+}
+
+rs_result rs_signature_init(rs_signature_t *sig, rs_magic_number magic,
+ size_t block_len, size_t strong_len,
+ rs_long_t sig_fsize)
+{
+ rs_result result;
+
+ /* Check and set default arguments, using old_fsize=-1 for unknown. */
+ if ((result = rs_sig_args(-1, &magic, &block_len, &strong_len)) != RS_DONE)
+ return result;
+ /* Set attributes from args. */
+ sig->magic = magic;
+ sig->block_len = (int)block_len;
+ sig->strong_sum_len = (int)strong_len;
+ sig->count = 0;
+ /* Calculate the number of blocks if we have the signature file size. */
+ /* Magic+header is 12 bytes, each block thereafter is 4 bytes
+ weak_sum+strong_sum_len bytes */
+ sig->size = (int)(sig_fsize < 12 ? 0 : (sig_fsize - 12) / (4 + strong_len));
+ if (sig->size)
+ sig->block_sigs =
+ rs_alloc(sig->size * rs_block_sig_size(sig),
+ "signature->block_sigs");
+ else
+ sig->block_sigs = NULL;
+ sig->hashtable = NULL;
+#ifndef HASHTABLE_NSTATS
+ sig->calc_strong_count = 0;
+#endif
+ rs_signature_check(sig);
+ return RS_DONE;
+}
+
+void rs_signature_done(rs_signature_t *sig)
+{
+ hashtable_free(sig->hashtable);
+ free(sig->block_sigs);
+ rs_bzero(sig, sizeof(*sig));
+}
+
+rs_block_sig_t *rs_signature_add_block(rs_signature_t *sig,
+ rs_weak_sum_t weak_sum,
+ rs_strong_sum_t *strong_sum)
+{
+ rs_signature_check(sig);
+ /* Apply mix32() to rollsum weaksums to improve their distribution. */
+ if (rs_signature_weaksum_kind(sig) == RS_ROLLSUM)
+ weak_sum = mix32(weak_sum);
+ /* If block_sigs is full, allocate more space. */
+ if (sig->count == sig->size) {
+ sig->size = sig->size ? sig->size * 2 : 16;
+ sig->block_sigs =
+ rs_realloc(sig->block_sigs, sig->size * rs_block_sig_size(sig),
+ "signature->block_sigs");
+ }
+ rs_block_sig_t *b = rs_block_sig_ptr(sig, sig->count++);
+ rs_block_sig_init(b, weak_sum, strong_sum, sig->strong_sum_len);
+ return b;
+}
+
+rs_long_t rs_signature_find_match(rs_signature_t *sig, rs_weak_sum_t weak_sum,
+ void const *buf, size_t len)
+{
+ rs_block_match_t m;
+ rs_block_sig_t *b;
+
+ rs_signature_check(sig);
+ rs_block_match_init(&m, sig, weak_sum, NULL, buf, len);
+ if ((b = hashtable_find(sig->hashtable, &m))) {
+ return (rs_long_t)rs_block_sig_idx(sig, b) * sig->block_len;
+ }
+ return -1;
+}
+
+void rs_signature_log_stats(rs_signature_t const *sig)
+{
+#ifndef HASHTABLE_NSTATS
+ hashtable_t *t = sig->hashtable;
+
+ rs_log(RS_LOG_INFO | RS_LOG_NONAME,
+ "match statistics: signature[%ld searches, %ld (%.3f%%) matches, "
+ "%ld (%.3fx) weak sum compares, %ld (%.3f%%) strong sum compares, "
+ "%ld (%.3f%%) strong sum calcs]", t->find_count, t->match_count,
+ 100.0 * (double)t->match_count / (double)t->find_count,
+ t->hashcmp_count, (double)t->hashcmp_count / (double)t->find_count,
+ t->entrycmp_count,
+ 100.0 * (double)t->entrycmp_count / (double)t->find_count,
+ sig->calc_strong_count,
+ 100.0 * (double)sig->calc_strong_count / (double)t->find_count);
+#endif
+}
+
+rs_result rs_build_hash_table(rs_signature_t *sig)
+{
+ rs_block_match_t m;
+ rs_block_sig_t *b;
+ int i;
+
+ rs_signature_check(sig);
+ sig->hashtable = hashtable_new(sig->count);
+ if (!sig->hashtable)
+ return RS_MEM_ERROR;
+ for (i = 0; i < sig->count; i++) {
+ b = rs_block_sig_ptr(sig, i);
+ rs_block_match_init(&m, sig, b->weak_sum, &b->strong_sum, NULL, 0);
+ if (!hashtable_find(sig->hashtable, &m))
+ hashtable_add(sig->hashtable, b);
+ }
+ hashtable_stats_init(sig->hashtable);
+ return RS_DONE;
+}
+
+void rs_free_sumset(rs_signature_t *psums)
+{
+ rs_signature_done(psums);
+ free(psums);
+}
+
+void rs_sumset_dump(rs_signature_t const *sums)
+{
+ int i;
+ rs_block_sig_t *b;
+ char strong_hex[RS_MAX_STRONG_SUM_LENGTH * 3];
+
+ rs_log(RS_LOG_INFO | RS_LOG_NONAME,
+ "sumset info: magic=%#x, block_len=%d, block_num=%d", sums->magic,
+ sums->block_len, sums->count);
+
+ for (i = 0; i < sums->count; i++) {
+ b = rs_block_sig_ptr(sums, i);
+ rs_hexify(strong_hex, b->strong_sum, sums->strong_sum_len);
+ rs_log(RS_LOG_INFO | RS_LOG_NONAME,
+ "sum %6d: weak=" FMT_WEAKSUM ", strong=%s", i, b->weak_sum,
+ strong_hex);
+ }
+}
diff --git a/src/sumset.h b/src/sumset.h
new file mode 100644
index 0000000..52bd7c4
--- /dev/null
+++ b/src/sumset.h
@@ -0,0 +1,134 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 1999, 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 1999 by Andrew Tridgell <tridge@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <assert.h>
+#include "hashtable.h"
+#include "checksum.h"
+
+/** Signature of a single block. */
+typedef struct rs_block_sig {
+ rs_weak_sum_t weak_sum; /**< Block's weak checksum. */
+ rs_strong_sum_t strong_sum; /**< Block's strong checksum. */
+} rs_block_sig_t;
+
+/** Signature of a whole file.
+ *
+ * This includes the all the block sums generated for a file and datastructures
+ * for fast matching against them. */
+struct rs_signature {
+ int magic; /**< The signature magic value. */
+ int block_len; /**< The block length. */
+ int strong_sum_len; /**< The block strong sum length. */
+ int count; /**< Total number of blocks. */
+ int size; /**< Total number of blocks allocated. */
+ void *block_sigs; /**< The packed block_sigs for all blocks. */
+ hashtable_t *hashtable; /**< The hashtable for finding matches. */
+ /* The is extra stats not included in the hashtable stats. */
+#ifndef HASHTABLE_NSTATS
+ long calc_strong_count; /**< The count of strongsum calcs done. */
+#endif
+};
+
+/** Initialize an rs_signature instance.
+ *
+ * \param *sig the signature to initialize.
+ *
+ * \param magic - the magic type to use (0 for "recommended").
+ *
+ * \param block_len - the block length to use (0 for "recommended").
+ *
+ * \param strong_len - the strongsum length to use (0 for "maximum", -1 for
+ * "minimum"). Must be <= the max strongsum size for the strongsum type
+ * indicated by the magic value.
+ *
+ * \param sig_fsize - the signature file size (-1 for "unknown"). Used to
+ * preallocate required storage. */
+rs_result rs_signature_init(rs_signature_t *sig, rs_magic_number magic,
+ size_t block_len, size_t strong_len,
+ rs_long_t sig_fsize);
+
+/** Destroy an rs_signature instance. */
+void rs_signature_done(rs_signature_t *sig);
+
+/** Add a block to an rs_signature instance. */
+rs_block_sig_t *rs_signature_add_block(rs_signature_t *sig,
+ rs_weak_sum_t weak_sum,
+ rs_strong_sum_t *strong_sum);
+
+/** Find a matching block offset in a signature. */
+rs_long_t rs_signature_find_match(rs_signature_t *sig, rs_weak_sum_t weak_sum,
+ void const *buf, size_t len);
+
+/** Assert that rs_sig_args() args for rs_signature_init() are valid.
+ *
+ * We don't use a static inline function here so that assert failure output
+ * points at where rs_sig_args_check() was called from. */
+#define rs_sig_args_check(magic, block_len, strong_len) do {\
+ assert(((magic) & ~0xff) == (RS_MD4_SIG_MAGIC & ~0xff));\
+ assert(((magic) & 0xf0) == 0x30 || ((magic) & 0xf0) == 0x40);\
+ assert((((magic) & 0x0f) == 0x06 &&\
+ (int)(strong_len) <= RS_MD4_SUM_LENGTH) ||\
+ (((magic) & 0x0f) == 0x07 &&\
+ (int)(strong_len) <= RS_BLAKE2_SUM_LENGTH));\
+ assert(0 < (block_len));\
+ assert(0 < (strong_len) && (strong_len) <= RS_MAX_STRONG_SUM_LENGTH);\
+} while (0)
+
+/** Assert that a signature is valid.
+ *
+ * We don't use a static inline function here so that assert failure output
+ * points at where rs_signature_check() was called from. */
+#define rs_signature_check(sig) do {\
+ rs_sig_args_check((sig)->magic, (sig)->block_len, (sig)->strong_sum_len);\
+ assert(0 <= (sig)->count && (sig)->count <= (sig)->size);\
+ assert(!(sig)->hashtable || (sig)->hashtable->count <= (sig)->count);\
+} while (0)
+
+/** Get the weaksum kind for a signature. */
+static inline weaksum_kind_t rs_signature_weaksum_kind(rs_signature_t const
+ *sig)
+{
+ return (sig->magic & 0xf0) == 0x30 ? RS_ROLLSUM : RS_RABINKARP;
+}
+
+/** Get the strongsum kind for a signature. */
+static inline strongsum_kind_t rs_signature_strongsum_kind(rs_signature_t const
+ *sig)
+{
+ return (sig->magic & 0x0f) == 0x06 ? RS_MD4 : RS_BLAKE2;
+}
+
+/** Calculate the weak sum of a buffer. */
+static inline rs_weak_sum_t rs_signature_calc_weak_sum(rs_signature_t const
+ *sig, void const *buf,
+ size_t len)
+{
+ return rs_calc_weak_sum(rs_signature_weaksum_kind(sig), buf, len);
+}
+
+/** Calculate the strong sum of a buffer. */
+static inline void rs_signature_calc_strong_sum(rs_signature_t const *sig,
+ void const *buf, size_t len,
+ rs_strong_sum_t *sum)
+{
+ rs_calc_strong_sum(rs_signature_strongsum_kind(sig), buf, len, sum);
+}
diff --git a/src/trace.c b/src/trace.c
new file mode 100644
index 0000000..0cbc738
--- /dev/null
+++ b/src/trace.c
@@ -0,0 +1,117 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- library for network deltas
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | Finality is death.
+ | Perfection is finality.
+ | Nothing is perfect.
+ | There are lumps in it.
+ */
+
+/** \file trace.c
+ * logging and debugging output.
+ *
+ * \todo Have a bit set in the log level that says not to include the function
+ * name. */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "librsync.h"
+#include "trace.h"
+#include "util.h"
+
+rs_trace_fn_t *rs_trace_impl = rs_trace_stderr;
+
+int rs_trace_level = RS_LOG_INFO;
+
+#define MY_NAME "librsync"
+
+static void rs_log_va(int level, char const *fn, char const *fmt, va_list va);
+
+/** Log severity strings, if any. Must match ordering in ::rs_loglevel. */
+static const char *rs_severities[] = {
+ "EMERGENCY! ", "ALERT! ", "CRITICAL! ", "ERROR: ", "Warning: ",
+ "", "", ""
+};
+
+/** Set the destination of trace information.
+ *
+ * The callback scheme allows for use within applications that may have their
+ * own particular ways of reporting errors: log files for a web server,
+ * perhaps, and an error dialog for a browser.
+ *
+ * \todo Do we really need such fine-grained control, or just yes/no tracing? */
+void rs_trace_to(rs_trace_fn_t *new_impl)
+{
+ rs_trace_impl = new_impl;
+}
+
+void rs_trace_set_level(rs_loglevel level)
+{
+ rs_trace_level = level;
+}
+
+static void rs_log_va(int flags, char const *fn, char const *fmt, va_list va)
+{
+ int level = flags & RS_LOG_PRIMASK;
+
+ if (rs_trace_impl && level <= rs_trace_level) {
+ char buf[1000];
+ char full_buf[1040];
+
+ vsnprintf(buf, sizeof(buf), fmt, va);
+ if (flags & RS_LOG_NONAME || !(*fn)) {
+ snprintf(full_buf, sizeof(full_buf), "%s: %s%s\n", MY_NAME,
+ rs_severities[level], buf);
+ } else {
+ snprintf(full_buf, sizeof(full_buf), "%s: %s(%s) %s\n", MY_NAME,
+ rs_severities[level], fn, buf);
+ }
+ rs_trace_impl(level, full_buf);
+ }
+}
+
+/* Called by a macro that prepends the calling function name, etc. */
+void rs_log0(int level, char const *fn, char const *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ rs_log_va(level, fn, fmt, va);
+ va_end(va);
+}
+
+void rs_trace_stderr(rs_loglevel UNUSED(level), char const *msg)
+{
+ fputs(msg, stderr);
+}
+
+int rs_supports_trace(void)
+{
+#ifdef DO_RS_TRACE
+ return 1;
+#else
+ return 0;
+#endif /* !DO_RS_TRACE */
+}
diff --git a/src/trace.h b/src/trace.h
new file mode 100644
index 0000000..9314b0e
--- /dev/null
+++ b/src/trace.h
@@ -0,0 +1,86 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- generate and apply network deltas
+ *
+ * Copyright (C) 2000, 2001, 2004 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** \file trace.h
+ * logging functions.
+ *
+ * trace may be turned off.
+ *
+ * error is always on, but you can return and continue in some way.
+ *
+ * fatal terminates the whole process.
+ *
+ * \todo A function like perror that includes strerror output. Apache does this
+ * by adding flags as well as the severity level which say whether such
+ * information should be included. */
+
+#include <inttypes.h>
+/* Printf format patters for standard librsync types. */
+#define FMT_LONG "%"PRIdMAX
+#define FMT_WEAKSUM "%08"PRIx32
+/* Old MSVC compilers don't support "%zu" and have "%Iu" instead. */
+#ifdef HAVE_PRINTF_Z
+# define FMT_SIZE "%zu"
+#else
+# define FMT_SIZE "%Iu"
+#endif
+
+/* Some old compilers don't support __func_ and have __FUNCTION__ instead. */
+#ifndef HAVE___FUNC__
+# ifdef HAVE___FUNCTION__
+# define __func__ __FUNCTION__
+# else
+# define __func__ ""
+# endif
+#endif
+
+/* Non-GNUC compatible compilers don't support __attribute__(). */
+#ifndef __GNUC__
+# define __attribute__(x)
+#endif
+
+void rs_log0(int level, char const *fn, char const *fmt, ...)
+ __attribute__((format(printf, 3, 4)));
+
+/** \def rs_trace_enabled()
+ * Call this before putting too much effort into generating trace messages. */
+#ifdef DO_RS_TRACE
+# define rs_trace_enabled() ((rs_trace_level & RS_LOG_PRIMASK) >= RS_LOG_DEBUG)
+# define rs_trace(...) rs_log0(RS_LOG_DEBUG, __func__, __VA_ARGS__)
+#else
+# define rs_trace_enabled() 0
+# define rs_trace(...)
+#endif /* !DO_RS_TRACE */
+
+#define rs_log(l, ...) rs_log0((l), __func__, __VA_ARGS__)
+#define rs_warn(...) rs_log0(RS_LOG_WARNING, __func__, __VA_ARGS__)
+#define rs_error(...) rs_log0(RS_LOG_ERR, __func__, __VA_ARGS__)
+#define rs_fatal(...) do { \
+ rs_log0(RS_LOG_CRIT, __func__, __VA_ARGS__); \
+ abort(); \
+} while (0)
+
+enum {
+ RS_LOG_PRIMASK = 7, /**< Mask to extract priority part. \internal */
+ RS_LOG_NONAME = 8 /**< \b Don't show function name in message. */
+};
+
+extern int rs_trace_level;
diff --git a/src/tube.c b/src/tube.c
new file mode 100644
index 0000000..28e3072
--- /dev/null
+++ b/src/tube.c
@@ -0,0 +1,221 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- dynamic caching and delta update in HTTP
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | Where a calculator on the ENIAC is
+ | equpped with 18,000 vaccuum tubes and
+ | weighs 30 tons, computers in the
+ | future may have only 1,000 vaccuum
+ | tubes and perhaps weigh 1 1/2
+ | tons.
+ | -- Popular Mechanics, March 1949
+ */
+
+/** \file tube.c
+ * A somewhat elastic but fairly small buffer for data passing through a
+ * stream.
+ *
+ * In most cases the iter can adjust to send just as much data will fit. In
+ * some cases that would be too complicated, because it has to transmit an
+ * integer or something similar. So in that case we stick whatever won't fit
+ * into a small buffer.
+ *
+ * A tube can contain some literal data to go out (typically command bytes),
+ * and also an instruction to copy data from the stream's input or from some
+ * other location. Both literal data and a copy command can be queued at the
+ * same time, but only in that order and at most one of each.
+ *
+ * \todo As an optimization, write it directly to the stream if possible. But
+ * for simplicity don't do that yet.
+ *
+ * \todo I think our current copy code will lock up if the application only
+ * ever calls us with either input or output buffers, and not both. So I guess
+ * in that case we might need to copy into some temporary buffer space, and
+ * then back out again later. */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "librsync.h"
+#include "job.h"
+#include "stream.h"
+#include "trace.h"
+
+static void rs_tube_catchup_write(rs_job_t *job)
+{
+ rs_buffers_t *stream = job->stream;
+ size_t len = job->write_len;
+
+ assert(len > 0);
+ if (len > stream->avail_out)
+ len = stream->avail_out;
+ if (len) {
+ memcpy(stream->next_out, job->write_buf, len);
+ stream->next_out += len;
+ stream->avail_out -= len;
+ job->write_len -= len;
+ if (job->write_len > 0)
+ /* Still something left in the tube, shuffle it to the front. */
+ memmove(job->write_buf, job->write_buf + len, job->write_len);
+ }
+ rs_trace("wrote " FMT_SIZE " bytes from tube, " FMT_SIZE " left to write",
+ len, job->write_len);
+}
+
+/** Execute a copy command, taking data from the scoop.
+ *
+ * \sa rs_tube_catchup_copy() */
+static void rs_tube_copy_from_scoop(rs_job_t *job)
+{
+ rs_buffers_t *stream = job->stream;
+ size_t len = job->copy_len;
+
+ assert(len > 0);
+ if (len > job->scoop_avail)
+ len = job->scoop_avail;
+ if (len > stream->avail_out)
+ len = stream->avail_out;
+ if (len) {
+ memcpy(stream->next_out, job->scoop_next, len);
+ stream->next_out += len;
+ stream->avail_out -= len;
+ job->scoop_avail -= len;
+ job->scoop_next += len;
+ job->copy_len -= len;
+ }
+ rs_trace("copied " FMT_SIZE " bytes from scoop, " FMT_SIZE
+ " left in scoop, " FMT_SIZE " left to copy", len, job->scoop_avail,
+ job->copy_len);
+}
+
+/** Execute a copy command, taking data from the stream.
+ *
+ * \sa rs_tube_catchup_copy() */
+static void rs_tube_copy_from_stream(rs_job_t *job)
+{
+ rs_buffers_t *stream = job->stream;
+ size_t len = job->copy_len;
+
+ assert(len > 0);
+ if (len > stream->avail_in)
+ len = stream->avail_in;
+ if (len > stream->avail_out)
+ len = stream->avail_out;
+ if (len) {
+ memcpy(stream->next_out, stream->next_in, len);
+ stream->next_out += len;
+ stream->avail_out -= len;
+ stream->next_in += len;
+ stream->avail_in -= len;
+ job->copy_len -= len;
+ }
+ rs_trace("copied " FMT_SIZE " bytes from stream, " FMT_SIZE
+ "left in stream, " FMT_SIZE " left to copy", len, stream->avail_in,
+ job->copy_len);
+}
+
+/** Catch up on an outstanding copy command.
+ *
+ * Takes data from the scoop, and the input (in that order), and writes as much
+ * as will fit to the output, up to the limit of the outstanding copy. */
+static void rs_tube_catchup_copy(rs_job_t *job)
+{
+ assert(job->write_len == 0);
+ assert(job->copy_len > 0);
+
+ /* If there's data in the scoop, send that first. */
+ if (job->scoop_avail && job->copy_len) {
+ rs_tube_copy_from_scoop(job);
+ }
+ /* If there's more to copy and we emptied the scoop, send input. */
+ if (job->copy_len && !job->scoop_avail) {
+ rs_tube_copy_from_stream(job);
+ }
+}
+
+/** Put whatever will fit from the tube into the output of the stream.
+ *
+ * \return RS_DONE if the tube is now empty and ready to accept another
+ * command, RS_BLOCKED if there is still stuff waiting to go out. */
+rs_result rs_tube_catchup(rs_job_t *job)
+{
+ if (job->write_len) {
+ rs_tube_catchup_write(job);
+ if (job->write_len)
+ return RS_BLOCKED;
+ }
+
+ if (job->copy_len) {
+ rs_tube_catchup_copy(job);
+ if (job->copy_len) {
+ if (job->stream->eof_in && !job->stream->avail_in
+ && !job->scoop_avail) {
+ rs_error("reached end of file while copying data");
+ return RS_INPUT_ENDED;
+ }
+ return RS_BLOCKED;
+ }
+ }
+ return RS_DONE;
+}
+
+/* Check whether there is data in the tube waiting to go out.
+
+ \return true if the previous command has finished doing all its output. */
+int rs_tube_is_idle(rs_job_t const *job)
+{
+ return job->write_len == 0 && job->copy_len == 0;
+}
+
+/** Queue up a request to copy through \p len bytes from the input to the
+ * output of the stream.
+ *
+ * The data is copied from the scoop (if there is anything there) or from the
+ * input, on the next call to rs_tube_write().
+ *
+ * We can only accept this request if there is no copy command already pending.
+ *
+ * \todo Try to do the copy immediately, and return a result. Then, people can
+ * try to continue if possible. Is this really required? Callers can just go
+ * out and back in again after flushing the tube. */
+void rs_tube_copy(rs_job_t *job, size_t len)
+{
+ assert(job->copy_len == 0);
+
+ job->copy_len = len;
+}
+
+/** Push some data into the tube for storage.
+ *
+ * The tube's never supposed to get very big, so this will just pop loudly if
+ * you do that.
+ *
+ * We can't accept write data if there's already a copy command in the tube,
+ * because the write data comes out first. */
+void rs_tube_write(rs_job_t *job, const void *buf, size_t len)
+{
+ assert(job->copy_len == 0);
+ assert(len <= sizeof(job->write_buf) - job->write_len);
+
+ memcpy(job->write_buf + job->write_len, buf, len);
+ job->write_len += len;
+}
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..da1ee9c
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,94 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | On heroin, I have all the answers.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include "librsync.h"
+#include "util.h"
+#include "trace.h"
+
+void rs_bzero(void *buf, size_t size)
+{
+ memset(buf, 0, size);
+}
+
+void *rs_alloc_struct0(size_t size, char const *name)
+{
+ void *p;
+
+ if (!(p = malloc(size))) {
+ rs_fatal("couldn't allocate instance of %s", name);
+ }
+ rs_bzero(p, size);
+ return p;
+}
+
+void *rs_alloc(size_t size, char const *name)
+{
+ void *p;
+
+ if (!(p = malloc(size))) {
+ rs_fatal("couldn't allocate instance of %s", name);
+ }
+
+ return p;
+}
+
+void *rs_realloc(void *ptr, size_t size, char const *name)
+{
+ void *p;
+
+ if (!(p = realloc(ptr, size))) {
+ rs_fatal("couldn't reallocate instance of %s", name);
+ }
+ return p;
+}
+
+int rs_long_ln2(rs_long_t v)
+{
+ int n;
+
+ /* Count the number of shifts to zero v. */
+ for (n = 0; (v >>= 1); n++) ;
+ return n;
+}
+
+int rs_long_sqrt(rs_long_t v)
+{
+ rs_long_t n, b;
+
+ /* Find the most significant bit of the root. */
+ for (b = 1, n = v; (n >>= 2); b <<= 1) ;
+ /* Walk down the bits of the root. */
+ for (n = 0; b; b >>= 1) {
+ /* Set the bit in the answer n. */
+ n |= b;
+ /* If n^2 is too big, clear the bit. */
+ if (n * n > v)
+ n ^= b;
+ }
+ return (int)n;
+}
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..4fbd1c7
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,42 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- library for network deltas
+ *
+ * Copyright (C) 1999, 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ * Copyright (C) 1999 by Andrew Tridgell <tridge@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+void *rs_alloc(size_t size, char const *name);
+void *rs_realloc(void *ptr, size_t size, char const *name);
+void *rs_alloc_struct0(size_t size, char const *name);
+
+void rs_bzero(void *buf, size_t size);
+
+int rs_long_ln2(rs_long_t v);
+int rs_long_sqrt(rs_long_t v);
+
+/** Allocate and zero-fill an instance of TYPE. */
+#define rs_alloc_struct(type) \
+ ((type *) rs_alloc_struct0(sizeof(type), #type))
+
+#ifdef __GNUC__
+# define UNUSED(x) x __attribute__((unused))
+#elif defined(__LCLINT__) || defined(S_SPLINT_S)
+# define UNUSED(x) /*@unused@*/ x
+#else /* !__GNUC__ && !__LCLINT__ */
+# define UNUSED(x) x
+#endif /* !__GNUC__ && !__LCLINT__ */
diff --git a/src/version.c b/src/version.c
new file mode 100644
index 0000000..ebc3983
--- /dev/null
+++ b/src/version.c
@@ -0,0 +1,25 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include "librsync_export.h"
+
+LIBRSYNC_EXPORT char const rs_librsync_version[] = PACKAGE " " VERSION;
diff --git a/src/whole.c b/src/whole.c
new file mode 100644
index 0000000..20cb9b7
--- /dev/null
+++ b/src/whole.c
@@ -0,0 +1,153 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright 2000, 2001, 2014, 2015 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /*=
+ | Is it possible that software is not
+ | like anything else, that it is meant
+ | to be discarded: that the whole point
+ | is to always see it as a soap bubble?
+ | -- Alan Perlis
+ */
+
+#include "config.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "librsync.h"
+#include "whole.h"
+#include "sumset.h"
+#include "job.h"
+#include "buf.h"
+
+/** Whole file IO buffer sizes. */
+LIBRSYNC_EXPORT int rs_inbuflen = 0, rs_outbuflen = 0;
+
+/** Run a job continuously, with input to/from the two specified files.
+ *
+ * The job should already be set up, and must be freed by the caller after
+ * return. If rs_inbuflen or rs_outbuflen are set, they will override the
+ * inbuflen and outbuflen arguments.
+ *
+ * \param in_file - input file, or NULL if there is no input.
+ *
+ * \param out_file - output file, or NULL if there is no output.
+ *
+ * \param inbuflen - recommended input buffer size to use.
+ *
+ * \param outbuflen - recommended output buffer size to use.
+ *
+ * \return RS_DONE if the job completed, or otherwise an error result. */
+rs_result rs_whole_run(rs_job_t *job, FILE *in_file, FILE *out_file,
+ int inbuflen, int outbuflen)
+{
+ rs_buffers_t buf;
+ rs_result result;
+ rs_filebuf_t *in_fb = NULL, *out_fb = NULL;
+
+ /* Override buffer sizes if rs_inbuflen or rs_outbuflen are set. */
+ inbuflen = rs_inbuflen ? rs_inbuflen : inbuflen;
+ outbuflen = rs_outbuflen ? rs_outbuflen : outbuflen;
+ if (in_file)
+ in_fb = rs_filebuf_new(in_file, inbuflen);
+ if (out_file)
+ out_fb = rs_filebuf_new(out_file, outbuflen);
+ result =
+ rs_job_drive(job, &buf, in_fb ? rs_infilebuf_fill : NULL, in_fb,
+ out_fb ? rs_outfilebuf_drain : NULL, out_fb);
+ if (in_fb)
+ rs_filebuf_free(in_fb);
+ if (out_fb)
+ rs_filebuf_free(out_fb);
+ return result;
+}
+
+rs_result rs_sig_file(FILE *old_file, FILE *sig_file, size_t block_len,
+ size_t strong_len, rs_magic_number sig_magic,
+ rs_stats_t *stats)
+{
+ rs_job_t *job;
+ rs_result r;
+ rs_long_t old_fsize = rs_file_size(old_file);
+
+ if ((r =
+ rs_sig_args(old_fsize, &sig_magic, &block_len,
+ &strong_len)) != RS_DONE)
+ return r;
+ job = rs_sig_begin(block_len, strong_len, sig_magic);
+ /* Size inbuf for 4 blocks, outbuf for header + 4 blocksums. */
+ r = rs_whole_run(job, old_file, sig_file, 4 * (int)block_len,
+ 12 + 4 * (4 + (int)strong_len));
+ if (stats)
+ memcpy(stats, &job->stats, sizeof *stats);
+ rs_job_free(job);
+
+ return r;
+}
+
+rs_result rs_loadsig_file(FILE *sig_file, rs_signature_t **sumset,
+ rs_stats_t *stats)
+{
+ rs_job_t *job;
+ rs_result r;
+
+ job = rs_loadsig_begin(sumset);
+ /* Set filesize used to estimate signature size. */
+ job->sig_fsize = rs_file_size(sig_file);
+ /* Size inbuf for 1024x 16 byte blocksums. */
+ r = rs_whole_run(job, sig_file, NULL, 1024 * 16, 0);
+ if (stats)
+ memcpy(stats, &job->stats, sizeof *stats);
+ rs_job_free(job);
+
+ return r;
+}
+
+rs_result rs_delta_file(rs_signature_t *sig, FILE *new_file, FILE *delta_file,
+ rs_stats_t *stats)
+{
+ rs_job_t *job;
+ rs_result r;
+
+ job = rs_delta_begin(sig);
+ /* Size inbuf for 1 block, outbuf for literal cmd + 4 blocks. */
+ r = rs_whole_run(job, new_file, delta_file, sig->block_len,
+ 10 + 4 * sig->block_len);
+ if (stats)
+ memcpy(stats, &job->stats, sizeof *stats);
+ rs_job_free(job);
+ return r;
+}
+
+rs_result rs_patch_file(FILE *basis_file, FILE *delta_file, FILE *new_file,
+ rs_stats_t *stats)
+{
+ rs_job_t *job;
+ rs_result r;
+
+ job = rs_patch_begin(rs_file_copy_cb, basis_file);
+ /* Default size inbuf and outbuf 64K. */
+ r = rs_whole_run(job, delta_file, new_file, 64 * 1024, 64 * 1024);
+ if (stats)
+ memcpy(stats, &job->stats, sizeof *stats);
+ rs_job_free(job);
+ return r;
+}
diff --git a/src/whole.h b/src/whole.h
new file mode 100644
index 0000000..945f568
--- /dev/null
+++ b/src/whole.h
@@ -0,0 +1,23 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- the library for network deltas
+ *
+ * Copyright (C) 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+rs_result rs_whole_run(rs_job_t *job, FILE *in_file, FILE *out_file,
+ int inbuflen, int outbuflen);
diff --git a/tests/changes.input/01.in b/tests/changes.input/01.in
new file mode 100644
index 0000000..e6e3285
--- /dev/null
+++ b/tests/changes.input/01.in
@@ -0,0 +1,182 @@
+I am the psychotherapist. Please, describe your problems. Each time
+you are finished talking, type RET twice.
+
+Well, I'm on the right planet---everyone looks like me!!!
+
+Why do you say that?
+
+Are we THERE yet?!
+
+What makes you believe are you there yet?
+
+.. Now I think I just reached the state of HYPERTENSION that comes
+ JUST BEFORE you see the TOTAL at the SAFEWAY CHECKOUT COUNTER!
+
+Is it because comes just before I see the total at the safeway
+checkout counter that you came to me?
+
+Do you guys know we just passed thru a BLACK HOLE in space?
+
+Maybe your plans have something to do with this.
+
+I am NOT a nut....
+
+Is it because of your life that you say you are not a nut?
+
+Okay, BARBRA STREISAND, I recognize you now!! Also EFREM ZIMBALIST,
+ JUNIOR!! And BEAUMONT NEWHALL!! Everybody into th' BATHROOM!
+
+Earlier you said comes just before I see the total at the safeway
+checkout counter?
+
+I know how to get the hostesses released! Give them their own
+ television series!
+
+Is it because of the people you hang around with that you are going
+through all this?
+
+I request a weekend in Havana with Phil Silvers!
+
+I don't understand.
+
+Why is it that when you DIE, you can't take your
+ HOME ENTERTAINMENT CENTER with you??
+
+Does it bother you that is it that when I die me cannot take my home
+entertainment center with me?
+
+HUMAN REPLICAS are inserted into VATS of NUTRITIONAL YEAST...
+
+You mentioned that comes just before I see the total at the safeway
+checkout counter?
+
+How's the wife? Is she at home enjoying capitalism?
+
+How do you reconcile problems at school?
+
+.. I think I'll KILL myself by leaping out of this
+ 14th STOREY WINDOW while reading ERICA JONG'S poetry!!
+
+This is not a healthy way of thinking.
+
+RELAX!! ... This is gonna be a HEALING EXPERIENCE!! Besides,
+ I work for DING DONGS!
+
+When did you first know that you work for ding dongs?
+
+Yow! I'm having a quadraphonic sensation of two winos
+ alone in a steel mill!
+
+Perhaps this has something to do with any hobbies you have?
+
+Awright, which one of you hid my PENIS ENVY?
+
+Are you sure that is it that when I die me cannot take my home
+entertainment center with me?
+
+My EARS are GONE!!
+
+Possibly your sex life are related to this.
+
+It's the land of DONNY AND MARIE as promised in TV GUIDE!
+
+Are you afraid of that?
+
+My TOYOTA is built like a ... BAGEL with CREAM CHEESE!!
+
+Do you really think built might want to have this bagel?
+
+I wonder if I could ever get started in the credit world?
+
+Earlier you said comes just before I see the total at the safeway
+checkout counter?
+
+TATTOOED MIDGETS are using ALFREDO in their SALAMI FACTORY!
+
+Is it because of hangups you have that you are going through all this?
+
+I LIKE Aisle 7a.
+
+What makes you think you like aisle 7a?
+
+Youth of today! Join me in a mass rally for traditional mental attitudes!
+
+You mentioned that you work for ding dongs?
+
+Yow! Did something bad happen or am I in a drive-in movie??
+
+How do you reconcile your inhibitions?
+
+Vote for ME -- I'm well-tapered, half-cocked, ill-conceived and
+ TAX-DEFERRED!
+
+Why do you say that?
+
+Are we THERE yet?!
+
+What makes you believe is it that when I die me cannot take my home
+entertainment center with me?
+
+Is it FUN to be a MIDGET?
+
+Maybe this is related to some problems in your childhood?
+
+I left my WALLET in the BATHROOM!!
+
+Is it because of some problems at home that you say you left your
+wallet in the bathroom?
+
+Spreading peanut butter reminds me of opera!! I wonder why?
+
+Can you elaborate on that?
+
+Dizzy, are we "REAL PEOPLE" or "AMAZING ANIMALS"?
+
+Earlier you said built would like to have this bagel?
+
+My LESLIE GORE record is BROKEN..
+
+Perhaps your plans could have caused this.
+
+With YOU, I can be MYSELF.. We don't NEED Dan Rather..
+
+Are you sure that you do not need dan rather?
+
+Yow!
+
+Yow! Are we interactive yet?
+
+You must be a CUB SCOUT!! Have you made your MONEY-DROP today??
+
+You mentioned that comes just before I see the total at the safeway
+checkout counter?
+
+It's the RINSE CYCLE!! They've ALL IGNORED the RINSE CYCLE!!
+
+Is it because of your life that you are going through all this?
+
+There's a little picture of ED MCMAHON doing BAD THINGS to JOAN RIVERS
+ in a $200,000 MALIBU BEACH HOUSE!!
+
+I don't understand.
+
+FISH-NET-FISH-NET-FISH-NET-FISH-NET-FISH!!
+
+Do you really think you work for ding dongs?
+
+NATHAN... your PARENTS were in a CARCRASH!!
+ They're VOIDED - They COLLAPSED
+ They had no CHAINSAWS... They had no MONEY MACHINES...
+ They did PILLS in SKIMPY GRASS SKIRTS...
+ Nathan, I EMULATED them... but they were OFF-KEY...
+
+Is the fact that they were off key the real reason?
+
+I want you to MEMORIZE the collected poems of EDNA ST VINCENT MILLAY..
+ BACKWARDS!!
+
+I would appreciate it if you would continue.
+
+Now KEN is having a MENTAL CRISIS beacuse his "R.V." PAYMENTS are
+ OVER-DUE!!
+
diff --git a/tests/changes.input/02.in b/tests/changes.input/02.in
new file mode 100644
index 0000000..6028817
--- /dev/null
+++ b/tests/changes.input/02.in
@@ -0,0 +1,179 @@
+Well, I'm on the right planet---everyone looks like me!!!
+
+Why do you say that?
+
+Are we THERE yet?!
+
+What makes you believe are you there yet?
+
+.. Now I think I just reached the state of HYPERTENSION that comes
+ JUST BEFORE you see the TOTAL at the SAFEWAY CHECKOUT COUNTER!
+
+Is it because comes just before I see the total at the safeway
+checkout counter that you came to me?
+
+Do you guys know we just passed thru a BLACK HOLE in space?
+
+Maybe your plans have something to do with this.
+
+I am NOT a nut....
+
+Is it because of your life that you say you are not a nut?
+
+Okay, BARBRA STREISAND, I recognize you now!! Also EFREM ZIMBALIST,
+ JUNIOR!! And BEAUMONT NEWHALL!! Everybody into th' BATHROOM!
+
+Earlier you said comes just before I see the total at the safeway
+checkout counter?
+
+I know how to get the hostesses released! Give them their own
+ television series!
+
+Is it because of the people you hang around with that you are going
+through all this?
+
+I request a weekend in Havana with Phil Silvers!
+
+I don't understand.
+
+Why is it that when you DIE, you can't take your
+ HOME ENTERTAINMENT CENTER with you??
+
+Does it bother you that is it that when I die me cannot take my home
+entertainment center with me?
+
+HUMAN REPLICAS are inserted into VATS of NUTRITIONAL YEAST...
+
+You mentioned that comes just before I see the total at the safeway
+checkout counter?
+
+How's the wife? Is she at home enjoying capitalism?
+
+How do you reconcile problems at school?
+
+.. I think I'll KILL myself by leaping out of this
+ 14th STOREY WINDOW while reading ERICA JONG'S poetry!!
+
+This is not a healthy way of thinking.
+
+RELAX!! ... This is gonna be a HEALING EXPERIENCE!! Besides,
+ I work for DING DONGS!
+
+When did you first know that you work for ding dongs?
+
+Yow! I'm having a quadraphonic sensation of two winos
+ alone in a steel mill!
+
+Perhaps this has something to do with any hobbies you have?
+
+Awright, which one of you hid my PENIS ENVY?
+
+Are you sure that is it that when I die me cannot take my home
+entertainment center with me?
+
+My EARS are GONE!!
+
+Possibly your sex life are related to this.
+
+It's the land of DONNY AND MARIE as promised in TV GUIDE!
+
+Are you afraid of that?
+
+My TOYOTA is built like a ... BAGEL with CREAM CHEESE!!
+
+Do you really think built might want to have this bagel?
+
+I wonder if I could ever get started in the credit world?
+
+Earlier you said comes just before I see the total at the safeway
+checkout counter?
+
+TATTOOED MIDGETS are using ALFREDO in their SALAMI FACTORY!
+
+Is it because of hangups you have that you are going through all this?
+
+I LIKE Aisle 7a.
+
+What makes you think you like aisle 7a?
+
+Youth of today! Join me in a mass rally for traditional mental attitudes!
+
+You mentioned that you work for ding dongs?
+
+Yow! Did something bad happen or am I in a drive-in movie??
+
+How do you reconcile your inhibitions?
+
+Vote for ME -- I'm well-tapered, half-cocked, ill-conceived and
+ TAX-DEFERRED!
+
+Why do you say that?
+
+Are we THERE yet?!
+
+What makes you believe is it that when I die me cannot take my home
+entertainment center with me?
+
+Is it FUN to be a MIDGET?
+
+Maybe this is related to some problems in your childhood?
+
+I left my WALLET in the BATHROOM!!
+
+Is it because of some problems at home that you say you left your
+wallet in the bathroom?
+
+Spreading peanut butter reminds me of opera!! I wonder why?
+
+Can you elaborate on that?
+
+Dizzy, are we "REAL PEOPLE" or "AMAZING ANIMALS"?
+
+Earlier you said built would like to have this bagel?
+
+My LESLIE GORE record is BROKEN..
+
+Perhaps your plans could have caused this.
+
+With YOU, I can be MYSELF.. We don't NEED Dan Rather..
+
+Are you sure that you do not need dan rather?
+
+Yow!
+
+Yow! Are we interactive yet?
+
+You must be a CUB SCOUT!! Have you made your MONEY-DROP today??
+
+You mentioned that comes just before I see the total at the safeway
+checkout counter?
+
+It's the RINSE CYCLE!! They've ALL IGNORED the RINSE CYCLE!!
+
+Is it because of your life that you are going through all this?
+
+There's a little picture of ED MCMAHON doing BAD THINGS to JOAN RIVERS
+ in a $200,000 MALIBU BEACH HOUSE!!
+
+I don't understand.
+
+FISH-NET-FISH-NET-FISH-NET-FISH-NET-FISH!!
+
+Do you really think you work for ding dongs?
+
+NATHAN... your PARENTS were in a CARCRASH!!
+ They're VOIDED - They COLLAPSED
+ They had no CHAINSAWS... They had no MONEY MACHINES...
+ They did PILLS in SKIMPY GRASS SKIRTS...
+ Nathan, I EMULATED them... but they were OFF-KEY...
+
+Is the fact that they were off key the real reason?
+
+I want you to MEMORIZE the collected poems of EDNA ST VINCENT MILLAY..
+ BACKWARDS!!
+
+I would appreciate it if you would continue.
+
+Now KEN is having a MENTAL CRISIS beacuse his "R.V." PAYMENTS are
+ OVER-DUE!!
+
diff --git a/tests/changes.input/03.in b/tests/changes.input/03.in
new file mode 100644
index 0000000..281f004
--- /dev/null
+++ b/tests/changes.input/03.in
@@ -0,0 +1,180 @@
+I am the psychotherapist. Please, describe your problems. Each time
+you are finished talking, type RET twice.
+
+Well, I'm on the right planet---everyone looks like me!!!
+
+Why do you say that?
+
+Are we THERE yet?!
+
+What makes you believe are you there yet?
+
+.. Now I think I just reached the state of HYPERTENSION that comes
+ JUST BEFORE you see the TOTAL at the SAFEWAY CHECKOUT COUNTER!
+
+Is it because comes just before I see the total at the safeway
+checkout counter that you came to me?
+
+Do you guys know we just passed thru a BLACK HOLE in space?
+
+Maybe your plans have something to do with this.
+
+I am NOT a nut....
+
+Is it because of your life that you say you are not a nut?
+
+Okay, BARBRA STREISAND, I recognize you now!! Also EFREM ZIMBALIST,
+ JUNIOR!! And BEAUMONT NEWHALL!! Everybody into th' BATHROOM!
+
+Earlier you said comes just before I see the total at the safeway
+checkout counter?
+
+I know how to get the hostesses released! Give them their own
+ television series!
+
+Is it because of the people you hang around with that you are going
+through all this?
+
+I request a weekend in Havana with Phil Silvers!
+
+I don't understand.
+
+Why is it that when you DIE, you can't take your
+ HOME ENTERTAINMENT CENTER with you??
+
+Does it bother you that is it that when I die me cannot take my home
+entertainment center with me?
+
+HUMAN REPLICAS are inserted into VATS of NUTRITIONAL YEAST...
+
+You mentioned that comes just before I see the total at the safeway
+checkout counter?
+
+How's the wife? Is she at home enjoying capitalism?
+
+How do you reconcile problems at school?
+
+.. I think I'll KILL myself by leaping out of this
+ 14th STOREY WINDOW while reading ERICA JONG'S poetry!!
+
+This is not a healthy way of thinking.
+
+RELAX!! ... This is gonna be a HEALING EXPERIENCE!! Besides,
+ I work for DING DONGS!
+
+When did you first know that you work for ding dongs?
+
+Yow! I'm having a quadraphonic sensation of two winos
+ alone in a steel mill!
+
+Perhaps this has something to do with any hobbies you have?
+
+Awright, which one of you hid my PENIS ENVY?
+
+Are you sure that is it that when I die me cannot take my home
+entertainment center with me?
+
+My EARS are GONE!!
+
+It's the land of DONNY AND MARIE as promised in TV GUIDE!
+
+Are you afraid of that?
+
+My TOYOTA is built like a ... BAGEL with CREAM CHEESE!!
+
+Do you really think built might want to have this bagel?
+
+I wonder if I could ever get started in the credit world?
+
+Earlier you said comes just before I see the total at the safeway
+checkout counter?
+
+TATTOOED MIDGETS are using ALFREDO in their SALAMI FACTORY!
+
+Is it because of hangups you have that you are going through all this?
+
+I LIKE Aisle 7a.
+
+What makes you think you like aisle 7a?
+
+Youth of today! Join me in a mass rally for traditional mental attitudes!
+
+You mentioned that you work for ding dongs?
+
+Yow! Did something bad happen or am I in a drive-in movie??
+
+How do you reconcile your inhibitions?
+
+Vote for ME -- I'm well-tapered, half-cocked, ill-conceived and
+ TAX-DEFERRED!
+
+Why do you say that?
+
+Are we THERE yet?!
+
+What makes you believe is it that when I die me cannot take my home
+entertainment center with me?
+
+Is it FUN to be a MIDGET?
+
+Maybe this is related to some problems in your childhood?
+
+I left my WALLET in the BATHROOM!!
+
+Is it because of some problems at home that you say you left your
+wallet in the bathroom?
+
+Spreading peanut butter reminds me of opera!! I wonder why?
+
+Can you elaborate on that?
+
+Dizzy, are we "REAL PEOPLE" or "AMAZING ANIMALS"?
+
+Earlier you said built would like to have this bagel?
+
+My LESLIE GORE record is BROKEN..
+
+Perhaps your plans could have caused this.
+
+With YOU, I can be MYSELF.. We don't NEED Dan Rather..
+
+Are you sure that you do not need dan rather?
+
+Yow!
+
+Yow! Are we interactive yet?
+
+You must be a CUB SCOUT!! Have you made your MONEY-DROP today??
+
+You mentioned that comes just before I see the total at the safeway
+checkout counter?
+
+It's the RINSE CYCLE!! They've ALL IGNORED the RINSE CYCLE!!
+
+Is it because of your life that you are going through all this?
+
+There's a little picture of ED MCMAHON doing BAD THINGS to JOAN RIVERS
+ in a $200,000 MALIBU BEACH HOUSE!!
+
+I don't understand.
+
+FISH-NET-FISH-NET-FISH-NET-FISH-NET-FISH!!
+
+Do you really think you work for ding dongs?
+
+NATHAN... your PARENTS were in a CARCRASH!!
+ They're VOIDED - They COLLAPSED
+ They had no CHAINSAWS... They had no MONEY MACHINES...
+ They did PILLS in SKIMPY GRASS SKIRTS...
+ Nathan, I EMULATED them... but they were OFF-KEY...
+
+Is the fact that they were off key the real reason?
+
+I want you to MEMORIZE the collected poems of EDNA ST VINCENT MILLAY..
+ BACKWARDS!!
+
+I would appreciate it if you would continue.
+
+Now KEN is having a MENTAL CRISIS beacuse his "R.V." PAYMENTS are
+ OVER-DUE!!
+
diff --git a/tests/changes.input/04.in b/tests/changes.input/04.in
new file mode 100644
index 0000000..11264ae
--- /dev/null
+++ b/tests/changes.input/04.in
@@ -0,0 +1,364 @@
+I am the psychotherapist. Please, describe your problems. Each time
+you are finished talking, type RET twice.
+
+Well, I'm on the right planet---everyone looks like me!!!
+
+Why do you say that?
+
+Are we THERE yet?!
+
+What makes you believe are you there yet?
+
+.. Now I think I just reached the state of HYPERTENSION that comes
+ JUST BEFORE you see the TOTAL at the SAFEWAY CHECKOUT COUNTER!
+
+Is it because comes just before I see the total at the safeway
+checkout counter that you came to me?
+
+Do you guys know we just passed thru a BLACK HOLE in space?
+
+Maybe your plans have something to do with this.
+
+I am NOT a nut....
+
+Is it because of your life that you say you are not a nut?
+
+Okay, BARBRA STREISAND, I recognize you now!! Also EFREM ZIMBALIST,
+ JUNIOR!! And BEAUMONT NEWHALL!! Everybody into th' BATHROOM!
+
+Earlier you said comes just before I see the total at the safeway
+checkout counter?
+
+I know how to get the hostesses released! Give them their own
+ television series!
+
+Is it because of the people you hang around with that you are going
+through all this?
+
+I request a weekend in Havana with Phil Silvers!
+
+I don't understand.
+
+Why is it that when you DIE, you can't take your
+ HOME ENTERTAINMENT CENTER with you??
+
+Does it bother you that is it that when I die me cannot take my home
+entertainment center with me?
+
+HUMAN REPLICAS are inserted into VATS of NUTRITIONAL YEAST...
+
+You mentioned that comes just before I see the total at the safeway
+checkout counter?
+
+How's the wife? Is she at home enjoying capitalism?
+
+How do you reconcile problems at school?
+
+.. I think I'll KILL myself by leaping out of this
+ 14th STOREY WINDOW while reading ERICA JONG'S poetry!!
+
+This is not a healthy way of thinking.
+
+RELAX!! ... This is gonna be a HEALING EXPERIENCE!! Besides,
+ I work for DING DONGS!
+
+When did you first know that you work for ding dongs?
+
+Yow! I'm having a quadraphonic sensation of two winos
+ alone in a steel mill!
+
+Perhaps this has something to do with any hobbies you have?
+
+Awright, which one of you hid my PENIS ENVY?
+
+Are you sure that is it that when I die me cannot take my home
+entertainment center with me?
+
+My EARS are GONE!!
+
+Possibly your sex life are related to this.
+
+It's the land of DONNY AND MARIE as promised in TV GUIDE!
+
+Are you afraid of that?
+
+My TOYOTA is built like a ... BAGEL with CREAM CHEESE!!
+
+Do you really think built might want to have this bagel?
+
+I wonder if I could ever get started in the credit world?
+
+Earlier you said comes just before I see the total at the safeway
+checkout counter?
+
+TATTOOED MIDGETS are using ALFREDO in their SALAMI FACTORY!
+
+Is it because of hangups you have that you are going through all this?
+
+I LIKE Aisle 7a.
+
+What makes you think you like aisle 7a?
+
+Youth of today! Join me in a mass rally for traditional mental attitudes!
+
+You mentioned that you work for ding dongs?
+
+Yow! Did something bad happen or am I in a drive-in movie??
+
+How do you reconcile your inhibitions?
+
+Vote for ME -- I'm well-tapered, half-cocked, ill-conceived and
+ TAX-DEFERRED!
+
+Why do you say that?
+
+Are we THERE yet?!
+
+What makes you believe is it that when I die me cannot take my home
+entertainment center with me?
+
+Is it FUN to be a MIDGET?
+
+Maybe this is related to some problems in your childhood?
+
+I left my WALLET in the BATHROOM!!
+
+Is it because of some problems at home that you say you left your
+wallet in the bathroom?
+
+Spreading peanut butter reminds me of opera!! I wonder why?
+
+Can you elaborate on that?
+
+Dizzy, are we "REAL PEOPLE" or "AMAZING ANIMALS"?
+
+Earlier you said built would like to have this bagel?
+
+My LESLIE GORE record is BROKEN..
+
+Perhaps your plans could have caused this.
+
+With YOU, I can be MYSELF.. We don't NEED Dan Rather..
+
+Are you sure that you do not need dan rather?
+
+Yow!
+
+Yow! Are we interactive yet?
+
+You must be a CUB SCOUT!! Have you made your MONEY-DROP today??
+
+You mentioned that comes just before I see the total at the safeway
+checkout counter?
+
+It's the RINSE CYCLE!! They've ALL IGNORED the RINSE CYCLE!!
+
+Is it because of your life that you are going through all this?
+
+There's a little picture of ED MCMAHON doing BAD THINGS to JOAN RIVERS
+ in a $200,000 MALIBU BEACH HOUSE!!
+
+I don't understand.
+
+FISH-NET-FISH-NET-FISH-NET-FISH-NET-FISH!!
+
+Do you really think you work for ding dongs?
+
+NATHAN... your PARENTS were in a CARCRASH!!
+ They're VOIDED - They COLLAPSED
+ They had no CHAINSAWS... They had no MONEY MACHINES...
+ They did PILLS in SKIMPY GRASS SKIRTS...
+ Nathan, I EMULATED them... but they were OFF-KEY...
+
+Is the fact that they were off key the real reason?
+
+I want you to MEMORIZE the collected poems of EDNA ST VINCENT MILLAY..
+ BACKWARDS!!
+
+I would appreciate it if you would continue.
+
+Now KEN is having a MENTAL CRISIS beacuse his "R.V." PAYMENTS are
+ OVER-DUE!!
+
+I am the psychotherapist. Please, describe your problems. Each time
+you are finished talking, type RET twice.
+
+Well, I'm on the right planet---everyone looks like me!!!
+
+Why do you say that?
+
+Are we THERE yet?!
+
+What makes you believe are you there yet?
+
+.. Now I think I just reached the state of HYPERTENSION that comes
+ JUST BEFORE you see the TOTAL at the SAFEWAY CHECKOUT COUNTER!
+
+Is it because comes just before I see the total at the safeway
+checkout counter that you came to me?
+
+Do you guys know we just passed thru a BLACK HOLE in space?
+
+Maybe your plans have something to do with this.
+
+I am NOT a nut....
+
+Is it because of your life that you say you are not a nut?
+
+Okay, BARBRA STREISAND, I recognize you now!! Also EFREM ZIMBALIST,
+ JUNIOR!! And BEAUMONT NEWHALL!! Everybody into th' BATHROOM!
+
+Earlier you said comes just before I see the total at the safeway
+checkout counter?
+
+I know how to get the hostesses released! Give them their own
+ television series!
+
+Is it because of the people you hang around with that you are going
+through all this?
+
+I request a weekend in Havana with Phil Silvers!
+
+I don't understand.
+
+Why is it that when you DIE, you can't take your
+ HOME ENTERTAINMENT CENTER with you??
+
+Does it bother you that is it that when I die me cannot take my home
+entertainment center with me?
+
+HUMAN REPLICAS are inserted into VATS of NUTRITIONAL YEAST...
+
+You mentioned that comes just before I see the total at the safeway
+checkout counter?
+
+How's the wife? Is she at home enjoying capitalism?
+
+How do you reconcile problems at school?
+
+.. I think I'll KILL myself by leaping out of this
+ 14th STOREY WINDOW while reading ERICA JONG'S poetry!!
+
+This is not a healthy way of thinking.
+
+RELAX!! ... This is gonna be a HEALING EXPERIENCE!! Besides,
+ I work for DING DONGS!
+
+When did you first know that you work for ding dongs?
+
+Yow! I'm having a quadraphonic sensation of two winos
+ alone in a steel mill!
+
+Perhaps this has something to do with any hobbies you have?
+
+Awright, which one of you hid my PENIS ENVY?
+
+Are you sure that is it that when I die me cannot take my home
+entertainment center with me?
+
+My EARS are GONE!!
+
+Possibly your sex life are related to this.
+
+It's the land of DONNY AND MARIE as promised in TV GUIDE!
+
+Are you afraid of that?
+
+My TOYOTA is built like a ... BAGEL with CREAM CHEESE!!
+
+Do you really think built might want to have this bagel?
+
+I wonder if I could ever get started in the credit world?
+
+Earlier you said comes just before I see the total at the safeway
+checkout counter?
+
+TATTOOED MIDGETS are using ALFREDO in their SALAMI FACTORY!
+
+Is it because of hangups you have that you are going through all this?
+
+I LIKE Aisle 7a.
+
+What makes you think you like aisle 7a?
+
+Youth of today! Join me in a mass rally for traditional mental attitudes!
+
+You mentioned that you work for ding dongs?
+
+Yow! Did something bad happen or am I in a drive-in movie??
+
+How do you reconcile your inhibitions?
+
+Vote for ME -- I'm well-tapered, half-cocked, ill-conceived and
+ TAX-DEFERRED!
+
+Why do you say that?
+
+Are we THERE yet?!
+
+What makes you believe is it that when I die me cannot take my home
+entertainment center with me?
+
+Is it FUN to be a MIDGET?
+
+Maybe this is related to some problems in your childhood?
+
+I left my WALLET in the BATHROOM!!
+
+Is it because of some problems at home that you say you left your
+wallet in the bathroom?
+
+Spreading peanut butter reminds me of opera!! I wonder why?
+
+Can you elaborate on that?
+
+Dizzy, are we "REAL PEOPLE" or "AMAZING ANIMALS"?
+
+Earlier you said built would like to have this bagel?
+
+My LESLIE GORE record is BROKEN..
+
+Perhaps your plans could have caused this.
+
+With YOU, I can be MYSELF.. We don't NEED Dan Rather..
+
+Are you sure that you do not need dan rather?
+
+Yow!
+
+Yow! Are we interactive yet?
+
+You must be a CUB SCOUT!! Have you made your MONEY-DROP today??
+
+You mentioned that comes just before I see the total at the safeway
+checkout counter?
+
+It's the RINSE CYCLE!! They've ALL IGNORED the RINSE CYCLE!!
+
+Is it because of your life that you are going through all this?
+
+There's a little picture of ED MCMAHON doing BAD THINGS to JOAN RIVERS
+ in a $200,000 MALIBU BEACH HOUSE!!
+
+I don't understand.
+
+FISH-NET-FISH-NET-FISH-NET-FISH-NET-FISH!!
+
+Do you really think you work for ding dongs?
+
+NATHAN... your PARENTS were in a CARCRASH!!
+ They're VOIDED - They COLLAPSED
+ They had no CHAINSAWS... They had no MONEY MACHINES...
+ They did PILLS in SKIMPY GRASS SKIRTS...
+ Nathan, I EMULATED them... but they were OFF-KEY...
+
+Is the fact that they were off key the real reason?
+
+I want you to MEMORIZE the collected poems of EDNA ST VINCENT MILLAY..
+ BACKWARDS!!
+
+I would appreciate it if you would continue.
+
+Now KEN is having a MENTAL CRISIS beacuse his "R.V." PAYMENTS are
+ OVER-DUE!!
+
diff --git a/tests/changes.input/05.in b/tests/changes.input/05.in
new file mode 100644
index 0000000..c6d6974
--- /dev/null
+++ b/tests/changes.input/05.in
Binary files differ
diff --git a/tests/changes.input/06.in b/tests/changes.input/06.in
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/changes.input/06.in
diff --git a/tests/changes.input/07.in b/tests/changes.input/07.in
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/tests/changes.input/07.in
@@ -0,0 +1 @@
+hello
diff --git a/tests/changes.test b/tests/changes.test
new file mode 100755
index 0000000..81acdfe
--- /dev/null
+++ b/tests/changes.test
@@ -0,0 +1,40 @@
+#! /bin/sh -e
+
+# librsync -- the library for network deltas
+#
+# Copyright (C) 2001, 2014 by Martin Pool <mbp@sourcefrog.net>
+
+# changes.test: Test converting in both directions between each pair of files.
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir='.'
+
+. $srcdir/testcommon.sh
+
+inputdir=$srcdir/changes.input
+
+for buf in $bufsizes
+do
+ old=$inputdir/01.in
+ for new in $inputdir/*.in
+ do
+ for hashopt in '' -Hmd4 -Hblake2
+ do
+ triple_test $buf $old $new $hashopt
+ triple_test $buf $new $old $hashopt
+ done
+ done
+done
diff --git a/tests/check-rdiff b/tests/check-rdiff
new file mode 100755
index 0000000..eb6f9b8
--- /dev/null
+++ b/tests/check-rdiff
@@ -0,0 +1,44 @@
+#!/usr/bin/perl
+# Creates a pair of semi-random files and check if rdiff
+# correctlys updates the first to the second.
+
+# script is "./g"
+
+$size = 5 << 30;
+$blocklen = 6000;
+
+use Getopt::Long;
+GetOptions("size=i" => \$size,
+ "blocklen=i" => \$blocklen);
+
+$runlen = $blocklen / 3;
+
+sub makefile { # Make a moderately random $size-byte file
+ ($fname,$size)=@_;
+ print "Creating: $fname ($size bytes)\n";
+ open OUT,">$fname" or die "Can't open $fname";
+ for $i (1..$size/$runlen) {
+ $ch = chr(32+int(rand(127))) ;
+ print OUT ($ch x $runlen);
+ }
+ $ch = chr(32+int(rand(127))) ;
+ print OUT ($ch x ($size % $runlen));
+}
+
+sub run {
+ ($cmd)=@_;
+ print "Running: $cmd\n";
+ system($cmd)==0 or die "FAILED!";
+}
+
+srand(0);
+makefile('old',$size);
+makefile('new',$size);
+run("time rdiff signature -b $blocklen old old.sig");
+run("time rdiff delta -s old.sig new delta");
+run("time rdiff patch -s old delta new2");
+print "Comparing MD5 hashes...\n";
+$sum1 = `md5sum < new`; die 'Failed 1' unless $?==0; print $sum1;
+$sum2 = `md5sum < new2`; die 'Failed 2' unless $?==0; print $sum2;
+die "DIFFERENT\n" unless $sum1==$sum2;
+print "SUCCESS\n"
diff --git a/tests/checksum_test.c b/tests/checksum_test.c
new file mode 100644
index 0000000..fdef2f3
--- /dev/null
+++ b/tests/checksum_test.c
@@ -0,0 +1,158 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * checksum_test -- tests for the checksum wrappers.
+ *
+ * Copyright (C) 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Force DEBUG on so that tests can use assert(). */
+#undef NDEBUG
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+#include "checksum.h"
+
+/* Test driver for rollsum. */
+int main(int argc, char **argv)
+{
+ weaksum_t r;
+ unsigned char buf[256];
+
+ /* Initialize buf for use by tests. */
+ for (int i = 0; i < 256; i++)
+ buf[i] = (unsigned char)i;
+
+ /* RS_ROLLSUM weaksum tests. */
+
+ /* Test weaksum_init(). */
+ weaksum_init(&r, RS_ROLLSUM);
+ assert(r.kind == RS_ROLLSUM);
+ assert(weaksum_count(&r) == 0);
+ assert(weaksum_digest(&r) == mix32(0x00000000));
+
+ /* Test weaksum_rollin() */
+ weaksum_rollin(&r, 0); /* [0] */
+ assert(weaksum_count(&r) == 1);
+ assert(weaksum_digest(&r) == mix32(0x001f001f));
+ weaksum_rollin(&r, 1);
+ weaksum_rollin(&r, 2);
+ weaksum_rollin(&r, 3); /* [0,1,2,3] */
+ assert(weaksum_count(&r) == 4);
+ assert(weaksum_digest(&r) == mix32(0x01400082));
+
+ /* Test weaksum_rotate() */
+ weaksum_rotate(&r, 0, 4); /* [1,2,3,4] */
+ assert(weaksum_count(&r) == 4);
+ assert(weaksum_digest(&r) == mix32(0x014a0086));
+ weaksum_rotate(&r, 1, 5);
+ weaksum_rotate(&r, 2, 6);
+ weaksum_rotate(&r, 3, 7); /* [4,5,6,7] */
+ assert(weaksum_count(&r) == 4);
+ assert(weaksum_digest(&r) == mix32(0x01680092));
+
+ /* Test weaksum_rollout() */
+ weaksum_rollout(&r, 4); /* [5,6,7] */
+ assert(weaksum_count(&r) == 3);
+ assert(weaksum_digest(&r) == mix32(0x00dc006f));
+ weaksum_rollout(&r, 5);
+ weaksum_rollout(&r, 6);
+ weaksum_rollout(&r, 7); /* [] */
+ assert(weaksum_count(&r) == 0);
+ assert(weaksum_digest(&r) == mix32(0x00000000));
+
+ /* Test weaksum_update() */
+ weaksum_update(&r, buf, 256);
+ assert(weaksum_digest(&r) == mix32(0x3a009e80));
+
+ /* Test weaksum_reset() */
+ weaksum_reset(&r);
+ assert(r.kind == RS_ROLLSUM);
+ assert(weaksum_count(&r) == 0);
+ assert(weaksum_digest(&r) == mix32(0x00000000));
+
+ /* RS_RABINKARP weaksum tests. */
+
+ /* Test weaksum_init(). */
+ weaksum_init(&r, RS_RABINKARP);
+ assert(r.kind == RS_RABINKARP);
+ assert(weaksum_count(&r) == 0);
+ assert(weaksum_digest(&r) == 0x00000001);
+
+ /* Test weaksum_rollin() */
+ weaksum_rollin(&r, 0); /* [0] */
+ assert(weaksum_count(&r) == 1);
+ assert(weaksum_digest(&r) == 0x08104225);
+ weaksum_rollin(&r, 1);
+ weaksum_rollin(&r, 2);
+ weaksum_rollin(&r, 3); /* [0,1,2,3] */
+ assert(weaksum_count(&r) == 4);
+ assert(weaksum_digest(&r) == 0xaf981e97);
+
+ /* Test weaksum_rotate() */
+ weaksum_rotate(&r, 0, 4); /* [1,2,3,4] */
+ assert(weaksum_count(&r) == 4);
+ assert(weaksum_digest(&r) == 0xe2ef15f3);
+ weaksum_rotate(&r, 1, 5);
+ weaksum_rotate(&r, 2, 6);
+ weaksum_rotate(&r, 3, 7); /* [4,5,6,7] */
+ assert(weaksum_count(&r) == 4);
+ assert(weaksum_digest(&r) == 0x7cf3fc07);
+
+ /* Test weaksum_rollout() */
+ weaksum_rollout(&r, 4); /* [5,6,7] */
+ assert(weaksum_count(&r) == 3);
+ assert(weaksum_digest(&r) == 0xf284a77f);
+ weaksum_rollout(&r, 5);
+ weaksum_rollout(&r, 6);
+ weaksum_rollout(&r, 7); /* [] */
+ assert(weaksum_count(&r) == 0);
+ assert(weaksum_digest(&r) == 0x00000001);
+
+ /* Test weaksum_update() */
+ weaksum_update(&r, buf, 256);
+ assert(weaksum_digest(&r) == 0xc1972381);
+
+ /* Test weaksum_reset() */
+ weaksum_reset(&r);
+ assert(r.kind == RS_RABINKARP);
+ assert(weaksum_count(&r) == 0);
+ assert(weaksum_digest(&r) == 0x00000001);
+
+ /* Test rs_calc_weaksum() */
+ assert(rs_calc_weak_sum(RS_ROLLSUM, buf, 256) == 0x3a009e80);
+ assert(rs_calc_weak_sum(RS_RABINKARP, buf, 256) == 0xc1972381);
+
+ /* Test rs_calc_strongsum() */
+ rs_strong_sum_t sum;
+ const unsigned char md4[16] = {
+ 0x29, 0x8a, 0x05, 0xbc, 0x50, 0x6e, 0x1e, 0xcd,
+ 0x5a, 0x47, 0xfd, 0x41, 0xf8, 0x74, 0xf1, 0xd2,
+ };
+ const unsigned char bk2[32] = {
+ 0x39, 0xa7, 0xeb, 0x9f, 0xed, 0xc1, 0x9a, 0xab,
+ 0xc8, 0x34, 0x25, 0xc6, 0x75, 0x5d, 0xd9, 0x0e,
+ 0x6f, 0x9d, 0x0c, 0x80, 0x49, 0x64, 0xa1, 0xf4,
+ 0xaa, 0xee, 0xa3, 0xb9, 0xfb, 0x59, 0x98, 0x35,
+ };
+
+ rs_calc_strong_sum(RS_MD4, buf, 256, &sum);
+ assert(!memcmp(sum, md4, RS_MD4_SUM_LENGTH));
+ rs_calc_strong_sum(RS_BLAKE2, buf, 256, &sum);
+ assert(!memcmp(sum, bk2, RS_BLAKE2_SUM_LENGTH));
+ return 0;
+}
diff --git a/tests/delta.input/01.delta b/tests/delta.input/01.delta
new file mode 100644
index 0000000..be24e37
--- /dev/null
+++ b/tests/delta.input/01.delta
Binary files differ
diff --git a/tests/delta.input/01.expect b/tests/delta.input/01.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/delta.input/01.expect
diff --git a/tests/delta.input/02.delta b/tests/delta.input/02.delta
new file mode 100644
index 0000000..59f472f
--- /dev/null
+++ b/tests/delta.input/02.delta
Binary files differ
diff --git a/tests/delta.input/02.expect b/tests/delta.input/02.expect
new file mode 100644
index 0000000..b6fc4c6
--- /dev/null
+++ b/tests/delta.input/02.expect
@@ -0,0 +1 @@
+hello
\ No newline at end of file
diff --git a/tests/delta.input/03.delta b/tests/delta.input/03.delta
new file mode 100644
index 0000000..cb1bc9f
--- /dev/null
+++ b/tests/delta.input/03.delta
Binary files differ
diff --git a/tests/delta.input/03.expect b/tests/delta.input/03.expect
new file mode 100644
index 0000000..3b18e51
--- /dev/null
+++ b/tests/delta.input/03.expect
@@ -0,0 +1 @@
+hello world
diff --git a/tests/delta.test b/tests/delta.test
new file mode 100755
index 0000000..64c9d85
--- /dev/null
+++ b/tests/delta.test
@@ -0,0 +1,61 @@
+#! /bin/sh -ex
+
+# librsync -- the library for network deltas
+
+# delta.test: Check application of some canned deltas to /dev/null
+
+# Copyright (C) 1999, 2000, 2001, 2014 by Martin Pool <mbp@sourcefrog.net>
+# Copyright (C) 1999 by Andrew Tridgell <tridge@samba.org>
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir='.'
+
+. $srcdir/testcommon.sh
+
+new=$tmpdir/delta.tmp
+
+inputdir=$srcdir/delta.input
+
+for delta in $inputdir/*.delta
+do
+ for inbuf in $bufsizes
+ do
+ cmd="$bindir/rdiff -I$inbuf -f patch /dev/null $delta $new"
+ run_test $cmd
+ expect=$inputdir/`basename $delta .delta`.expect
+ check_compare $expect $new
+ done
+done
+
+# Make sure rdiff can't overwrite files if ran without -f
+# RS_IO_ERROR == 100 should be returned if file exists
+RS_IO_ERROR=100
+output_expect="File exists \".*\", aborting!"
+expect=$tmpdir/delta_new.tmp
+ret=0
+
+# Change $new and rerun last test to check it won't be reverted
+echo "$output_expect" > $expect
+echo "$output_expect" > $new
+cmd="$bindir/rdiff patch /dev/null $delta $new"
+echo " $cmd" >&2
+output="`$cmd 2>&1`" || ret=$?
+[ "$ret" -eq "$RS_IO_ERROR" ] ||
+ fail_test "$ret" "RS_IO_ERROR ($RS_IO_ERROR) not returned while trying to overwrite existing file"
+[ "$(echo "$output" | grep -c "$output_expect")" -gt 0 ] ||
+ fail_test "$output" "\"$output_expect\" not returned when trying to overwrite files without --force"
+# Check the file has not changed
+check_compare $expect $new
diff --git a/tests/hashtable_test.c b/tests/hashtable_test.c
new file mode 100644
index 0000000..016acbe
--- /dev/null
+++ b/tests/hashtable_test.c
@@ -0,0 +1,180 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * hashtable_test -- tests for the hashtable.
+ *
+ * Copyright (C) 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Force DEBUG on so that tests can use assert(). */
+#undef NDEBUG
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include "hashtable.h"
+
+/* Key type for the hashtable. */
+typedef int mykey_t;
+void mykey_init(mykey_t *k, int i)
+{
+ /* This is chosen to cause bad key collisions and clustering. */
+ *k = (i / 2) * (i / 2);
+}
+
+int mykey_hash(const mykey_t *k)
+{
+ return *k;
+}
+
+int mykey_cmp(mykey_t *k, const mykey_t *o)
+{
+ return *k - *o;
+}
+
+/* Entry type for values in hashtable. */
+typedef struct myentry {
+ mykey_t key; /* Inherit from mykey_t. */
+ int value;
+} myentry_t;
+
+void myentry_init(myentry_t *e, int i)
+{
+ mykey_init(&e->key, i);
+ e->value = i;
+}
+
+/* Match type for finding matching entries in hashtable.
+
+ This demonstrates using deferred calculation and comparison of the expected
+ value only when the key matches. */
+typedef struct mymatch {
+ mykey_t key; /* Inherit from mykey_t. */
+ int value;
+ int source;
+} mymatch_t;
+
+void mymatch_init(mymatch_t *m, int i)
+{
+ mykey_init(&m->key, i);
+ m->value = 0;
+ m->source = i;
+}
+
+int mymatch_cmp(mymatch_t *m, const myentry_t *e)
+{
+ int ans = mykey_cmp(&m->key, &e->key);
+ /* Calculate and compare value if key matches */
+ if (ans == 0) {
+ if (m->value != m->source)
+ m->value = m->source;
+ ans = m->value - e->value;
+ }
+ return ans;
+}
+
+/* Instantiate a simple mykey_hashtable of keys. */
+#define ENTRY mykey
+#include "hashtable.h"
+
+/* Instantiate a fancy myhashtable of myentrys using a custom match. */
+#define ENTRY myentry
+#define KEY mykey
+#define MATCH mymatch
+#define NAME myhashtable
+#include "hashtable.h"
+
+/* Test driver for hashtable. */
+int main(int argc, char **argv)
+{
+ /* Test mykey_hashtable instance. */
+ hashtable_t *kt;
+ int ki;
+ mykey_t k1, k2;
+
+ mykey_init(&k1, 1);
+ mykey_init(&k2, 2);
+ assert((kt = mykey_hashtable_new(16)) != NULL);
+ assert(mykey_hashtable_add(kt, &k1) == &k1);
+ assert(mykey_hashtable_find(kt, &k1) == &k1);
+ assert(mykey_hashtable_find(kt, &k2) == NULL);
+ assert(mykey_hashtable_iter(kt, &ki) == &k1);
+ assert(mykey_hashtable_next(kt, &ki) == NULL);
+
+ /* Test myhashtable instance. */
+ hashtable_t *t;
+ myentry_t entry[256];
+ myentry_t e;
+ mymatch_t m;
+ int i;
+
+ myentry_init(&e, 0);
+ for (i = 0; i < 256; i++)
+ myentry_init(&entry[i], i);
+
+ /* Test myhashtable_new() */
+ t = myhashtable_new(256);
+ assert(t->size == 512);
+ assert(t->count == 0);
+ assert(t->etable != NULL);
+ assert(t->ktable != NULL);
+
+ /* Test myhashtable_add() */
+ assert(myhashtable_add(t, &e) == &e); /* Added duplicated copy. */
+ assert(myhashtable_add(t, &entry[0]) == &entry[0]); /* Added duplicated
+ instance. */
+ for (i = 0; i < 256; i++)
+ assert(myhashtable_add(t, &entry[i]) == &entry[i]);
+ assert(t->count == 258);
+
+ /* Test myhashtable_find() */
+ mymatch_init(&m, 0);
+ assert(myhashtable_find(t, &m) == &e); /* Finds first duplicate added.
+ */
+ assert(m.value == m.source); /* mymatch_cmp() updated m.value. */
+ for (i = 1; i < 256; i++) {
+ mymatch_init(&m, i);
+ assert(myhashtable_find(t, &m) == &entry[i]);
+ assert(m.value == m.source); /* mymatch_cmp() updated m.value. */
+ }
+ mymatch_init(&m, 256);
+ assert(myhashtable_find(t, &m) == NULL); /* Find missing myentry. */
+ assert(m.value == 0); /* mymatch_cmp() didn't update m.value. */
+#ifndef HASHTABLE_NSTATS
+ assert(t->find_count == 257);
+ assert(t->match_count == 256);
+ assert(t->hashcmp_count >= 256);
+ assert(t->entrycmp_count >= 256);
+ myhashtable_stats_init(t);
+ assert(t->find_count == 0);
+ assert(t->match_count == 0);
+ assert(t->hashcmp_count == 0);
+ assert(t->entrycmp_count == 0);
+#endif
+
+ /* Test hashtable iterators */
+ myentry_t *p;
+ int iter;
+ int count = 0;
+ for (p = myhashtable_iter(t, &iter); p != NULL;
+ p = myhashtable_next(t, &iter)) {
+ assert(p == &e || (&entry[0] <= p && p <= &entry[255]));
+ count++;
+ }
+ assert(count == 258);
+ myhashtable_free(t);
+
+ return 0;
+}
diff --git a/tests/help.test b/tests/help.test
new file mode 100755
index 0000000..93efd02
--- /dev/null
+++ b/tests/help.test
@@ -0,0 +1,30 @@
+#! /bin/sh -e
+
+# librsync -- the library for network deltas
+#
+# help.test: Test that `rdiff --help` etc work reasonably.
+
+# Copyright 2014 by Martin Pool <mbp@sourcefrog.net>
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir='.'
+. $srcdir/testcommon.sh
+
+run_test $bindir/rdiff --help
+run_test $bindir/rdiff --version
+
+run_test $bindir/rdiff --help | grep ' --statistics'
+run_test $bindir/rdiff --version | grep 'Copyright'
diff --git a/tests/isprefix.h b/tests/isprefix.h
new file mode 100644
index 0000000..a5904a6
--- /dev/null
+++ b/tests/isprefix.h
@@ -0,0 +1,22 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ * librsync -- dynamic caching and delta update in HTTP
+ *
+ * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Return true if TIP is a prefix of ICEBERG. */
+int isprefix(char const *tip, char const *iceberg);
diff --git a/tests/isprefix_test.c b/tests/isprefix_test.c
new file mode 100644
index 0000000..6590a5f
--- /dev/null
+++ b/tests/isprefix_test.c
@@ -0,0 +1,45 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ * librsync -- dynamic caching and delta update in HTTP
+ *
+ * Copyright (C) 2000 by Martin Pool <mbp@sourcefrog.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Force DEBUG on so that tests can use assert(). */
+#undef NDEBUG
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "isprefix.h"
+
+/* Test driver for isprefix. */
+int main(int argc, char **argv)
+{
+ assert(isprefix("foo", "foobar"));
+ assert(isprefix("", "foobar"));
+ assert(isprefix("foobar", "foobar"));
+ assert(isprefix("", ""));
+ assert(isprefix("f", "foorbar"));
+
+ assert(!isprefix("foobar", "foo"));
+ assert(!isprefix("goo", "foo"));
+ assert(!isprefix("foo", ""));
+ assert(!isprefix("f", "g"));
+
+ return 0;
+}
diff --git a/tests/largefile.test b/tests/largefile.test
new file mode 100755
index 0000000..4d062d4
--- /dev/null
+++ b/tests/largefile.test
@@ -0,0 +1,64 @@
+#! /bin/sh -e
+#
+# librsync -- the library for network deltas
+# Copyright (C) 2001, 2014 by Martin Pool <mbp@sourcefrog.net>
+#
+# largefile.test: Generate some large random files with 50% matches
+# and generate signature, delta, and patch files, comparing for
+# correctness.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Note this test is not included in make check because it creates very
+# large data files and takes a long time.
+
+srcdir='.'
+. $srcdir/testcommon.sh
+
+# Note $1 is used to specify "BINDIR" by cmake tests, so we use
+# arguments after that.
+
+# Allow the number of blocks to be specified in $2 in the form '64K'.
+blocks=${2:-64K}
+
+# Allow a data directory to be specified in $3 to use persistent
+# random data files to make tests more repeatable, otherwise use
+# $tmpdir.
+datadir=${3:-$tmpdir}
+echo "DATADIR $datadir"
+
+# Use $4 to optionally specify a block size to use.
+blocksize=${4:-1024}
+
+old="$datadir/old.$blocks"
+new="$datadir/new.$blocks"
+sig="$datadir/sig.$blocks"
+delta="$datadir/delta.$blocks"
+out="$datadir/out.$blocks"
+
+if [ ! -f "$old" ]; then
+ mkdir -p $datadir
+ dd bs=$blocks count=1024 if=/dev/urandom >"$old"
+ dd bs=$blocks count=256 if=/dev/urandom >"$new"
+ dd bs=$blocks count=256 skip=128 if="$old" >>"$new"
+ dd bs=$blocks count=256 if=/dev/urandom >>"$new"
+ dd bs=$blocks count=256 skip=640 if="$old" >>"$new"
+fi
+
+run_test time $bindir/rdiff $debug -f -s -b $blocksize -S 8 signature $old $sig
+run_test time $bindir/rdiff $debug -f -s delta $sig $new $delta
+run_test time $bindir/rdiff $debug -f -s patch $old $delta $out
+check_compare $new $out "large files"
+true
diff --git a/tests/mdfour.input/01.data b/tests/mdfour.input/01.data
new file mode 100644
index 0000000..1497d56
--- /dev/null
+++ b/tests/mdfour.input/01.data
@@ -0,0 +1 @@
+Sun Dec 3 17:03:18 PST 2000
diff --git a/tests/mdfour.input/01.expect b/tests/mdfour.input/01.expect
new file mode 100644
index 0000000..2f8da48
--- /dev/null
+++ b/tests/mdfour.input/01.expect
@@ -0,0 +1 @@
+0df1847ec72b1683956389cca2477d8e
diff --git a/tests/mutate.pl b/tests/mutate.pl
new file mode 100644
index 0000000..bc3dc63
--- /dev/null
+++ b/tests/mutate.pl
@@ -0,0 +1,64 @@
+#! /usr/bin/perl -w
+
+# librsync -- the library for network deltas
+#
+# Copyright (C) 1999, 2000 by Martin Pool <mbp@sourcefrog.net>
+# Copyright (C) 1999 by Andrew Tridgell <tridge@samba.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# mutate: makes a random smalll change to an input file and writes it
+# to stdout.
+
+use strict;
+
+if ($#ARGV != 1) {
+ print STDERR "usage: mutate.pl SEED MUTATIONS <BASIS\n";
+ exit 1;
+}
+
+srand shift @ARGV;
+my $n_muts = 1 + int rand shift @ARGV;
+
+undef $/; # slurp whole file
+my $corpus = <STDIN>;
+
+printf STDERR "%d mutations\n", $n_muts;
+
+while ($n_muts-- > 0) {
+ my $in_len = length($corpus);
+
+ my $from_off = int rand $in_len;
+ my $from_len = int(rand(1.0) * rand($in_len));
+ my $to_off = int rand $in_len;
+ my $to_len = int(rand(1.0) * rand($in_len));
+
+ my $op = rand 3;
+ if ($op < 1.0) {
+ printf STDERR "copy and overwrite";
+ substr($corpus, $to_off, $to_len) = substr($corpus, $from_off, $from_len);
+ } elsif ($op < 2.0) {
+ print STDERR "copy and insert";
+ substr($corpus, $to_off, 0) = substr($corpus, $from_off, $from_len);
+ } else {
+ print STDERR "delete";
+ substr($corpus, $to_off, $to_len) = '';
+ }
+
+ printf STDERR " (%d, %d) -> (%d, %d)\n", $from_off, $from_len, $to_off, $to_len;
+}
+
+print $corpus;
+
diff --git a/tests/mutate.test b/tests/mutate.test
new file mode 100755
index 0000000..9809e89
--- /dev/null
+++ b/tests/mutate.test
@@ -0,0 +1,60 @@
+#! /bin/sh -e
+
+# librsync -- the library for network deltas
+# Copyright (C) 2001, 2014 by Martin Pool <mbp@sourcefrog.net>
+
+# mutate.test: Make some deterministic pseudorandom changes to a file and
+# compute deltas across them.
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir='.'
+
+. $srcdir/testcommon.sh
+
+old=$srcdir/COPYING
+
+if which perl >/dev/null
+then
+ :
+else
+ echo "Skipped because perl was not found";
+ exit 77;
+fi
+
+old="$tmpdir/old"
+cat $srcdir/*.[ch] >"$old"
+new="$tmpdir/new"
+sig="$tmpdir/sig"
+delta="$tmpdir/delta"
+out="$tmpdir/out"
+i=0
+
+while test $i -lt 100
+do
+ perl "$srcdir/mutate.pl" $i 5 <"$old" >"$new" 2>>"$tmpdir/mutate.log"
+
+ for hashopt in '' -Hmd4 -Hblake2
+ do
+ run_test $bindir/rdiff -f $debug $hashopt signature $old $sig
+ run_test $bindir/rdiff -f $debug delta $sig $new $delta
+ run_test $bindir/rdiff -f $debug patch $old $delta $out
+
+ check_compare "$new" "$out" "mutate $i $old $new"
+ done
+
+ i=`expr $i + 1`
+done
+true
diff --git a/tests/netint_test.c b/tests/netint_test.c
new file mode 100644
index 0000000..e25b582
--- /dev/null
+++ b/tests/netint_test.c
@@ -0,0 +1,49 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ * librsync -- dynamic caching and delta update in HTTP
+ *
+ * Copyright (C) 2019 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Force DEBUG on so that tests can use assert(). */
+#undef NDEBUG
+#include <assert.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "librsync.h"
+#include "netint.h"
+
+/* Test driver for netint. */
+int main(int argc, char **argv)
+{
+ assert(rs_int_len((rs_long_t)0) == 1);
+ assert(rs_int_len((rs_long_t)1) == 1);
+ assert(rs_int_len((rs_long_t)INT8_MAX) == 1);
+ assert(rs_int_len((rs_long_t)1 << 7) == 1);
+ assert(rs_int_len((rs_long_t)1 << 8) == 2);
+ assert(rs_int_len((rs_long_t)INT16_MAX) == 2);
+#ifdef INT32_MAX
+ assert(rs_int_len((rs_long_t)1 << 15) == 2);
+ assert(rs_int_len((rs_long_t)1 << 16) == 4);
+ assert(rs_int_len((rs_long_t)INT32_MAX) == 4);
+#endif
+#ifdef INT64_MAX
+ assert(rs_int_len((rs_long_t)1 << 31) == 4);
+ assert(rs_int_len((rs_long_t)1 << 32) == 8);
+ assert(rs_int_len((rs_long_t)INT64_MAX) == 8);
+#endif
+ return 0;
+}
diff --git a/tests/performance.test b/tests/performance.test
new file mode 100755
index 0000000..e5b6736
--- /dev/null
+++ b/tests/performance.test
@@ -0,0 +1,48 @@
+#! /bin/sh -e
+#
+# librsync -- the library for network deltas
+# Copyright (C) 2001, 2014 by Martin Pool <mbp@sourcefrog.net>
+#
+# performance.test: Run largefile.test with a variety of different
+# numbers of blocks, using persistent data files in /tmp so the tests
+# are repeatable.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Note this test is not included in make check because it creates very
+# large data files that are not deleted and takes a long time.
+
+srcdir='.'
+. $srcdir/testcommon.sh
+
+# Note $1 is used to specify "BINDIR" by cmake tests, so we use
+# arguments after that.
+
+# Allow a data directory to be specified in $2 to use persistent
+# random data files to make tests more repeatable, otherwise use
+# /tmp.
+datadir=${2:-/tmp}
+echo "DATADIR $datadir"
+
+run_test () {
+ echo $1 blocks of 1K size.
+ echo ========================
+ $srcdir/largefile.test $bindir $1 $2
+ echo
+}
+
+for size in 32K 44K 51K 64K 716K 1024K; do
+ run_test $size $datadir
+done;
diff --git a/tests/rabinkarp_perf.c b/tests/rabinkarp_perf.c
new file mode 100644
index 0000000..f3b52fd
--- /dev/null
+++ b/tests/rabinkarp_perf.c
@@ -0,0 +1,42 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * rabinkarp_perf -- peformance tests for the rabinkarp checksum.
+ *
+ * Copyright (C) 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include "rabinkarp.h"
+
+int main(int argc, char **argv)
+{
+ rabinkarp_t r;
+ int i;
+ uint8_t buf[1024];
+ uint32_t sum;
+
+ rabinkarp_init(&r);
+ for (i = 0; i < 1024 * 1024; i++) {
+ fread(buf, 1024, 1, stdin);
+ rabinkarp_update(&r, buf, 1024);
+ }
+ sum = rabinkarp_digest(&r);
+ printf("%08" PRIx32 "\n", sum);
+ return 0;
+}
diff --git a/tests/rabinkarp_test.c b/tests/rabinkarp_test.c
new file mode 100644
index 0000000..d0ac6c4
--- /dev/null
+++ b/tests/rabinkarp_test.c
@@ -0,0 +1,77 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * rabinkarp_test -- tests for the rabinkarp_t rolling checksum.
+ *
+ * Copyright (C) 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Force DEBUG on so that tests can use assert(). */
+#undef NDEBUG
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include "rabinkarp.h"
+
+int main(int argc, char **argv)
+{
+ rabinkarp_t r;
+ int i;
+ unsigned char buf[256];
+
+ /* Test rabinkarp_init() */
+ rabinkarp_init(&r);
+ assert(r.count == 0);
+ assert(r.hash == 1);
+ assert(rabinkarp_digest(&r) == 0x00000001);
+
+ /* Test rabinkarp_rollin() */
+ rabinkarp_rollin(&r, 0); /* [0] */
+ assert(r.count == 1);
+ assert(rabinkarp_digest(&r) == 0x08104225);
+ rabinkarp_rollin(&r, 1);
+ rabinkarp_rollin(&r, 2);
+ rabinkarp_rollin(&r, 3); /* [0,1,2,3] */
+ assert(r.count == 4);
+ assert(rabinkarp_digest(&r) == 0xaf981e97);
+
+ /* Test rabinkarp_rotate() */
+ rabinkarp_rotate(&r, 0, 4); /* [1,2,3,4] */
+ assert(r.count == 4);
+ assert(rabinkarp_digest(&r) == 0xe2ef15f3);
+ rabinkarp_rotate(&r, 1, 5);
+ rabinkarp_rotate(&r, 2, 6);
+ rabinkarp_rotate(&r, 3, 7); /* [4,5,6,7] */
+ assert(r.count == 4);
+ assert(rabinkarp_digest(&r) == 0x7cf3fc07);
+
+ /* Test rabinkarp_rollout() */
+ rabinkarp_rollout(&r, 4); /* [5,6,7] */
+ assert(r.count == 3);
+ assert(rabinkarp_digest(&r) == 0xf284a77f);
+ rabinkarp_rollout(&r, 5);
+ rabinkarp_rollout(&r, 6);
+ rabinkarp_rollout(&r, 7); /* [] */
+ assert(r.count == 0);
+ assert(rabinkarp_digest(&r) == 0x00000001);
+
+ /* Test rabinkarp_update() */
+ for (i = 0; i < 256; i++)
+ buf[i] = (unsigned char)i;
+ rabinkarp_update(&r, buf, 256);
+ assert(rabinkarp_digest(&r) == 0xc1972381);
+ return 0;
+}
diff --git a/tests/rdiff_bad_option.sh b/tests/rdiff_bad_option.sh
new file mode 100755
index 0000000..b29e3bd
--- /dev/null
+++ b/tests/rdiff_bad_option.sh
@@ -0,0 +1,28 @@
+#! /bin/sh -ex
+
+# librsync -- the library for network deltas
+
+# Copyright (C) 2016 by Martin Pool
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+# Bad command-line options return an error and print a message.
+
+errout=`mktemp -t rdiff_bad_option_test_XXXXXXX`
+trap "rm $errout" EXIT
+! $1/rdiff --imaginary-option 2>"$errout"
+cat "$errout"
+grep 'unknown option: --imaginary-option' "$errout"
diff --git a/tests/rollsum_test.c b/tests/rollsum_test.c
new file mode 100644
index 0000000..109d9fc
--- /dev/null
+++ b/tests/rollsum_test.c
@@ -0,0 +1,79 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * rollsum_test -- tests for the librsync rolling checksum.
+ *
+ * Copyright (C) 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Force DEBUG on so that tests can use assert(). */
+#undef NDEBUG
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include "rollsum.h"
+
+/* Test driver for rollsum. */
+int main(int argc, char **argv)
+{
+ Rollsum r;
+ int i;
+ unsigned char buf[256];
+
+ /* Test RollsumInit() */
+ RollsumInit(&r);
+ assert(r.count == 0);
+ assert(r.s1 == 0);
+ assert(r.s2 == 0);
+ assert(RollsumDigest(&r) == 0x00000000);
+
+ /* Test RollsumRollin() */
+ RollsumRollin(&r, 0); /* [0] */
+ assert(r.count == 1);
+ assert(RollsumDigest(&r) == 0x001f001f);
+ RollsumRollin(&r, 1);
+ RollsumRollin(&r, 2);
+ RollsumRollin(&r, 3); /* [0,1,2,3] */
+ assert(r.count == 4);
+ assert(RollsumDigest(&r) == 0x01400082);
+
+ /* Test RollsumRotate() */
+ RollsumRotate(&r, 0, 4); /* [1,2,3,4] */
+ assert(r.count == 4);
+ assert(RollsumDigest(&r) == 0x014a0086);
+ RollsumRotate(&r, 1, 5);
+ RollsumRotate(&r, 2, 6);
+ RollsumRotate(&r, 3, 7); /* [4,5,6,7] */
+ assert(r.count == 4);
+ assert(RollsumDigest(&r) == 0x01680092);
+
+ /* Test RollsumRollout() */
+ RollsumRollout(&r, 4); /* [5,6,7] */
+ assert(r.count == 3);
+ assert(RollsumDigest(&r) == 0x00dc006f);
+ RollsumRollout(&r, 5);
+ RollsumRollout(&r, 6);
+ RollsumRollout(&r, 7); /* [] */
+ assert(r.count == 0);
+ assert(RollsumDigest(&r) == 0x00000000);
+
+ /* Test RollsumUpdate() */
+ for (i = 0; i < 256; i++)
+ buf[i] = (unsigned char)i;
+ RollsumUpdate(&r, buf, 256);
+ assert(RollsumDigest(&r) == 0x3a009e80);
+ return 0;
+}
diff --git a/tests/signature.input/01-Rrabinkarp-Hblake2-S-1.sig b/tests/signature.input/01-Rrabinkarp-Hblake2-S-1.sig
new file mode 100644
index 0000000..ee0cbe6
--- /dev/null
+++ b/tests/signature.input/01-Rrabinkarp-Hblake2-S-1.sig
Binary files differ
diff --git a/tests/signature.input/01-Rrabinkarp-Hblake2-S0.sig b/tests/signature.input/01-Rrabinkarp-Hblake2-S0.sig
new file mode 100644
index 0000000..7744860
--- /dev/null
+++ b/tests/signature.input/01-Rrabinkarp-Hblake2-S0.sig
Binary files differ
diff --git a/tests/signature.input/01-Rrabinkarp-Hblake2-S8.sig b/tests/signature.input/01-Rrabinkarp-Hblake2-S8.sig
new file mode 100644
index 0000000..0a19edb
--- /dev/null
+++ b/tests/signature.input/01-Rrabinkarp-Hblake2-S8.sig
Binary files differ
diff --git a/tests/signature.input/01-Rrabinkarp-Hmd4-S-1.sig b/tests/signature.input/01-Rrabinkarp-Hmd4-S-1.sig
new file mode 100644
index 0000000..ea90e59
--- /dev/null
+++ b/tests/signature.input/01-Rrabinkarp-Hmd4-S-1.sig
Binary files differ
diff --git a/tests/signature.input/01-Rrabinkarp-Hmd4-S0.sig b/tests/signature.input/01-Rrabinkarp-Hmd4-S0.sig
new file mode 100644
index 0000000..aa08860
--- /dev/null
+++ b/tests/signature.input/01-Rrabinkarp-Hmd4-S0.sig
Binary files differ
diff --git a/tests/signature.input/01-Rrabinkarp-Hmd4-S8.sig b/tests/signature.input/01-Rrabinkarp-Hmd4-S8.sig
new file mode 100644
index 0000000..4c106c5
--- /dev/null
+++ b/tests/signature.input/01-Rrabinkarp-Hmd4-S8.sig
Binary files differ
diff --git a/tests/signature.input/01-Rrollsum-Hblake2-S-1.sig b/tests/signature.input/01-Rrollsum-Hblake2-S-1.sig
new file mode 100644
index 0000000..9c9faec
--- /dev/null
+++ b/tests/signature.input/01-Rrollsum-Hblake2-S-1.sig
Binary files differ
diff --git a/tests/signature.input/01-Rrollsum-Hblake2-S0.sig b/tests/signature.input/01-Rrollsum-Hblake2-S0.sig
new file mode 100644
index 0000000..49966d0
--- /dev/null
+++ b/tests/signature.input/01-Rrollsum-Hblake2-S0.sig
Binary files differ
diff --git a/tests/signature.input/01-Rrollsum-Hblake2-S8.sig b/tests/signature.input/01-Rrollsum-Hblake2-S8.sig
new file mode 100644
index 0000000..43fff97
--- /dev/null
+++ b/tests/signature.input/01-Rrollsum-Hblake2-S8.sig
Binary files differ
diff --git a/tests/signature.input/01-Rrollsum-Hmd4-S-1.sig b/tests/signature.input/01-Rrollsum-Hmd4-S-1.sig
new file mode 100644
index 0000000..c02ec4c
--- /dev/null
+++ b/tests/signature.input/01-Rrollsum-Hmd4-S-1.sig
Binary files differ
diff --git a/tests/signature.input/01-Rrollsum-Hmd4-S0.sig b/tests/signature.input/01-Rrollsum-Hmd4-S0.sig
new file mode 100644
index 0000000..ccd4398
--- /dev/null
+++ b/tests/signature.input/01-Rrollsum-Hmd4-S0.sig
Binary files differ
diff --git a/tests/signature.input/01-Rrollsum-Hmd4-S8.sig b/tests/signature.input/01-Rrollsum-Hmd4-S8.sig
new file mode 100644
index 0000000..28d40a6
--- /dev/null
+++ b/tests/signature.input/01-Rrollsum-Hmd4-S8.sig
Binary files differ
diff --git a/tests/signature.input/01.in b/tests/signature.input/01.in
new file mode 100644
index 0000000..c4792dd
--- /dev/null
+++ b/tests/signature.input/01.in
@@ -0,0 +1,515 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+ When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+^L
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+^L
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, 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 library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+ 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 Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+^L
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+ If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+^L
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be 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.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+^L
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+ 9. 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 Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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 with
+this License.
+^L
+ 11. 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 Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+^L
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+^L
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library.
+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 library's name and a brief idea of what it
+does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper
+mail.
+
+You should also get your employer (if you work as a programmer) or
+your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James
+Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/tests/signature.test b/tests/signature.test
new file mode 100755
index 0000000..82f5aa0
--- /dev/null
+++ b/tests/signature.test
@@ -0,0 +1,43 @@
+#! /bin/sh -e
+
+# librsync -- the library for network deltas
+#
+# signature.test: Test that `rdiff signature` produces the exactly expected
+# output: this is supposed to check that it remains compatible with previous
+# versions.
+
+# Copyright (C) 2001, 2014 by Martin Pool <mbp@sourcefrog.net>
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir='.'
+
+. $srcdir/testcommon.sh
+
+new=$tmpdir/signature
+
+for rollfunc in rollsum rabinkarp; do
+ for hashfunc in md4 blake2; do
+ for stronglen in 0 -1 8; do
+ for input in "$srcdir/signature.input"/*.in; do
+ for inbuf in $bufsizes; do
+ expect=`echo $input | sed -e "s/.in\$/-R${rollfunc}-H${hashfunc}-S${stronglen}.sig/"`
+ run_test $bindir/rdiff -R$rollfunc -H$hashfunc -S$stronglen -I$inbuf -f signature "$input" "$new"
+ check_compare "$expect" "$new"
+ done
+ done
+ done
+ done
+done
diff --git a/tests/sources.test b/tests/sources.test
new file mode 100755
index 0000000..be14e2f
--- /dev/null
+++ b/tests/sources.test
@@ -0,0 +1,43 @@
+#! /bin/sh -e
+
+# librsync -- the library for network deltas
+# Copyright (C) 2001, 2014 by Martin Pool <mbp@sourcefrog.net>
+
+# sources.test: Run three-way tests on all librsync source files.
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir='.'
+
+. $srcdir/testcommon.sh
+block_len=200
+for buf in $bufsizes
+do
+ for old in $srcdir/*.[ch]
+ do
+ for new in $old $old*~
+ do
+ test ! -r $new && continue
+ test ! -r $old && continue
+ test -n "$stats" && echo $old $new
+
+ for hashopt in '' -Hmd4 -Hblake2
+ do
+ triple_test $buf $old $new $hashopt
+ triple_test $buf $new $old $hashopt
+ done
+ done
+ done
+done
diff --git a/tests/sumset_test.c b/tests/sumset_test.c
new file mode 100644
index 0000000..ad8cf28
--- /dev/null
+++ b/tests/sumset_test.c
@@ -0,0 +1,284 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * rollsum_test -- tests for the librsync rolling checksum.
+ *
+ * Copyright (C) 2003 by Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Force DEBUG on so that tests can use assert(). */
+#undef NDEBUG
+#include "config.h"
+#include <string.h>
+#include <assert.h>
+#include "librsync.h"
+#include "sumset.h"
+
+/* Test driver for sumset.c. */
+int main(int argc, char **argv)
+{
+ rs_signature_t sig;
+ rs_result res;
+ rs_weak_sum_t weak = 0x12345678;
+ rs_strong_sum_t strong = "ABCDEF";
+ int i;
+ unsigned char buf[256];
+
+ /* Initialize test buffer. */
+ for (i = 0; i < 256; i++)
+ buf[i] = (unsigned char)i;
+
+ /* Test rs_sig_args() */
+ rs_magic_number magic;
+ size_t block_len, strong_len;
+
+ /* old_fsize=unknown, all recommended. */
+ magic = 0;
+ block_len = 0;
+ strong_len = 0;
+ res = rs_sig_args(-1, &magic, &block_len, &strong_len);
+ assert(res == RS_DONE);
+ assert(magic == RS_RK_BLAKE2_SIG_MAGIC);
+ assert(block_len == 2048);
+ assert(strong_len == 32);
+
+ /* old_fsize=0, all recommended. */
+ magic = 0;
+ block_len = 0;
+ strong_len = 0;
+ res = rs_sig_args(0, &magic, &block_len, &strong_len);
+ assert(res == RS_DONE);
+ assert(magic == RS_RK_BLAKE2_SIG_MAGIC);
+ assert(block_len == 256);
+ assert(strong_len == 32);
+
+ /* old_fsize=100000, magic=rs/md4, block_len=rec, strong_len=rec. */
+ magic = RS_MD4_SIG_MAGIC;
+ block_len = 0;
+ strong_len = 0;
+ res = rs_sig_args(1000000, &magic, &block_len, &strong_len);
+ assert(res == RS_DONE);
+ assert(magic == RS_MD4_SIG_MAGIC);
+ assert(block_len == 896);
+ assert(strong_len == 16);
+
+ /* old_fsize=unknown, magic=rk/b2, block_len=rec, strong_len=min. */
+ magic = RS_RK_BLAKE2_SIG_MAGIC;
+ block_len = 0;
+ strong_len = -1;
+ res = rs_sig_args(-1, &magic, &block_len, &strong_len);
+ assert(res == RS_DONE);
+ assert(magic == RS_RK_BLAKE2_SIG_MAGIC);
+ assert(block_len == 2048);
+ assert(strong_len == 12);
+
+ /* old_fsize=unknown, magic=rs/b2, block_len=1000, strong_len=8. */
+ magic = RS_BLAKE2_SIG_MAGIC;
+ block_len = 1000;
+ strong_len = 8;
+ res = rs_sig_args(-1, &magic, &block_len, &strong_len);
+ assert(res == RS_DONE);
+ assert(magic == RS_BLAKE2_SIG_MAGIC);
+ assert(block_len == 1000);
+ assert(strong_len == 8);
+
+ /* old_fsize=0, magic=rs/md4, block_len=rec, strong_len=min. */
+ magic = RS_RK_MD4_SIG_MAGIC;
+ block_len = 0;
+ strong_len = -1;
+ res = rs_sig_args(0, &magic, &block_len, &strong_len);
+ assert(res == RS_DONE);
+ assert(magic == RS_RK_MD4_SIG_MAGIC);
+ assert(block_len == 256);
+ assert(strong_len == 5);
+
+ /* old_fsize=0, magic=rs/md4, block_len=1000, strong_len=8. */
+ magic = RS_MD4_SIG_MAGIC;
+ block_len = 1000;
+ strong_len = 8;
+ res = rs_sig_args(0, &magic, &block_len, &strong_len);
+ assert(res == RS_DONE);
+ assert(magic == RS_MD4_SIG_MAGIC);
+ assert(block_len == 1000);
+ assert(strong_len == 8);
+
+ /* old_fsize=100000, magic=rs/b2, block_len=rec, strong_len=min. */
+ magic = RS_BLAKE2_SIG_MAGIC;
+ block_len = 0;
+ strong_len = -1;
+ res = rs_sig_args(1000000, &magic, &block_len, &strong_len);
+ assert(res == RS_DONE);
+ assert(magic == RS_BLAKE2_SIG_MAGIC);
+ assert(block_len == 896);
+ assert(strong_len == 7);
+
+ /* old_fsize=100000, magic=rk/md4, block_len=1000, strong_len=8. */
+ magic = RS_RK_MD4_SIG_MAGIC;
+ block_len = 1000;
+ strong_len = 8;
+ res = rs_sig_args(100000, &magic, &block_len, &strong_len);
+ assert(res == RS_DONE);
+ assert(magic == RS_RK_MD4_SIG_MAGIC);
+ assert(block_len == 1000);
+ assert(strong_len == 8);
+
+ /* magic=bad. */
+ magic = 1;
+ block_len = 0;
+ strong_len = 0;
+ res = rs_sig_args(-1, &magic, &block_len, &strong_len);
+ assert(res == RS_BAD_MAGIC);
+
+ /* strong_len=bad. */
+ magic = RS_RK_BLAKE2_SIG_MAGIC;
+ block_len = 0;
+ strong_len = 33;
+ res = rs_sig_args(-1, &magic, &block_len, &strong_len);
+ assert(res == RS_PARAM_ERROR);
+ magic = RS_BLAKE2_SIG_MAGIC;
+ block_len = 0;
+ strong_len = 33;
+ res = rs_sig_args(-1, &magic, &block_len, &strong_len);
+ assert(res == RS_PARAM_ERROR);
+ magic = RS_RK_MD4_SIG_MAGIC;
+ block_len = 0;
+ strong_len = 17;
+ res = rs_sig_args(-1, &magic, &block_len, &strong_len);
+ assert(res == RS_PARAM_ERROR);
+ magic = RS_MD4_SIG_MAGIC;
+ block_len = 0;
+ strong_len = 17;
+ res = rs_sig_args(-1, &magic, &block_len, &strong_len);
+ assert(res == RS_PARAM_ERROR);
+
+ /* Test rs_signature_init() */
+ /* magic=rec, block_len=rec, strong_len=max. */
+ res = rs_signature_init(&sig, 0, 0, 0, -1);
+ assert(res == RS_DONE);
+ assert(sig.magic == RS_RK_BLAKE2_SIG_MAGIC);
+ assert(sig.block_len == 2048);
+ assert(sig.strong_sum_len == 32);
+ assert(sig.count == 0);
+ assert(sig.size == 0);
+ assert(sig.block_sigs == NULL);
+ assert(sig.hashtable == NULL);
+#ifndef HASHTABLE_NSTATS
+ assert(sig.calc_strong_count == 0);
+#endif
+
+ /* Blake2 magic, block_len=rec, strong_len=max. */
+ res = rs_signature_init(&sig, RS_BLAKE2_SIG_MAGIC, 0, 0, -1);
+ assert(res == RS_DONE);
+ assert(sig.magic == RS_BLAKE2_SIG_MAGIC);
+ assert(sig.block_len == 2048);
+ assert(sig.strong_sum_len == 32);
+
+ /* MD4 magic, block_len=rec, strong_len=max. */
+ res = rs_signature_init(&sig, RS_MD4_SIG_MAGIC, 0, 0, -1);
+ assert(res == RS_DONE);
+ assert(sig.magic == RS_MD4_SIG_MAGIC);
+ assert(sig.block_len == 2048);
+ assert(sig.strong_sum_len == 16);
+
+ /* RabinKarp + Blake2 magic, block_len=16, strong_len=min. */
+ res = rs_signature_init(&sig, RS_RK_BLAKE2_SIG_MAGIC, 16, -1, -1);
+ assert(res == RS_DONE);
+ assert(sig.magic == RS_RK_BLAKE2_SIG_MAGIC);
+ assert(sig.block_len == 16);
+ assert(sig.strong_sum_len == 12);
+
+ /* RabinKarp + MD4 magic, block_len=16, strong_len=6. */
+ res = rs_signature_init(&sig, RS_RK_MD4_SIG_MAGIC, 16, 6, -1);
+ assert(res == RS_DONE);
+ assert(sig.magic == RS_RK_MD4_SIG_MAGIC);
+ assert(sig.block_len == 16);
+ assert(sig.strong_sum_len == 6);
+
+ /* Bad magic. */
+ res = rs_signature_init(&sig, 1, 16, 6, -1);
+ assert(res == RS_BAD_MAGIC);
+
+ /* Bad strong_sum_len. */
+ res = rs_signature_init(&sig, RS_MD4_SIG_MAGIC, 16, 17, -1);
+ assert(res == RS_PARAM_ERROR);
+ res = rs_signature_init(&sig, RS_RK_MD4_SIG_MAGIC, 16, 17, -1);
+ assert(res == RS_PARAM_ERROR);
+ res = rs_signature_init(&sig, RS_BLAKE2_SIG_MAGIC, 16, 33, -1);
+ assert(res == RS_PARAM_ERROR);
+ res = rs_signature_init(&sig, RS_RK_BLAKE2_SIG_MAGIC, 16, 33, -1);
+ assert(res == RS_PARAM_ERROR);
+
+ /* With sig_fsize provided. */
+ res = rs_signature_init(&sig, 0, 16, 6, 92);
+ assert(res == RS_DONE);
+ assert(sig.magic == RS_RK_BLAKE2_SIG_MAGIC);
+ assert(sig.block_len == 16);
+ assert(sig.strong_sum_len == 6);
+ assert(sig.count == 0);
+ assert(sig.size == 8);
+ assert(sig.block_sigs != NULL);
+
+ /* Test rs_signature_done(). */
+ rs_signature_done(&sig);
+ assert(sig.size == 0);
+ assert(sig.block_sigs == NULL);
+
+ /* Test rs_signature_calc_strong_sum(). */
+ res = rs_signature_init(&sig, RS_MD4_SIG_MAGIC, 16, 6, -1);
+ rs_signature_calc_strong_sum(&sig, &buf, 256, &strong);
+ assert(memcmp(&strong, "\x29\x8a\x05\xbc\x50\x6e", 6) == 0);
+
+ res = rs_signature_init(&sig, RS_BLAKE2_SIG_MAGIC, 16, 6, -1);
+ rs_signature_calc_strong_sum(&sig, &buf, 256, &strong);
+ assert(memcmp(&strong, "\x39\xa7\xeb\x9f\xed\xc1", 6) == 0);
+
+ /* Test rs_signature_add_block(). */
+ res = rs_signature_init(&sig, 0, 16, 6, -1);
+ rs_signature_add_block(&sig, weak, &strong);
+ assert(sig.count == 1);
+ assert(sig.size == 16);
+ assert(sig.block_sigs != NULL);
+ assert(((rs_block_sig_t *)sig.block_sigs)->weak_sum == 0x12345678);
+ assert(memcmp(((rs_block_sig_t *)sig.block_sigs)->strong_sum, &strong, 6)
+ == 0);
+ rs_signature_done(&sig);
+
+ /* Prepare rs_build_hash_table() and rs_signature_find_match() tests. */
+ res = rs_signature_init(&sig, 0, 16, 6, -1);
+ for (i = 0; i < 256; i += 16) {
+ weak = rs_signature_calc_weak_sum(&sig, &buf[i], 16);
+ rs_signature_calc_strong_sum(&sig, &buf[i], 16, &strong);
+ rs_signature_add_block(&sig, weak, &strong);
+ }
+
+ /* Test rs_build_hash_table(). */
+ rs_build_hash_table(&sig);
+ assert(sig.hashtable->count == 16);
+
+ /* Test rs_signature_find_match(). */
+ /* different weak, different block. */
+ assert(rs_signature_find_match(&sig, 0x12345678, &buf[2], 16) == -1);
+ /* Matching weak, different block. */
+ assert(rs_signature_find_match(&sig, weak, &buf[2], 16) == -1);
+ /* Matching weak, matching block. */
+ assert(rs_signature_find_match(&sig, weak, &buf[15 * 16], 16) == 15 * 16);
+#ifndef HASHTABLE_NSTATS
+ assert(sig.calc_strong_count == 2);
+#endif
+ rs_signature_done(&sig);
+
+ return 0;
+}
diff --git a/tests/testcommon.sh b/tests/testcommon.sh
new file mode 100644
index 0000000..e59b1ce
--- /dev/null
+++ b/tests/testcommon.sh
@@ -0,0 +1,99 @@
+# Common test utilities for librsync.
+
+# Copyright (C) 2000, 2001, 2014 by Martin Pool
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+# For CMake tests
+bindir=$1
+if [ -z "$bindir" ]
+then
+ # Fallback to automake tests
+ bindir='..'
+fi
+echo "BINDIR $bindir"
+
+testinputdir=$srcdir/$test_base.input
+tmpdir=`mktemp -d -t librsynctest_XXXXXXXX`
+trap "{ rm -r $tmpdir; }" EXIT
+
+block_len=2048
+
+# TODO: Add more pair instructions here
+delta_instr="
+0,1024
+0,2048
+1024,1024:0,1024
+0,1025
+0,1
+0,10
+0,1000
+0,2000
+0,10000
+0,100000
+1,10
+1,10000
+0,2000:2000,2000:4000,100000
+1,10000:0,1:10000,1000000
+10,1:8,4:6,8:4,10:2,12
+0,10000:0,10000:0,10000
+"
+bufsizes='0 1 2 3 7 15 100 10000 200000'
+
+run_test () {
+ if :|| test -n "$VERBOSE"
+ then
+ echo " $@" >&2
+ fi
+
+ "$@" || fail_test "$?" "$@"
+}
+
+fail_test () {
+ result=$1
+ shift
+ echo "not ok $testcounter: returned $result: $@" >&2
+ exit 2
+}
+
+test_skipped () {
+ echo $test_name: skipped; exit 77
+}
+
+check_compare() {
+ if ! cmp "$1" "$2"
+ then
+ echo "$test_name: comparison failed from command: $3" >&2
+ exit 2
+ fi
+}
+
+triple_test () {
+ buf="$1"
+ old="$2"
+ new="$3"
+ hashopt="$4"
+
+ run_test $bindir/rdiff $debug $hashopt -f -I$buf -O$buf $stats signature --block-size=$block_len \
+ $old $tmpdir/sig
+ run_test $bindir/rdiff $debug $hashopt -f -I$buf -O$buf $stats delta $tmpdir/sig $new $tmpdir/delta
+ run_test $bindir/rdiff $debug $hashopt -f -I$buf -O$buf $stats patch $old $tmpdir/delta $tmpdir/new
+ check_compare $new $tmpdir/new "triple -f -I$buf -O$buf $old $new"
+}
+
+make_input () {
+ cat $srcdir/COPYING
+}
diff --git a/tests/triple.input/copying.in b/tests/triple.input/copying.in
new file mode 100644
index 0000000..c4792dd
--- /dev/null
+++ b/tests/triple.input/copying.in
@@ -0,0 +1,515 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+ When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+^L
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+^L
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, 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 library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+ 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 Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+^L
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+ If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+^L
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be 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.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+^L
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+ 9. 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 Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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 with
+this License.
+^L
+ 11. 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 Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+^L
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+^L
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library.
+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 library's name and a brief idea of what it
+does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper
+mail.
+
+You should also get your employer (if you work as a programmer) or
+your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James
+Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/tests/triple.input/half.in b/tests/triple.input/half.in
new file mode 100644
index 0000000..06ed63b
--- /dev/null
+++ b/tests/triple.input/half.in
@@ -0,0 +1,204 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+ When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+^L
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+^L
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, 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 library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+ 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 Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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.
+
diff --git a/tests/triple.input/hello.in b/tests/triple.input/hello.in
new file mode 100644
index 0000000..10ddd6d
--- /dev/null
+++ b/tests/triple.input/hello.in
@@ -0,0 +1 @@
+Hello!
diff --git a/tests/triple.input/zero.in b/tests/triple.input/zero.in
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/triple.input/zero.in
diff --git a/tests/triple.test b/tests/triple.test
new file mode 100755
index 0000000..0a75870
--- /dev/null
+++ b/tests/triple.test
@@ -0,0 +1,51 @@
+#! /bin/sh
+
+# librsync -- the library for network deltas
+#
+# Copyright (C) 2001, 2014 by Martin Pool <mbp@sourcefrog.net>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir='.'
+
+. $srcdir/testcommon.sh
+inputdir=$srcdir/triple.input
+
+for buf in $bufsizes
+do
+ for old in $inputdir/*.in
+ do
+ for new in $inputdir/*.in
+ do
+ for hashopt in -Hmd4 -Hblake2
+ do
+ run_test $bindir/rdiff $debug $hashopt -f -I$buf -O$buf signature $old $tmpdir/sig
+ run_test $bindir/rdiff $debug $hashopt -f -I$buf -O$buf delta $tmpdir/sig $new $tmpdir/delta
+ run_test $bindir/rdiff $debug $hashopt -f -I$buf -O$buf patch $old $tmpdir/delta $tmpdir/new
+
+ check_compare $new $tmpdir/new "triple -I$buf -O$buf $old $new"
+
+ # Run tests again and check if reading and writing to pipes works
+ :> $tmpdir/new
+ cat $old | run_test $bindir/rdiff $debug $hashopt -I$buf -O$buf signature > $tmpdir/sig
+ # this test pipes signature instead of $new so that signature memory preallocation is tested
+ cat $tmpdir/sig | run_test $bindir/rdiff $debug $hashopt -I$buf -O$buf delta - $new > $tmpdir/delta
+ cat $tmpdir/delta | run_test $bindir/rdiff $debug $hashopt -I$buf -O$buf patch $old > $tmpdir/new
+
+ check_compare $new $tmpdir/new "triple -I$buf -O$buf $old $new"
+ done
+ done
+ done
+done