🏗 Add xdelta3 dependency
This commit is contained in:
parent
80f2439239
commit
ae59ce2256
97 changed files with 45332 additions and 1 deletions
14
README.md
14
README.md
|
@ -49,4 +49,16 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
## Xdelta3
|
## Xdelta3 <[https://github.com/jmacd/xdelta](https://github.com/jmacd/xdelta)>
|
||||||
|
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
176
lib/xdelta3/LICENSE
Normal file
176
lib/xdelta3/LICENSE
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
192
lib/xdelta3/Makefile.am
Normal file
192
lib/xdelta3/Makefile.am
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
AUTOMAKE_OPTIONS = subdir-objects
|
||||||
|
|
||||||
|
bin_PROGRAMS = xdelta3
|
||||||
|
noinst_PROGRAMS = xdelta3regtest xdelta3decode xdelta3checksum
|
||||||
|
|
||||||
|
export AFL_HARDEN
|
||||||
|
|
||||||
|
common_SOURCES = \
|
||||||
|
xdelta3-blkcache.h \
|
||||||
|
xdelta3-decode.h \
|
||||||
|
xdelta3-djw.h \
|
||||||
|
xdelta3-fgk.h \
|
||||||
|
xdelta3-hash.h \
|
||||||
|
xdelta3-internal.h \
|
||||||
|
xdelta3-list.h \
|
||||||
|
xdelta3-lzma.h \
|
||||||
|
xdelta3-main.h \
|
||||||
|
xdelta3-merge.h \
|
||||||
|
xdelta3-second.h \
|
||||||
|
xdelta3-test.h \
|
||||||
|
xdelta3-cfgs.h \
|
||||||
|
xdelta3.h
|
||||||
|
|
||||||
|
xdelta3_SOURCES = $(common_SOURCES) xdelta3.c
|
||||||
|
|
||||||
|
xdelta3decode_SOURCES = $(common_SOURCES) xdelta3.c
|
||||||
|
|
||||||
|
xdelta3regtest_SOURCES = $(common_SOURCES) \
|
||||||
|
testing/cmp.h \
|
||||||
|
testing/delta.h \
|
||||||
|
testing/file.h \
|
||||||
|
testing/modify.h \
|
||||||
|
testing/random.h \
|
||||||
|
testing/regtest.cc \
|
||||||
|
testing/regtest_c.c \
|
||||||
|
testing/segment.h \
|
||||||
|
testing/sizes.h \
|
||||||
|
testing/test.h
|
||||||
|
|
||||||
|
xdelta3checksum_SOURCES = $(common_SOURCES) \
|
||||||
|
testing/checksum_test.cc \
|
||||||
|
testing/checksum_test_c.c
|
||||||
|
|
||||||
|
# These sources constitute a regression test written in Go, that is
|
||||||
|
# not automatically built or run. Install Go-1.5.x or later, add
|
||||||
|
# `pwd`/go in $GOPATH, and (cd go/src && go run regtest.go).
|
||||||
|
# TODO(jmacd): replace hard-coded path names in regtest.go w/ flags.
|
||||||
|
GOLANG_SRCS = \
|
||||||
|
go/src/xdelta/test.go \
|
||||||
|
go/src/xdelta/rstream.go \
|
||||||
|
go/src/xdelta/tgroup.go \
|
||||||
|
go/src/xdelta/run.go \
|
||||||
|
go/src/regtest.go
|
||||||
|
|
||||||
|
# Note: for extra sanity checks, enable -Wconversion. Note there
|
||||||
|
# are a lot of false positives.
|
||||||
|
WFLAGS = -Wall -Wshadow -fno-builtin -Wextra -Wsign-compare \
|
||||||
|
-Wformat=2 -Wno-format-nonliteral \
|
||||||
|
-Wno-unused-parameter -Wno-unused-function
|
||||||
|
|
||||||
|
# -Weverything \
|
||||||
|
# -Wc++11-compat-reserved-user-defined-literal \
|
||||||
|
# -Wno-padded \
|
||||||
|
# -Wno-format-nonliteral \
|
||||||
|
# -Wno-cast-align \
|
||||||
|
# -Wno-unused-parameter \
|
||||||
|
# -Wno-sign-conversion \
|
||||||
|
# -Wno-conversion \
|
||||||
|
# -Wno-switch-enum \
|
||||||
|
# -Wno-covered-switch-default \
|
||||||
|
# -Wno-disabled-macro-expansion \
|
||||||
|
# -Wno-variadic-macros \
|
||||||
|
# -Wno-c++98-compat-pedantic
|
||||||
|
|
||||||
|
C_WFLAGS = $(WFLAGS) -std=c99
|
||||||
|
CXX_WFLAGS = $(WFLAGS) -std=c++11
|
||||||
|
|
||||||
|
common_CFLAGS = \
|
||||||
|
-DREGRESSION_TEST=1 \
|
||||||
|
-DSECONDARY_DJW=1 \
|
||||||
|
-DSECONDARY_FGK=1 \
|
||||||
|
-DXD3_MAIN=1
|
||||||
|
|
||||||
|
if DEBUG_SYMBOLS
|
||||||
|
common_CFLAGS += -g
|
||||||
|
endif
|
||||||
|
|
||||||
|
#common_CFLAGS += -fsanitize=address -fno-omit-frame-pointer
|
||||||
|
#common_CFLAGS += -O2
|
||||||
|
|
||||||
|
# For additional debugging, add -DXD3_DEBUG=1, 2, 3, ...
|
||||||
|
xdelta3_CFLAGS = $(C_WFLAGS) $(common_CFLAGS) -DXD3_DEBUG=0
|
||||||
|
xdelta3_LDADD = -lm
|
||||||
|
|
||||||
|
xdelta3decode_CFLAGS = \
|
||||||
|
$(C_WFLAGS) \
|
||||||
|
-DREGRESSION_TEST=0 \
|
||||||
|
-DSECONDARY_DJW=0 \
|
||||||
|
-DSECONDARY_FGK=0 \
|
||||||
|
-DSECONDARY_LZMA=0 \
|
||||||
|
-DXD3_MAIN=1 \
|
||||||
|
-DXD3_ENCODER=0 \
|
||||||
|
-DXD3_STDIO=1 \
|
||||||
|
-DEXTERNAL_COMPRESSION=0 \
|
||||||
|
-DVCDIFF_TOOLS=0
|
||||||
|
|
||||||
|
xdelta3regtest_CXXFLAGS = \
|
||||||
|
$(CXX_WFLAGS) $(common_CFLAGS) -DNOT_MAIN=1 -DXD3_DEBUG=1
|
||||||
|
xdelta3regtest_CFLAGS = \
|
||||||
|
$(C_WFLAGS) $(common_CFLAGS) -DNOT_MAIN=1 -DXD3_DEBUG=1
|
||||||
|
xdelta3regtest_LDADD = -lm
|
||||||
|
|
||||||
|
xdelta3checksum_CXXFLAGS = \
|
||||||
|
$(CXX_WFLAGS) $(common_CFLAGS) -DNOT_MAIN=1 -DXD3_MAIN=1 -std=c++11
|
||||||
|
xdelta3checksum_CFLAGS = \
|
||||||
|
$(C_WFLAGS) $(common_CFLAGS) -DNOT_MAIN=1 -DXD3_MAIN=1
|
||||||
|
|
||||||
|
|
||||||
|
man1_MANS = xdelta3.1
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
README.md \
|
||||||
|
run_release.sh \
|
||||||
|
draft-korn-vcdiff.txt \
|
||||||
|
$(GOLANG_SRCS) \
|
||||||
|
examples/Makefile \
|
||||||
|
examples/README.md \
|
||||||
|
examples/compare_test.c \
|
||||||
|
examples/encode_decode_test.c \
|
||||||
|
examples/small_page_test.c \
|
||||||
|
examples/speed_test.c \
|
||||||
|
examples/test.h \
|
||||||
|
examples/iOS/xdelta3-ios-test/xdelta3-ios-test.xcodeproj/project.pbxproj \
|
||||||
|
examples/iOS/xdelta3-ios-test/xdelta3-ios-test/Xd3iOSAppDelegate.h \
|
||||||
|
examples/iOS/xdelta3-ios-test/xdelta3-ios-test/Xd3iOSAppDelegate.m \
|
||||||
|
examples/iOS/xdelta3-ios-test/xdelta3-ios-test/Xd3iOSViewController.h \
|
||||||
|
examples/iOS/xdelta3-ios-test/xdelta3-ios-test/Xd3iOSViewController.m \
|
||||||
|
examples/iOS/xdelta3-ios-test/xdelta3-ios-test/en.lproj/InfoPlist.strings \
|
||||||
|
examples/iOS/xdelta3-ios-test/xdelta3-ios-test/en.lproj/MainStoryboard_iPad.storyboard \
|
||||||
|
examples/iOS/xdelta3-ios-test/xdelta3-ios-test/en.lproj/MainStoryboard_iPhone.storyboard \
|
||||||
|
examples/iOS/xdelta3-ios-test/xdelta3-ios-test/file_v1.bin \
|
||||||
|
examples/iOS/xdelta3-ios-test/xdelta3-ios-test/file_v1_to_v2.bin \
|
||||||
|
examples/iOS/xdelta3-ios-test/xdelta3-ios-test/file_v2.bin \
|
||||||
|
examples/iOS/xdelta3-ios-test/xdelta3-ios-test/main.m \
|
||||||
|
examples/iOS/xdelta3-ios-test/xdelta3-ios-test/xdelta3-ios-test-Info.plist \
|
||||||
|
examples/iOS/xdelta3-ios-test/xdelta3-ios-test/xdelta3-ios-test-Prefix.pch \
|
||||||
|
cpp-btree/CMakeLists.txt \
|
||||||
|
cpp-btree/COPYING \
|
||||||
|
cpp-btree/README \
|
||||||
|
cpp-btree/btree.h \
|
||||||
|
cpp-btree/btree_bench.cc \
|
||||||
|
cpp-btree/btree_container.h \
|
||||||
|
cpp-btree/btree_map.h \
|
||||||
|
cpp-btree/btree_set.h \
|
||||||
|
cpp-btree/btree_test.cc \
|
||||||
|
cpp-btree/btree_test.h \
|
||||||
|
cpp-btree/btree_test_flags.cc \
|
||||||
|
cpp-btree/safe_btree.h \
|
||||||
|
cpp-btree/safe_btree_map.h \
|
||||||
|
cpp-btree/safe_btree_set.h \
|
||||||
|
cpp-btree/safe_btree_test.cc \
|
||||||
|
testing/xdelta3-regtest.py \
|
||||||
|
testing/xdelta3-test.py \
|
||||||
|
xdelta3.1 \
|
||||||
|
xdelta3.i \
|
||||||
|
xdelta3.vcxproj \
|
||||||
|
xdelta3.wxi \
|
||||||
|
xdelta3.wxs
|
||||||
|
|
||||||
|
# Broken, removed from distribution:
|
||||||
|
# xdelta3_pywrap.c
|
||||||
|
# xdelta3.py
|
||||||
|
|
||||||
|
#PYFILES = xdelta3_pywrap.c xdelta3.py
|
||||||
|
#XDELTA3PY = xdelta3.py
|
||||||
|
#XDELTA3PYLIB = xdelta3.la
|
||||||
|
|
||||||
|
#BUILT_SOURCES = $(PYFILES)
|
||||||
|
|
||||||
|
#xdelta3_pywrap.c xdelta3.py : xdelta3.i
|
||||||
|
# $(SWIG) -python -o xdelta3_pywrap.c xdelta3.i
|
||||||
|
|
||||||
|
# OS X for some reason requires:
|
||||||
|
# pythondir = $(PYTHON_SITE_PKG)
|
||||||
|
# pyexecdir = $(PYTHON_SITE_PKG)
|
||||||
|
|
||||||
|
#python_PYTHON = $(XDELTA3PY)
|
||||||
|
#pyexec_LTLIBRARIES = $(XDELTA3PYLIB)
|
||||||
|
#_xdelta3_la_SOURCES = $(srcdir)/xdelta3_pywrap.c $(xdelta3_SOURCES)
|
||||||
|
#_xdelta3_la_CFLAGS = $(common_CFLAGS) -DNOT_MAIN=1 $(PYTHON_CPPFLAGS)
|
||||||
|
#_xdelta3_la_LDFLAGS = -module
|
37
lib/xdelta3/README.md
Normal file
37
lib/xdelta3/README.md
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
Xdelta 3.x readme.txt
|
||||||
|
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
||||||
|
2009, 2010, 2011, 2012, 2013, 2014, 2015
|
||||||
|
<josh.macdonald@gmail.com>
|
||||||
|
|
||||||
|
|
||||||
|
Thanks for downloading Xdelta!
|
||||||
|
|
||||||
|
This directory contains the Xdelta3 command-line interface (CLI) and source
|
||||||
|
distribution for VCDIFF differential compression, a.k.a. delta
|
||||||
|
compression. The latest information and downloads are available here:
|
||||||
|
|
||||||
|
http://xdelta.org/
|
||||||
|
http://github.com/jmacd/xdelta/
|
||||||
|
|
||||||
|
Xdelta can be configured to use XZ Utils for secondary compression:
|
||||||
|
|
||||||
|
http://tukaani.org/xz/
|
||||||
|
|
||||||
|
The command-line syntax is detailed here:
|
||||||
|
|
||||||
|
https://github.com/jmacd/xdelta/blob/wiki/CommandLineSyntax.md
|
||||||
|
|
||||||
|
Run 'xdelta3 -h' for brief help. Run 'xdelta3 test' for built-in tests.
|
||||||
|
|
||||||
|
Sample commands (like gzip, -e means encode, -d means decode)
|
||||||
|
|
||||||
|
xdelta3 -9 -S lzma -e -f -s OLD_FILE NEW_FILE DELTA_FILE
|
||||||
|
xdelta3 -d -s OLD_FILE DELTA_FILE DECODED_FILE
|
||||||
|
|
||||||
|
File bug reports and browse open support issues here:
|
||||||
|
|
||||||
|
https://github.com/jmacd/xdelta/issues
|
||||||
|
|
||||||
|
The source distribution contains the C/C++/Python APIs, Unix, Microsoft VC++
|
||||||
|
and Cygwin builds. Xdelta3 is covered under the terms of the APL, see
|
||||||
|
LICENSE.
|
158
lib/xdelta3/badcopy.c
Normal file
158
lib/xdelta3/badcopy.c
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#define BUFSZ (1 << 22)
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
// whatever
|
||||||
|
static
|
||||||
|
double drand48() {
|
||||||
|
double r = rand() / (double)RAND_MAX;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
long lrand48() {
|
||||||
|
long l = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
l = l ^ (l << 2) ^ (l << 1) ^ rand();
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define XD3_WIN32 1
|
||||||
|
#else
|
||||||
|
#define XD3_POSIX 1
|
||||||
|
#endif
|
||||||
|
#define XD3_MAIN 1
|
||||||
|
#define main notmain
|
||||||
|
#define EXTERNAL_COMPRESSION 0
|
||||||
|
#define XD3_USE_LARGEFILE64 1
|
||||||
|
#include "xdelta3.c"
|
||||||
|
#undef main
|
||||||
|
|
||||||
|
|
||||||
|
double error_prob = 0.0001;
|
||||||
|
usize_t mean_change = 100;
|
||||||
|
xoff_t total_change = 0;
|
||||||
|
xoff_t total_size = 0;
|
||||||
|
usize_t max_change = 0;
|
||||||
|
usize_t num_change = 0;
|
||||||
|
|
||||||
|
|
||||||
|
static usize_t
|
||||||
|
edist (usize_t mean, usize_t max)
|
||||||
|
{
|
||||||
|
double mean_d = mean;
|
||||||
|
double erand = log (1.0 / drand48 ());
|
||||||
|
usize_t x = (usize_t) (mean_d * erand + 0.5);
|
||||||
|
|
||||||
|
return (x < max) ? (x > 0 ? x : 1) : max;
|
||||||
|
}
|
||||||
|
|
||||||
|
void modify (char *buf, usize_t size)
|
||||||
|
{
|
||||||
|
usize_t bufpos = 0, j;
|
||||||
|
usize_t last_end = 0;
|
||||||
|
|
||||||
|
for (;; /* bufpos and j are incremented in the inner loop */)
|
||||||
|
{
|
||||||
|
/* The size of the next modification. */
|
||||||
|
usize_t next_size = edist (mean_change, 1 << 31);
|
||||||
|
/* The expected interval of such a change. */
|
||||||
|
double expect_interval = ((double) next_size * (1.0 - error_prob)) / error_prob;
|
||||||
|
/* The number of bytes until the next modification. */
|
||||||
|
usize_t next_mod = edist ((usize_t)expect_interval, 1 << 31);
|
||||||
|
|
||||||
|
if (next_size + next_mod + bufpos > size) { break; }
|
||||||
|
|
||||||
|
if (max_change < next_size) { max_change = next_size; }
|
||||||
|
|
||||||
|
bufpos += next_mod;
|
||||||
|
|
||||||
|
fprintf (stderr, "COPY: %I64u-%I64u (%u)\n",
|
||||||
|
total_size + (xoff_t)last_end,
|
||||||
|
total_size + (xoff_t)bufpos,
|
||||||
|
bufpos - last_end);
|
||||||
|
fprintf (stderr, "ADD: %I64u-%I64u (%u) is change %u\n",
|
||||||
|
total_size + (xoff_t)bufpos,
|
||||||
|
total_size + (xoff_t)(bufpos + next_size),
|
||||||
|
next_size, num_change);
|
||||||
|
|
||||||
|
total_change += next_size;
|
||||||
|
num_change += 1;
|
||||||
|
|
||||||
|
for (j = 0; j < next_size; j += 1, bufpos += 1)
|
||||||
|
{
|
||||||
|
buf[bufpos] = (char)(lrand48 () >> 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_end = bufpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr, "COPY: %I64u-%I64u (%u)\n",
|
||||||
|
total_size + last_end,
|
||||||
|
total_size + size, size - last_end);
|
||||||
|
|
||||||
|
total_size += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
main_file inp, out;
|
||||||
|
char *buf = malloc(BUFSZ);
|
||||||
|
int c, ret;
|
||||||
|
main_file_init(&inp);
|
||||||
|
main_file_init(&out);
|
||||||
|
option_force = 1;
|
||||||
|
if (argc > 5)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "usage: badcopy [byte_error_prob [mean_error_size]]\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > 4) { mean_change = atoi (argv[4]); }
|
||||||
|
if (argc > 3) { error_prob = atof (argv[3]); }
|
||||||
|
fprintf (stderr, "mean change = %u; error_prob = %0.10f\n", mean_change, error_prob);
|
||||||
|
|
||||||
|
if ((ret = main_file_open (&inp, argv[1], XO_READ)) != 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ((ret = main_file_open (&out, argv[2], XO_WRITE)) != 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error_prob < 0.0 || error_prob > 1.0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "warning: error probability out of range\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if ((ret = main_file_read (&inp, buf, BUFSZ, &c, "read failed")) != 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 0) { break; }
|
||||||
|
|
||||||
|
modify (buf, c);
|
||||||
|
|
||||||
|
if ((ret = main_file_write (&out, buf, c, "write failed")) != 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (c == BUFSZ);
|
||||||
|
|
||||||
|
if ((ret = main_file_close (&out)))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr, "add_prob %f; %u adds; total_change %u of %u bytes; add percentage %f; max add size %u\n",
|
||||||
|
error_prob, num_change, total_change, total_size, (double) total_change / (double) total_size, max_change);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
51
lib/xdelta3/configure.ac
Normal file
51
lib/xdelta3/configure.ac
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
AC_INIT([Xdelta3], [3.1.1], [josh.macdonald@gmail.com],
|
||||||
|
[xdelta3], [http://xdelta.org/])
|
||||||
|
AC_PREREQ([2.68])
|
||||||
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
|
LT_INIT
|
||||||
|
AM_INIT_AUTOMAKE([1.15 no-define foreign tar-ustar subdir-objects])
|
||||||
|
AC_CONFIG_MACRO_DIRS([m4])
|
||||||
|
|
||||||
|
AX_CHECK_ALIGNED_ACCESS_REQUIRED
|
||||||
|
AC_PROG_CC
|
||||||
|
AC_PROG_CXX
|
||||||
|
|
||||||
|
AC_CHECK_SIZEOF(size_t)
|
||||||
|
AC_CHECK_SIZEOF(unsigned int)
|
||||||
|
AC_CHECK_SIZEOF(unsigned long)
|
||||||
|
AC_CHECK_SIZEOF(unsigned long long)
|
||||||
|
|
||||||
|
AC_ARG_WITH(
|
||||||
|
[liblzma],
|
||||||
|
[AC_HELP_STRING(
|
||||||
|
[--with-liblzma],
|
||||||
|
[build with liblzma support @<:@default=autodetect@:>@])],
|
||||||
|
[USE_LIBLZMA=$withval],
|
||||||
|
[USE_LIBLZMA=auto])
|
||||||
|
|
||||||
|
if test "x$USE_LIBLZMA" != xno ; then
|
||||||
|
AC_CHECK_HEADERS([lzma.h],,[
|
||||||
|
if test "x$with_liblzma" = xyes ; then
|
||||||
|
AC_MSG_FAILURE([liblzma includes were not found])
|
||||||
|
fi])
|
||||||
|
AC_CHECK_LIB([lzma], [lzma_easy_buffer_encode],,[
|
||||||
|
if test "x$with_liblzma" = xyes ; then
|
||||||
|
AC_MSG_FAILURE([liblzma library were not found])
|
||||||
|
fi])
|
||||||
|
fi
|
||||||
|
|
||||||
|
#AM_PATH_PYTHON(,, [:])
|
||||||
|
#AM_CONDITIONAL([HAVE_PYTHON], [test "$PYTHON" != :])
|
||||||
|
#AX_PYTHON_DEVEL()
|
||||||
|
#AX_PKG_SWIG(2.0.0,,)
|
||||||
|
#AX_SWIG_PYTHON
|
||||||
|
|
||||||
|
dnl --enable-debug-symbols : build with debug symbols?
|
||||||
|
AC_ARG_ENABLE(debug-symbols,
|
||||||
|
AS_HELP_STRING(--enable-debug-symbols,[Build with debug symbols (default is NO)]),,enableval=no)
|
||||||
|
AM_CONDITIONAL([DEBUG_SYMBOLS], [test ${enableval} = "yes"])
|
||||||
|
|
||||||
|
|
||||||
|
AC_CONFIG_HEADERS([config.h])
|
||||||
|
AC_CONFIG_FILES([Makefile])
|
||||||
|
AC_OUTPUT
|
40
lib/xdelta3/cpp-btree/CMakeLists.txt
Normal file
40
lib/xdelta3/cpp-btree/CMakeLists.txt
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 2.6)
|
||||||
|
|
||||||
|
project(cppbtree CXX)
|
||||||
|
|
||||||
|
option(build_tests "Build B-tree tests" OFF)
|
||||||
|
add_definitions(-std=c++11)
|
||||||
|
set(CMAKE_CXX_FLAGS "-g -O2")
|
||||||
|
|
||||||
|
# CMake doesn't have a way to pure template library,
|
||||||
|
# add_library(cppbtree btree.h btree_map.h btree_set.h
|
||||||
|
# safe_btree.h safe_btree_map.h safe_btree_set.h)
|
||||||
|
# set_target_properties(cppbtree PROPERTIES LINKER_LANGUAGE CXX)
|
||||||
|
|
||||||
|
if(build_tests)
|
||||||
|
enable_testing()
|
||||||
|
include_directories($ENV{GTEST_ROOT}/include)
|
||||||
|
link_directories($ENV{GTEST_ROOT})
|
||||||
|
include_directories($ENV{GFLAGS_ROOT}/include)
|
||||||
|
link_directories($ENV{GFLAGS_ROOT}/lib)
|
||||||
|
add_executable(btree_test btree_test.cc btree_test_flags.cc)
|
||||||
|
add_executable(safe_btree_test safe_btree_test.cc btree_test_flags.cc)
|
||||||
|
add_executable(btree_bench btree_bench.cc btree_test_flags.cc)
|
||||||
|
target_link_libraries(btree_test gtest_main gtest gflags)
|
||||||
|
target_link_libraries(safe_btree_test gtest_main gtest gflags)
|
||||||
|
target_link_libraries(btree_bench gflags gtest)
|
||||||
|
endif()
|
202
lib/xdelta3/cpp-btree/COPYING
Normal file
202
lib/xdelta3/cpp-btree/COPYING
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
31
lib/xdelta3/cpp-btree/README
Normal file
31
lib/xdelta3/cpp-btree/README
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
This library is a C++ template library and, as such, there is no
|
||||||
|
library to build and install. Copy the .h files and use them!
|
||||||
|
|
||||||
|
See http://code.google.com/p/cpp-btree/wiki/UsageInstructions for
|
||||||
|
details.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
To build and run the provided tests, however, you will need to install
|
||||||
|
CMake, the Google C++ Test framework, and the Google flags package.
|
||||||
|
|
||||||
|
Download and install CMake from http://www.cmake.org
|
||||||
|
|
||||||
|
Download and build the GoogleTest framework from
|
||||||
|
http://code.google.com/p/googletest
|
||||||
|
|
||||||
|
Download and install gflags from https://code.google.com/p/gflags
|
||||||
|
|
||||||
|
Set GTEST_ROOT to the directory where GTEST was built.
|
||||||
|
Set GFLAGS_ROOT to the directory prefix where GFLAGS is installed.
|
||||||
|
|
||||||
|
export GTEST_ROOT=/path/for/gtest-x.y
|
||||||
|
export GFLAGS_ROOT=/opt
|
||||||
|
|
||||||
|
cmake . -Dbuild_tests=ON
|
||||||
|
|
||||||
|
For example, to build on a Unix system with the clang++ compiler,
|
||||||
|
|
||||||
|
export GTEST_ROOT=$(HOME)/src/googletest
|
||||||
|
export GFLAGS_ROOT=/opt
|
||||||
|
cmake . -G "Unix Makefiles" -Dbuild_tests=ON -DCMAKE_CXX_COMPILER=clang++
|
2394
lib/xdelta3/cpp-btree/btree.h
Normal file
2394
lib/xdelta3/cpp-btree/btree.h
Normal file
File diff suppressed because it is too large
Load diff
593
lib/xdelta3/cpp-btree/btree_bench.cc
Normal file
593
lib/xdelta3/cpp-btree/btree_bench.cc
Normal file
|
@ -0,0 +1,593 @@
|
||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "gflags/gflags.h"
|
||||||
|
#include "btree_map.h"
|
||||||
|
#include "btree_set.h"
|
||||||
|
#include "btree_test.h"
|
||||||
|
|
||||||
|
DEFINE_int32(test_random_seed, 123456789, "Seed for srand()");
|
||||||
|
DEFINE_int32(benchmark_max_iters, 10000000, "Maximum test iterations");
|
||||||
|
DEFINE_int32(benchmark_min_iters, 100, "Minimum test iterations");
|
||||||
|
DEFINE_int32(benchmark_target_seconds, 1,
|
||||||
|
"Attempt to benchmark for this many seconds");
|
||||||
|
|
||||||
|
using std::allocator;
|
||||||
|
using std::less;
|
||||||
|
using std::map;
|
||||||
|
using std::max;
|
||||||
|
using std::min;
|
||||||
|
using std::multimap;
|
||||||
|
using std::multiset;
|
||||||
|
using std::set;
|
||||||
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
namespace btree {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct RandGen {
|
||||||
|
typedef ptrdiff_t result_type;
|
||||||
|
RandGen(result_type seed) {
|
||||||
|
srand(seed);
|
||||||
|
}
|
||||||
|
result_type operator()(result_type l) {
|
||||||
|
return rand() % l;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BenchmarkRun {
|
||||||
|
BenchmarkRun(const char *name, void (*func)(int));
|
||||||
|
void Run();
|
||||||
|
void Stop();
|
||||||
|
void Start();
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
BenchmarkRun *next_benchmark;
|
||||||
|
const char *benchmark_name;
|
||||||
|
void (*benchmark_func)(int);
|
||||||
|
int64_t accum_micros;
|
||||||
|
int64_t last_started;
|
||||||
|
};
|
||||||
|
|
||||||
|
BenchmarkRun *first_benchmark;
|
||||||
|
BenchmarkRun *current_benchmark;
|
||||||
|
|
||||||
|
int64_t get_micros () {
|
||||||
|
timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
return tv.tv_sec * 1000000 + tv.tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
BenchmarkRun::BenchmarkRun(const char *name, void (*func)(int))
|
||||||
|
: next_benchmark(first_benchmark),
|
||||||
|
benchmark_name(name),
|
||||||
|
benchmark_func(func),
|
||||||
|
accum_micros(0),
|
||||||
|
last_started(0) {
|
||||||
|
first_benchmark = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BTREE_BENCHMARK(name) \
|
||||||
|
BTREE_BENCHMARK2(#name, name, __COUNTER__)
|
||||||
|
#define BTREE_BENCHMARK2(name, func, counter) \
|
||||||
|
BTREE_BENCHMARK3(name, func, counter)
|
||||||
|
#define BTREE_BENCHMARK3(name, func, counter) \
|
||||||
|
BenchmarkRun bench ## counter (name, func)
|
||||||
|
|
||||||
|
void StopBenchmarkTiming() {
|
||||||
|
current_benchmark->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartBenchmarkTiming() {
|
||||||
|
current_benchmark->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunBenchmarks() {
|
||||||
|
for (BenchmarkRun *bench = first_benchmark; bench;
|
||||||
|
bench = bench->next_benchmark) {
|
||||||
|
bench->Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BenchmarkRun::Start() {
|
||||||
|
assert(!last_started);
|
||||||
|
last_started = get_micros();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BenchmarkRun::Stop() {
|
||||||
|
if (last_started == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
accum_micros += get_micros() - last_started;
|
||||||
|
last_started = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BenchmarkRun::Reset() {
|
||||||
|
last_started = 0;
|
||||||
|
accum_micros = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BenchmarkRun::Run() {
|
||||||
|
assert(current_benchmark == NULL);
|
||||||
|
current_benchmark = this;
|
||||||
|
int iters = FLAGS_benchmark_min_iters;
|
||||||
|
for (;;) {
|
||||||
|
Reset();
|
||||||
|
Start();
|
||||||
|
benchmark_func(iters);
|
||||||
|
Stop();
|
||||||
|
if (accum_micros > FLAGS_benchmark_target_seconds * 1000000 ||
|
||||||
|
iters >= FLAGS_benchmark_max_iters) {
|
||||||
|
break;
|
||||||
|
} else if (accum_micros == 0) {
|
||||||
|
iters *= 100;
|
||||||
|
} else {
|
||||||
|
int64_t target_micros = FLAGS_benchmark_target_seconds * 1000000;
|
||||||
|
iters = target_micros * iters / accum_micros;
|
||||||
|
}
|
||||||
|
iters = min(iters, FLAGS_benchmark_max_iters);
|
||||||
|
}
|
||||||
|
std::cout << benchmark_name << "\t"
|
||||||
|
<< accum_micros * 1000 / iters << "\t"
|
||||||
|
<< iters;
|
||||||
|
current_benchmark = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to avoid compiler optimizations for these benchmarks.
|
||||||
|
template <typename T>
|
||||||
|
void sink(const T& t0) {
|
||||||
|
volatile T t = t0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Benchmark insertion of values into a container.
|
||||||
|
template <typename T>
|
||||||
|
void BM_Insert(int n) {
|
||||||
|
typedef typename std::remove_const<typename T::value_type>::type V;
|
||||||
|
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||||
|
|
||||||
|
// Disable timing while we perform some initialization.
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
|
||||||
|
T container;
|
||||||
|
vector<V> values = GenerateValues<V>(FLAGS_benchmark_values);
|
||||||
|
for (int i = 0; i < values.size(); i++) {
|
||||||
|
container.insert(values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < n; ) {
|
||||||
|
// Remove and re-insert 10% of the keys
|
||||||
|
int m = min(n - i, FLAGS_benchmark_values / 10);
|
||||||
|
|
||||||
|
for (int j = i; j < i + m; j++) {
|
||||||
|
int x = j % FLAGS_benchmark_values;
|
||||||
|
container.erase(key_of_value(values[x]));
|
||||||
|
}
|
||||||
|
|
||||||
|
StartBenchmarkTiming();
|
||||||
|
|
||||||
|
for (int j = i; j < i + m; j++) {
|
||||||
|
int x = j % FLAGS_benchmark_values;
|
||||||
|
container.insert(values[x]);
|
||||||
|
}
|
||||||
|
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
|
||||||
|
i += m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Benchmark lookup of values in a container.
|
||||||
|
template <typename T>
|
||||||
|
void BM_Lookup(int n) {
|
||||||
|
typedef typename std::remove_const<typename T::value_type>::type V;
|
||||||
|
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||||
|
|
||||||
|
// Disable timing while we perform some initialization.
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
|
||||||
|
T container;
|
||||||
|
vector<V> values = GenerateValues<V>(FLAGS_benchmark_values);
|
||||||
|
|
||||||
|
for (int i = 0; i < values.size(); i++) {
|
||||||
|
container.insert(values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
V r = V();
|
||||||
|
|
||||||
|
StartBenchmarkTiming();
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
int m = i % values.size();
|
||||||
|
r = *container.find(key_of_value(values[m]));
|
||||||
|
}
|
||||||
|
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
|
||||||
|
sink(r); // Keep compiler from optimizing away r.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Benchmark lookup of values in a full container, meaning that values
|
||||||
|
// are inserted in-order to take advantage of biased insertion, which
|
||||||
|
// yields a full tree.
|
||||||
|
template <typename T>
|
||||||
|
void BM_FullLookup(int n) {
|
||||||
|
typedef typename std::remove_const<typename T::value_type>::type V;
|
||||||
|
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||||
|
|
||||||
|
// Disable timing while we perform some initialization.
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
|
||||||
|
T container;
|
||||||
|
vector<V> values = GenerateValues<V>(FLAGS_benchmark_values);
|
||||||
|
vector<V> sorted(values);
|
||||||
|
sort(sorted.begin(), sorted.end());
|
||||||
|
|
||||||
|
for (int i = 0; i < sorted.size(); i++) {
|
||||||
|
container.insert(sorted[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
V r = V();
|
||||||
|
|
||||||
|
StartBenchmarkTiming();
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
int m = i % values.size();
|
||||||
|
r = *container.find(key_of_value(values[m]));
|
||||||
|
}
|
||||||
|
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
|
||||||
|
sink(r); // Keep compiler from optimizing away r.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Benchmark deletion of values from a container.
|
||||||
|
template <typename T>
|
||||||
|
void BM_Delete(int n) {
|
||||||
|
typedef typename std::remove_const<typename T::value_type>::type V;
|
||||||
|
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||||
|
|
||||||
|
// Disable timing while we perform some initialization.
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
|
||||||
|
T container;
|
||||||
|
vector<V> values = GenerateValues<V>(FLAGS_benchmark_values);
|
||||||
|
for (int i = 0; i < values.size(); i++) {
|
||||||
|
container.insert(values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < n; ) {
|
||||||
|
// Remove and re-insert 10% of the keys
|
||||||
|
int m = min(n - i, FLAGS_benchmark_values / 10);
|
||||||
|
|
||||||
|
StartBenchmarkTiming();
|
||||||
|
|
||||||
|
for (int j = i; j < i + m; j++) {
|
||||||
|
int x = j % FLAGS_benchmark_values;
|
||||||
|
container.erase(key_of_value(values[x]));
|
||||||
|
}
|
||||||
|
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
|
||||||
|
for (int j = i; j < i + m; j++) {
|
||||||
|
int x = j % FLAGS_benchmark_values;
|
||||||
|
container.insert(values[x]);
|
||||||
|
}
|
||||||
|
|
||||||
|
i += m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Benchmark steady-state insert (into first half of range) and remove
|
||||||
|
// (from second second half of range), treating the container
|
||||||
|
// approximately like a queue with log-time access for all elements.
|
||||||
|
// This benchmark does not test the case where insertion and removal
|
||||||
|
// happen in the same region of the tree. This benchmark counts two
|
||||||
|
// value constructors.
|
||||||
|
template <typename T>
|
||||||
|
void BM_QueueAddRem(int n) {
|
||||||
|
typedef typename std::remove_const<typename T::value_type>::type V;
|
||||||
|
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||||
|
|
||||||
|
// Disable timing while we perform some initialization.
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
assert(FLAGS_benchmark_values % 2 == 0);
|
||||||
|
|
||||||
|
T container;
|
||||||
|
|
||||||
|
const int half = FLAGS_benchmark_values / 2;
|
||||||
|
vector<int> remove_keys(half);
|
||||||
|
vector<int> add_keys(half);
|
||||||
|
|
||||||
|
for (int i = 0; i < half; i++) {
|
||||||
|
remove_keys[i] = i;
|
||||||
|
add_keys[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
RandGen rand(FLAGS_test_random_seed);
|
||||||
|
|
||||||
|
random_shuffle(remove_keys.begin(), remove_keys.end(), rand);
|
||||||
|
random_shuffle(add_keys.begin(), add_keys.end(), rand);
|
||||||
|
|
||||||
|
Generator<V> g(FLAGS_benchmark_values + FLAGS_benchmark_max_iters);
|
||||||
|
|
||||||
|
for (int i = 0; i < half; i++) {
|
||||||
|
container.insert(g(add_keys[i]));
|
||||||
|
container.insert(g(half + remove_keys[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// There are three parts each of size "half":
|
||||||
|
// 1 is being deleted from [offset - half, offset)
|
||||||
|
// 2 is standing [offset, offset + half)
|
||||||
|
// 3 is being inserted into [offset + half, offset + 2 * half)
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
StartBenchmarkTiming();
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
int idx = i % half;
|
||||||
|
|
||||||
|
if (idx == 0) {
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
random_shuffle(remove_keys.begin(), remove_keys.end(), rand);
|
||||||
|
random_shuffle(add_keys.begin(), add_keys.end(), rand);
|
||||||
|
offset += half;
|
||||||
|
StartBenchmarkTiming();
|
||||||
|
}
|
||||||
|
|
||||||
|
int e = container.erase(key_of_value(g(offset - half + remove_keys[idx])));
|
||||||
|
assert(e == 1);
|
||||||
|
container.insert(g(offset + half + add_keys[idx]));
|
||||||
|
}
|
||||||
|
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mixed insertion and deletion in the same range using pre-constructed values.
|
||||||
|
template <typename T>
|
||||||
|
void BM_MixedAddRem(int n) {
|
||||||
|
typedef typename std::remove_const<typename T::value_type>::type V;
|
||||||
|
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||||
|
|
||||||
|
// Disable timing while we perform some initialization.
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
assert(FLAGS_benchmark_values % 2 == 0);
|
||||||
|
|
||||||
|
T container;
|
||||||
|
RandGen rand(FLAGS_test_random_seed);
|
||||||
|
|
||||||
|
vector<V> values = GenerateValues<V>(FLAGS_benchmark_values * 2);
|
||||||
|
|
||||||
|
// Create two random shuffles
|
||||||
|
vector<int> remove_keys(FLAGS_benchmark_values);
|
||||||
|
vector<int> add_keys(FLAGS_benchmark_values);
|
||||||
|
|
||||||
|
// Insert the first half of the values (already in random order)
|
||||||
|
for (int i = 0; i < FLAGS_benchmark_values; i++) {
|
||||||
|
container.insert(values[i]);
|
||||||
|
|
||||||
|
// remove_keys and add_keys will be swapped before each round,
|
||||||
|
// therefore fill add_keys here w/ the keys being inserted, so
|
||||||
|
// they'll be the first to be removed.
|
||||||
|
remove_keys[i] = i + FLAGS_benchmark_values;
|
||||||
|
add_keys[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
StartBenchmarkTiming();
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
int idx = i % FLAGS_benchmark_values;
|
||||||
|
|
||||||
|
if (idx == 0) {
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
remove_keys.swap(add_keys);
|
||||||
|
random_shuffle(remove_keys.begin(), remove_keys.end(), rand);
|
||||||
|
random_shuffle(add_keys.begin(), add_keys.end(), rand);
|
||||||
|
StartBenchmarkTiming();
|
||||||
|
}
|
||||||
|
|
||||||
|
int e = container.erase(key_of_value(values[remove_keys[idx]]));
|
||||||
|
assert(e == 1);
|
||||||
|
container.insert(values[add_keys[idx]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insertion at end, removal from the beginning. This benchmark
|
||||||
|
// counts two value constructors.
|
||||||
|
template <typename T>
|
||||||
|
void BM_Fifo(int n) {
|
||||||
|
typedef typename std::remove_const<typename T::value_type>::type V;
|
||||||
|
|
||||||
|
// Disable timing while we perform some initialization.
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
|
||||||
|
T container;
|
||||||
|
Generator<V> g(FLAGS_benchmark_values + FLAGS_benchmark_max_iters);
|
||||||
|
|
||||||
|
for (int i = 0; i < FLAGS_benchmark_values; i++) {
|
||||||
|
container.insert(g(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
StartBenchmarkTiming();
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
container.erase(container.begin());
|
||||||
|
container.insert(container.end(), g(i + FLAGS_benchmark_values));
|
||||||
|
}
|
||||||
|
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iteration (forward) through the tree
|
||||||
|
template <typename T>
|
||||||
|
void BM_FwdIter(int n) {
|
||||||
|
typedef typename std::remove_const<typename T::value_type>::type V;
|
||||||
|
|
||||||
|
// Disable timing while we perform some initialization.
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
|
||||||
|
T container;
|
||||||
|
vector<V> values = GenerateValues<V>(FLAGS_benchmark_values);
|
||||||
|
|
||||||
|
for (int i = 0; i < FLAGS_benchmark_values; i++) {
|
||||||
|
container.insert(values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
typename T::iterator iter;
|
||||||
|
|
||||||
|
V r = V();
|
||||||
|
|
||||||
|
StartBenchmarkTiming();
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
int idx = i % FLAGS_benchmark_values;
|
||||||
|
|
||||||
|
if (idx == 0) {
|
||||||
|
iter = container.begin();
|
||||||
|
}
|
||||||
|
r = *iter;
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
StopBenchmarkTiming();
|
||||||
|
|
||||||
|
sink(r); // Keep compiler from optimizing away r.
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef set<int32_t> stl_set_int32;
|
||||||
|
typedef set<int64_t> stl_set_int64;
|
||||||
|
typedef set<string> stl_set_string;
|
||||||
|
|
||||||
|
typedef map<int32_t, intptr_t> stl_map_int32;
|
||||||
|
typedef map<int64_t, intptr_t> stl_map_int64;
|
||||||
|
typedef map<string, intptr_t> stl_map_string;
|
||||||
|
|
||||||
|
typedef multiset<int32_t> stl_multiset_int32;
|
||||||
|
typedef multiset<int64_t> stl_multiset_int64;
|
||||||
|
typedef multiset<string> stl_multiset_string;
|
||||||
|
|
||||||
|
typedef multimap<int32_t, intptr_t> stl_multimap_int32;
|
||||||
|
typedef multimap<int64_t, intptr_t> stl_multimap_int64;
|
||||||
|
typedef multimap<string, intptr_t> stl_multimap_string;
|
||||||
|
|
||||||
|
#define MY_BENCHMARK_TYPES2(value, name, size) \
|
||||||
|
typedef btree ## _set<value, less<value>, allocator<value>, size> \
|
||||||
|
btree ## _ ## size ## _set_ ## name; \
|
||||||
|
typedef btree ## _map<value, int, less<value>, allocator<value>, size> \
|
||||||
|
btree ## _ ## size ## _map_ ## name; \
|
||||||
|
typedef btree ## _multiset<value, less<value>, allocator<value>, size> \
|
||||||
|
btree ## _ ## size ## _multiset_ ## name; \
|
||||||
|
typedef btree ## _multimap<value, int, less<value>, allocator<value>, size> \
|
||||||
|
btree ## _ ## size ## _multimap_ ## name
|
||||||
|
|
||||||
|
#define MY_BENCHMARK_TYPES(value, name) \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 128); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 160); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 192); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 224); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 256); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 288); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 320); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 352); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 384); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 416); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 448); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 480); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 512); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 1024); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 1536); \
|
||||||
|
MY_BENCHMARK_TYPES2(value, name, 2048)
|
||||||
|
|
||||||
|
MY_BENCHMARK_TYPES(int32_t, int32);
|
||||||
|
MY_BENCHMARK_TYPES(int64_t, int64);
|
||||||
|
MY_BENCHMARK_TYPES(string, string);
|
||||||
|
|
||||||
|
#define MY_BENCHMARK4(type, name, func) \
|
||||||
|
void BM_ ## type ## _ ## name(int n) { BM_ ## func <type>(n); } \
|
||||||
|
BTREE_BENCHMARK(BM_ ## type ## _ ## name)
|
||||||
|
|
||||||
|
// Define NODESIZE_TESTING when running btree_perf.py.
|
||||||
|
|
||||||
|
#ifdef NODESIZE_TESTING
|
||||||
|
#define MY_BENCHMARK3(tree, type, name, func) \
|
||||||
|
MY_BENCHMARK4(tree ## _128_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _160_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _192_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _224_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _256_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _288_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _320_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _352_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _384_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _416_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _448_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _480_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _512_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _1024_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _1536_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _2048_ ## type, name, func)
|
||||||
|
#else
|
||||||
|
#define MY_BENCHMARK3(tree, type, name, func) \
|
||||||
|
MY_BENCHMARK4(tree ## _256_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK4(tree ## _2048_ ## type, name, func)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MY_BENCHMARK2(type, name, func) \
|
||||||
|
MY_BENCHMARK4(stl_ ## type, name, func); \
|
||||||
|
MY_BENCHMARK3(btree, type, name, func)
|
||||||
|
|
||||||
|
#define MY_BENCHMARK(type) \
|
||||||
|
MY_BENCHMARK2(type, insert, Insert); \
|
||||||
|
MY_BENCHMARK2(type, lookup, Lookup); \
|
||||||
|
MY_BENCHMARK2(type, fulllookup, FullLookup); \
|
||||||
|
MY_BENCHMARK2(type, delete, Delete); \
|
||||||
|
MY_BENCHMARK2(type, queueaddrem, QueueAddRem); \
|
||||||
|
MY_BENCHMARK2(type, mixedaddrem, MixedAddRem); \
|
||||||
|
MY_BENCHMARK2(type, fifo, Fifo); \
|
||||||
|
MY_BENCHMARK2(type, fwditer, FwdIter)
|
||||||
|
|
||||||
|
MY_BENCHMARK(set_int32);
|
||||||
|
MY_BENCHMARK(map_int32);
|
||||||
|
MY_BENCHMARK(set_int64);
|
||||||
|
MY_BENCHMARK(map_int64);
|
||||||
|
MY_BENCHMARK(set_string);
|
||||||
|
MY_BENCHMARK(map_string);
|
||||||
|
|
||||||
|
MY_BENCHMARK(multiset_int32);
|
||||||
|
MY_BENCHMARK(multimap_int32);
|
||||||
|
MY_BENCHMARK(multiset_int64);
|
||||||
|
MY_BENCHMARK(multimap_int64);
|
||||||
|
MY_BENCHMARK(multiset_string);
|
||||||
|
MY_BENCHMARK(multimap_string);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace btree
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
btree::RunBenchmarks();
|
||||||
|
return 0;
|
||||||
|
}
|
349
lib/xdelta3/cpp-btree/btree_container.h
Normal file
349
lib/xdelta3/cpp-btree/btree_container.h
Normal file
|
@ -0,0 +1,349 @@
|
||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef UTIL_BTREE_BTREE_CONTAINER_H__
|
||||||
|
#define UTIL_BTREE_BTREE_CONTAINER_H__
|
||||||
|
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "btree.h"
|
||||||
|
|
||||||
|
namespace btree {
|
||||||
|
|
||||||
|
// A common base class for btree_set, btree_map, btree_multiset and
|
||||||
|
// btree_multimap.
|
||||||
|
template <typename Tree>
|
||||||
|
class btree_container {
|
||||||
|
typedef btree_container<Tree> self_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename Tree::params_type params_type;
|
||||||
|
typedef typename Tree::key_type key_type;
|
||||||
|
typedef typename Tree::value_type value_type;
|
||||||
|
typedef typename Tree::key_compare key_compare;
|
||||||
|
typedef typename Tree::allocator_type allocator_type;
|
||||||
|
typedef typename Tree::pointer pointer;
|
||||||
|
typedef typename Tree::const_pointer const_pointer;
|
||||||
|
typedef typename Tree::reference reference;
|
||||||
|
typedef typename Tree::const_reference const_reference;
|
||||||
|
typedef typename Tree::size_type size_type;
|
||||||
|
typedef typename Tree::difference_type difference_type;
|
||||||
|
typedef typename Tree::iterator iterator;
|
||||||
|
typedef typename Tree::const_iterator const_iterator;
|
||||||
|
typedef typename Tree::reverse_iterator reverse_iterator;
|
||||||
|
typedef typename Tree::const_reverse_iterator const_reverse_iterator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Default constructor.
|
||||||
|
btree_container(const key_compare &comp, const allocator_type &alloc)
|
||||||
|
: tree_(comp, alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
btree_container(const self_type &x)
|
||||||
|
: tree_(x.tree_) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterator routines.
|
||||||
|
iterator begin() { return tree_.begin(); }
|
||||||
|
const_iterator begin() const { return tree_.begin(); }
|
||||||
|
iterator end() { return tree_.end(); }
|
||||||
|
const_iterator end() const { return tree_.end(); }
|
||||||
|
reverse_iterator rbegin() { return tree_.rbegin(); }
|
||||||
|
const_reverse_iterator rbegin() const { return tree_.rbegin(); }
|
||||||
|
reverse_iterator rend() { return tree_.rend(); }
|
||||||
|
const_reverse_iterator rend() const { return tree_.rend(); }
|
||||||
|
|
||||||
|
// Lookup routines.
|
||||||
|
iterator lower_bound(const key_type &key) {
|
||||||
|
return tree_.lower_bound(key);
|
||||||
|
}
|
||||||
|
const_iterator lower_bound(const key_type &key) const {
|
||||||
|
return tree_.lower_bound(key);
|
||||||
|
}
|
||||||
|
iterator upper_bound(const key_type &key) {
|
||||||
|
return tree_.upper_bound(key);
|
||||||
|
}
|
||||||
|
const_iterator upper_bound(const key_type &key) const {
|
||||||
|
return tree_.upper_bound(key);
|
||||||
|
}
|
||||||
|
std::pair<iterator,iterator> equal_range(const key_type &key) {
|
||||||
|
return tree_.equal_range(key);
|
||||||
|
}
|
||||||
|
std::pair<const_iterator,const_iterator> equal_range(const key_type &key) const {
|
||||||
|
return tree_.equal_range(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility routines.
|
||||||
|
void clear() {
|
||||||
|
tree_.clear();
|
||||||
|
}
|
||||||
|
void swap(self_type &x) {
|
||||||
|
tree_.swap(x.tree_);
|
||||||
|
}
|
||||||
|
void dump(std::ostream &os) const {
|
||||||
|
tree_.dump(os);
|
||||||
|
}
|
||||||
|
void verify() const {
|
||||||
|
tree_.verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size routines.
|
||||||
|
size_type size() const { return tree_.size(); }
|
||||||
|
size_type max_size() const { return tree_.max_size(); }
|
||||||
|
bool empty() const { return tree_.empty(); }
|
||||||
|
size_type height() const { return tree_.height(); }
|
||||||
|
size_type internal_nodes() const { return tree_.internal_nodes(); }
|
||||||
|
size_type leaf_nodes() const { return tree_.leaf_nodes(); }
|
||||||
|
size_type nodes() const { return tree_.nodes(); }
|
||||||
|
size_type bytes_used() const { return tree_.bytes_used(); }
|
||||||
|
static double average_bytes_per_value() {
|
||||||
|
return Tree::average_bytes_per_value();
|
||||||
|
}
|
||||||
|
double fullness() const { return tree_.fullness(); }
|
||||||
|
double overhead() const { return tree_.overhead(); }
|
||||||
|
|
||||||
|
bool operator==(const self_type& x) const {
|
||||||
|
if (size() != x.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const_iterator i = begin(), xi = x.begin(); i != end(); ++i, ++xi) {
|
||||||
|
if (*i != *xi) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const self_type& other) const {
|
||||||
|
return !operator==(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Tree tree_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline std::ostream& operator<<(std::ostream &os, const btree_container<T> &b) {
|
||||||
|
b.dump(os);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A common base class for btree_set and safe_btree_set.
|
||||||
|
template <typename Tree>
|
||||||
|
class btree_unique_container : public btree_container<Tree> {
|
||||||
|
typedef btree_unique_container<Tree> self_type;
|
||||||
|
typedef btree_container<Tree> super_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename Tree::key_type key_type;
|
||||||
|
typedef typename Tree::value_type value_type;
|
||||||
|
typedef typename Tree::size_type size_type;
|
||||||
|
typedef typename Tree::key_compare key_compare;
|
||||||
|
typedef typename Tree::allocator_type allocator_type;
|
||||||
|
typedef typename Tree::iterator iterator;
|
||||||
|
typedef typename Tree::const_iterator const_iterator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Default constructor.
|
||||||
|
btree_unique_container(const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(comp, alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
btree_unique_container(const self_type &x)
|
||||||
|
: super_type(x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range constructor.
|
||||||
|
template <class InputIterator>
|
||||||
|
btree_unique_container(InputIterator b, InputIterator e,
|
||||||
|
const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(comp, alloc) {
|
||||||
|
insert(b, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup routines.
|
||||||
|
iterator find(const key_type &key) {
|
||||||
|
return this->tree_.find_unique(key);
|
||||||
|
}
|
||||||
|
const_iterator find(const key_type &key) const {
|
||||||
|
return this->tree_.find_unique(key);
|
||||||
|
}
|
||||||
|
size_type count(const key_type &key) const {
|
||||||
|
return this->tree_.count_unique(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insertion routines.
|
||||||
|
std::pair<iterator,bool> insert(const value_type &x) {
|
||||||
|
return this->tree_.insert_unique(x);
|
||||||
|
}
|
||||||
|
iterator insert(iterator position, const value_type &x) {
|
||||||
|
return this->tree_.insert_unique(position, x);
|
||||||
|
}
|
||||||
|
template <typename InputIterator>
|
||||||
|
void insert(InputIterator b, InputIterator e) {
|
||||||
|
this->tree_.insert_unique(b, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletion routines.
|
||||||
|
int erase(const key_type &key) {
|
||||||
|
return this->tree_.erase_unique(key);
|
||||||
|
}
|
||||||
|
// Erase the specified iterator from the btree. The iterator must be valid
|
||||||
|
// (i.e. not equal to end()). Return an iterator pointing to the node after
|
||||||
|
// the one that was erased (or end() if none exists).
|
||||||
|
iterator erase(const iterator &iter) {
|
||||||
|
return this->tree_.erase(iter);
|
||||||
|
}
|
||||||
|
void erase(const iterator &first, const iterator &last) {
|
||||||
|
this->tree_.erase(first, last);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A common base class for btree_map and safe_btree_map.
|
||||||
|
template <typename Tree>
|
||||||
|
class btree_map_container : public btree_unique_container<Tree> {
|
||||||
|
typedef btree_map_container<Tree> self_type;
|
||||||
|
typedef btree_unique_container<Tree> super_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename Tree::key_type key_type;
|
||||||
|
typedef typename Tree::data_type data_type;
|
||||||
|
typedef typename Tree::value_type value_type;
|
||||||
|
typedef typename Tree::mapped_type mapped_type;
|
||||||
|
typedef typename Tree::key_compare key_compare;
|
||||||
|
typedef typename Tree::allocator_type allocator_type;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// A pointer-like object which only generates its value when
|
||||||
|
// dereferenced. Used by operator[] to avoid constructing an empty data_type
|
||||||
|
// if the key already exists in the map.
|
||||||
|
struct generate_value {
|
||||||
|
generate_value(const key_type &k)
|
||||||
|
: key(k) {
|
||||||
|
}
|
||||||
|
value_type operator*() const {
|
||||||
|
return std::make_pair(key, data_type());
|
||||||
|
}
|
||||||
|
const key_type &key;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Default constructor.
|
||||||
|
btree_map_container(const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(comp, alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
btree_map_container(const self_type &x)
|
||||||
|
: super_type(x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range constructor.
|
||||||
|
template <class InputIterator>
|
||||||
|
btree_map_container(InputIterator b, InputIterator e,
|
||||||
|
const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(b, e, comp, alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insertion routines.
|
||||||
|
data_type& operator[](const key_type &key) {
|
||||||
|
return this->tree_.insert_unique(key, generate_value(key)).first->second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A common base class for btree_multiset and btree_multimap.
|
||||||
|
template <typename Tree>
|
||||||
|
class btree_multi_container : public btree_container<Tree> {
|
||||||
|
typedef btree_multi_container<Tree> self_type;
|
||||||
|
typedef btree_container<Tree> super_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename Tree::key_type key_type;
|
||||||
|
typedef typename Tree::value_type value_type;
|
||||||
|
typedef typename Tree::size_type size_type;
|
||||||
|
typedef typename Tree::key_compare key_compare;
|
||||||
|
typedef typename Tree::allocator_type allocator_type;
|
||||||
|
typedef typename Tree::iterator iterator;
|
||||||
|
typedef typename Tree::const_iterator const_iterator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Default constructor.
|
||||||
|
btree_multi_container(const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(comp, alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
btree_multi_container(const self_type &x)
|
||||||
|
: super_type(x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range constructor.
|
||||||
|
template <class InputIterator>
|
||||||
|
btree_multi_container(InputIterator b, InputIterator e,
|
||||||
|
const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(comp, alloc) {
|
||||||
|
insert(b, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup routines.
|
||||||
|
iterator find(const key_type &key) {
|
||||||
|
return this->tree_.find_multi(key);
|
||||||
|
}
|
||||||
|
const_iterator find(const key_type &key) const {
|
||||||
|
return this->tree_.find_multi(key);
|
||||||
|
}
|
||||||
|
size_type count(const key_type &key) const {
|
||||||
|
return this->tree_.count_multi(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insertion routines.
|
||||||
|
iterator insert(const value_type &x) {
|
||||||
|
return this->tree_.insert_multi(x);
|
||||||
|
}
|
||||||
|
iterator insert(iterator position, const value_type &x) {
|
||||||
|
return this->tree_.insert_multi(position, x);
|
||||||
|
}
|
||||||
|
template <typename InputIterator>
|
||||||
|
void insert(InputIterator b, InputIterator e) {
|
||||||
|
this->tree_.insert_multi(b, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletion routines.
|
||||||
|
int erase(const key_type &key) {
|
||||||
|
return this->tree_.erase_multi(key);
|
||||||
|
}
|
||||||
|
// Erase the specified iterator from the btree. The iterator must be valid
|
||||||
|
// (i.e. not equal to end()). Return an iterator pointing to the node after
|
||||||
|
// the one that was erased (or end() if none exists).
|
||||||
|
iterator erase(const iterator &iter) {
|
||||||
|
return this->tree_.erase(iter);
|
||||||
|
}
|
||||||
|
void erase(const iterator &first, const iterator &last) {
|
||||||
|
this->tree_.erase(first, last);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace btree
|
||||||
|
|
||||||
|
#endif // UTIL_BTREE_BTREE_CONTAINER_H__
|
130
lib/xdelta3/cpp-btree/btree_map.h
Normal file
130
lib/xdelta3/cpp-btree/btree_map.h
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// A btree_map<> implements the STL unique sorted associative container
|
||||||
|
// interface and the pair associative container interface (a.k.a map<>) using a
|
||||||
|
// btree. A btree_multimap<> implements the STL multiple sorted associative
|
||||||
|
// container interface and the pair associtive container interface (a.k.a
|
||||||
|
// multimap<>) using a btree. See btree.h for details of the btree
|
||||||
|
// implementation and caveats.
|
||||||
|
|
||||||
|
#ifndef UTIL_BTREE_BTREE_MAP_H__
|
||||||
|
#define UTIL_BTREE_BTREE_MAP_H__
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "btree.h"
|
||||||
|
#include "btree_container.h"
|
||||||
|
|
||||||
|
namespace btree {
|
||||||
|
|
||||||
|
// The btree_map class is needed mainly for its constructors.
|
||||||
|
template <typename Key, typename Value,
|
||||||
|
typename Compare = std::less<Key>,
|
||||||
|
typename Alloc = std::allocator<std::pair<const Key, Value> >,
|
||||||
|
int TargetNodeSize = 256>
|
||||||
|
class btree_map : public btree_map_container<
|
||||||
|
btree<btree_map_params<Key, Value, Compare, Alloc, TargetNodeSize> > > {
|
||||||
|
|
||||||
|
typedef btree_map<Key, Value, Compare, Alloc, TargetNodeSize> self_type;
|
||||||
|
typedef btree_map_params<
|
||||||
|
Key, Value, Compare, Alloc, TargetNodeSize> params_type;
|
||||||
|
typedef btree<params_type> btree_type;
|
||||||
|
typedef btree_map_container<btree_type> super_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename btree_type::key_compare key_compare;
|
||||||
|
typedef typename btree_type::allocator_type allocator_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Default constructor.
|
||||||
|
btree_map(const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(comp, alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
btree_map(const self_type &x)
|
||||||
|
: super_type(x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range constructor.
|
||||||
|
template <class InputIterator>
|
||||||
|
btree_map(InputIterator b, InputIterator e,
|
||||||
|
const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(b, e, comp, alloc) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K, typename V, typename C, typename A, int N>
|
||||||
|
inline void swap(btree_map<K, V, C, A, N> &x,
|
||||||
|
btree_map<K, V, C, A, N> &y) {
|
||||||
|
x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The btree_multimap class is needed mainly for its constructors.
|
||||||
|
template <typename Key, typename Value,
|
||||||
|
typename Compare = std::less<Key>,
|
||||||
|
typename Alloc = std::allocator<std::pair<const Key, Value> >,
|
||||||
|
int TargetNodeSize = 256>
|
||||||
|
class btree_multimap : public btree_multi_container<
|
||||||
|
btree<btree_map_params<Key, Value, Compare, Alloc, TargetNodeSize> > > {
|
||||||
|
|
||||||
|
typedef btree_multimap<Key, Value, Compare, Alloc, TargetNodeSize> self_type;
|
||||||
|
typedef btree_map_params<
|
||||||
|
Key, Value, Compare, Alloc, TargetNodeSize> params_type;
|
||||||
|
typedef btree<params_type> btree_type;
|
||||||
|
typedef btree_multi_container<btree_type> super_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename btree_type::key_compare key_compare;
|
||||||
|
typedef typename btree_type::allocator_type allocator_type;
|
||||||
|
typedef typename btree_type::data_type data_type;
|
||||||
|
typedef typename btree_type::mapped_type mapped_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Default constructor.
|
||||||
|
btree_multimap(const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(comp, alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
btree_multimap(const self_type &x)
|
||||||
|
: super_type(x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range constructor.
|
||||||
|
template <class InputIterator>
|
||||||
|
btree_multimap(InputIterator b, InputIterator e,
|
||||||
|
const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(b, e, comp, alloc) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K, typename V, typename C, typename A, int N>
|
||||||
|
inline void swap(btree_multimap<K, V, C, A, N> &x,
|
||||||
|
btree_multimap<K, V, C, A, N> &y) {
|
||||||
|
x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace btree
|
||||||
|
|
||||||
|
#endif // UTIL_BTREE_BTREE_MAP_H__
|
121
lib/xdelta3/cpp-btree/btree_set.h
Normal file
121
lib/xdelta3/cpp-btree/btree_set.h
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// A btree_set<> implements the STL unique sorted associative container
|
||||||
|
// interface (a.k.a set<>) using a btree. A btree_multiset<> implements the STL
|
||||||
|
// multiple sorted associative container interface (a.k.a multiset<>) using a
|
||||||
|
// btree. See btree.h for details of the btree implementation and caveats.
|
||||||
|
|
||||||
|
#ifndef UTIL_BTREE_BTREE_SET_H__
|
||||||
|
#define UTIL_BTREE_BTREE_SET_H__
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "btree.h"
|
||||||
|
#include "btree_container.h"
|
||||||
|
|
||||||
|
namespace btree {
|
||||||
|
|
||||||
|
// The btree_set class is needed mainly for its constructors.
|
||||||
|
template <typename Key,
|
||||||
|
typename Compare = std::less<Key>,
|
||||||
|
typename Alloc = std::allocator<Key>,
|
||||||
|
int TargetNodeSize = 256>
|
||||||
|
class btree_set : public btree_unique_container<
|
||||||
|
btree<btree_set_params<Key, Compare, Alloc, TargetNodeSize> > > {
|
||||||
|
|
||||||
|
typedef btree_set<Key, Compare, Alloc, TargetNodeSize> self_type;
|
||||||
|
typedef btree_set_params<Key, Compare, Alloc, TargetNodeSize> params_type;
|
||||||
|
typedef btree<params_type> btree_type;
|
||||||
|
typedef btree_unique_container<btree_type> super_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename btree_type::key_compare key_compare;
|
||||||
|
typedef typename btree_type::allocator_type allocator_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Default constructor.
|
||||||
|
btree_set(const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(comp, alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
btree_set(const self_type &x)
|
||||||
|
: super_type(x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range constructor.
|
||||||
|
template <class InputIterator>
|
||||||
|
btree_set(InputIterator b, InputIterator e,
|
||||||
|
const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(b, e, comp, alloc) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K, typename C, typename A, int N>
|
||||||
|
inline void swap(btree_set<K, C, A, N> &x, btree_set<K, C, A, N> &y) {
|
||||||
|
x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The btree_multiset class is needed mainly for its constructors.
|
||||||
|
template <typename Key,
|
||||||
|
typename Compare = std::less<Key>,
|
||||||
|
typename Alloc = std::allocator<Key>,
|
||||||
|
int TargetNodeSize = 256>
|
||||||
|
class btree_multiset : public btree_multi_container<
|
||||||
|
btree<btree_set_params<Key, Compare, Alloc, TargetNodeSize> > > {
|
||||||
|
|
||||||
|
typedef btree_multiset<Key, Compare, Alloc, TargetNodeSize> self_type;
|
||||||
|
typedef btree_set_params<Key, Compare, Alloc, TargetNodeSize> params_type;
|
||||||
|
typedef btree<params_type> btree_type;
|
||||||
|
typedef btree_multi_container<btree_type> super_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename btree_type::key_compare key_compare;
|
||||||
|
typedef typename btree_type::allocator_type allocator_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Default constructor.
|
||||||
|
btree_multiset(const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(comp, alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
btree_multiset(const self_type &x)
|
||||||
|
: super_type(x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range constructor.
|
||||||
|
template <class InputIterator>
|
||||||
|
btree_multiset(InputIterator b, InputIterator e,
|
||||||
|
const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(b, e, comp, alloc) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K, typename C, typename A, int N>
|
||||||
|
inline void swap(btree_multiset<K, C, A, N> &x,
|
||||||
|
btree_multiset<K, C, A, N> &y) {
|
||||||
|
x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace btree
|
||||||
|
|
||||||
|
#endif // UTIL_BTREE_BTREE_SET_H__
|
270
lib/xdelta3/cpp-btree/btree_test.cc
Normal file
270
lib/xdelta3/cpp-btree/btree_test.cc
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "btree_map.h"
|
||||||
|
#include "btree_set.h"
|
||||||
|
#include "btree_test.h"
|
||||||
|
|
||||||
|
namespace btree {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <typename K, int N>
|
||||||
|
void SetTest() {
|
||||||
|
typedef TestAllocator<K> TestAlloc;
|
||||||
|
ASSERT_EQ(sizeof(btree_set<K>), sizeof(void*));
|
||||||
|
BtreeTest<btree_set<K, std::less<K>, std::allocator<K>, N>, std::set<K> >();
|
||||||
|
BtreeAllocatorTest<btree_set<K, std::less<K>, TestAlloc, N> >();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename K, int N>
|
||||||
|
void MapTest() {
|
||||||
|
typedef TestAllocator<K> TestAlloc;
|
||||||
|
ASSERT_EQ(sizeof(btree_map<K, K>), sizeof(void*));
|
||||||
|
BtreeTest<btree_map<K, K, std::less<K>, std::allocator<K>, N>, std::map<K, K> >();
|
||||||
|
BtreeAllocatorTest<btree_map<K, K, std::less<K>, TestAlloc, N> >();
|
||||||
|
BtreeMapTest<btree_map<K, K, std::less<K>, std::allocator<K>, N> >();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Btree, set_int32_32) { SetTest<int32_t, 32>(); }
|
||||||
|
TEST(Btree, set_int32_64) { SetTest<int32_t, 64>(); }
|
||||||
|
TEST(Btree, set_int32_128) { SetTest<int32_t, 128>(); }
|
||||||
|
TEST(Btree, set_int32_256) { SetTest<int32_t, 256>(); }
|
||||||
|
TEST(Btree, set_int64_256) { SetTest<int64_t, 256>(); }
|
||||||
|
TEST(Btree, set_string_256) { SetTest<std::string, 256>(); }
|
||||||
|
TEST(Btree, set_pair_256) { SetTest<std::pair<int, int>, 256>(); }
|
||||||
|
TEST(Btree, map_int32_256) { MapTest<int32_t, 256>(); }
|
||||||
|
TEST(Btree, map_int64_256) { MapTest<int64_t, 256>(); }
|
||||||
|
TEST(Btree, map_string_256) { MapTest<std::string, 256>(); }
|
||||||
|
TEST(Btree, map_pair_256) { MapTest<std::pair<int, int>, 256>(); }
|
||||||
|
|
||||||
|
// Large-node tests
|
||||||
|
TEST(Btree, map_int32_1024) { MapTest<int32_t, 1024>(); }
|
||||||
|
TEST(Btree, map_int32_1032) { MapTest<int32_t, 1032>(); }
|
||||||
|
TEST(Btree, map_int32_1040) { MapTest<int32_t, 1040>(); }
|
||||||
|
TEST(Btree, map_int32_1048) { MapTest<int32_t, 1048>(); }
|
||||||
|
TEST(Btree, map_int32_1056) { MapTest<int32_t, 1056>(); }
|
||||||
|
|
||||||
|
TEST(Btree, map_int32_2048) { MapTest<int32_t, 2048>(); }
|
||||||
|
TEST(Btree, map_int32_4096) { MapTest<int32_t, 4096>(); }
|
||||||
|
TEST(Btree, set_int32_1024) { SetTest<int32_t, 1024>(); }
|
||||||
|
TEST(Btree, set_int32_2048) { SetTest<int32_t, 2048>(); }
|
||||||
|
TEST(Btree, set_int32_4096) { SetTest<int32_t, 4096>(); }
|
||||||
|
TEST(Btree, map_string_1024) { MapTest<std::string, 1024>(); }
|
||||||
|
TEST(Btree, map_string_2048) { MapTest<std::string, 2048>(); }
|
||||||
|
TEST(Btree, map_string_4096) { MapTest<std::string, 4096>(); }
|
||||||
|
TEST(Btree, set_string_1024) { SetTest<std::string, 1024>(); }
|
||||||
|
TEST(Btree, set_string_2048) { SetTest<std::string, 2048>(); }
|
||||||
|
TEST(Btree, set_string_4096) { SetTest<std::string, 4096>(); }
|
||||||
|
|
||||||
|
template <typename K, int N>
|
||||||
|
void MultiSetTest() {
|
||||||
|
typedef TestAllocator<K> TestAlloc;
|
||||||
|
ASSERT_EQ(sizeof(btree_multiset<K>), sizeof(void*));
|
||||||
|
BtreeMultiTest<btree_multiset<K, std::less<K>, std::allocator<K>, N>,
|
||||||
|
std::multiset<K> >();
|
||||||
|
BtreeAllocatorTest<btree_multiset<K, std::less<K>, TestAlloc, N> >();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename K, int N>
|
||||||
|
void MultiMapTest() {
|
||||||
|
typedef TestAllocator<K> TestAlloc;
|
||||||
|
ASSERT_EQ(sizeof(btree_multimap<K, K>), sizeof(void*));
|
||||||
|
BtreeMultiTest<btree_multimap<K, K, std::less<K>, std::allocator<K>, N>,
|
||||||
|
std::multimap<K, K> >();
|
||||||
|
BtreeMultiMapTest<btree_multimap<K, K, std::less<K>, std::allocator<K>, N> >();
|
||||||
|
BtreeAllocatorTest<btree_multimap<K, K, std::less<K>, TestAlloc, N> >();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Btree, multiset_int32_256) { MultiSetTest<int32_t, 256>(); }
|
||||||
|
TEST(Btree, multiset_int64_256) { MultiSetTest<int64_t, 256>(); }
|
||||||
|
TEST(Btree, multiset_string_256) { MultiSetTest<std::string, 256>(); }
|
||||||
|
TEST(Btree, multiset_pair_256) { MultiSetTest<std::pair<int, int>, 256>(); }
|
||||||
|
TEST(Btree, multimap_int32_256) { MultiMapTest<int32_t, 256>(); }
|
||||||
|
TEST(Btree, multimap_int64_256) { MultiMapTest<int64_t, 256>(); }
|
||||||
|
TEST(Btree, multimap_string_256) { MultiMapTest<std::string, 256>(); }
|
||||||
|
TEST(Btree, multimap_pair_256) { MultiMapTest<std::pair<int, int>, 256>(); }
|
||||||
|
|
||||||
|
// Large-node tests
|
||||||
|
TEST(Btree, multimap_int32_1024) { MultiMapTest<int32_t, 1024>(); }
|
||||||
|
TEST(Btree, multimap_int32_2048) { MultiMapTest<int32_t, 2048>(); }
|
||||||
|
TEST(Btree, multimap_int32_4096) { MultiMapTest<int32_t, 4096>(); }
|
||||||
|
TEST(Btree, multiset_int32_1024) { MultiSetTest<int32_t, 1024>(); }
|
||||||
|
TEST(Btree, multiset_int32_2048) { MultiSetTest<int32_t, 2048>(); }
|
||||||
|
TEST(Btree, multiset_int32_4096) { MultiSetTest<int32_t, 4096>(); }
|
||||||
|
TEST(Btree, multimap_string_1024) { MultiMapTest<std::string, 1024>(); }
|
||||||
|
TEST(Btree, multimap_string_2048) { MultiMapTest<std::string, 2048>(); }
|
||||||
|
TEST(Btree, multimap_string_4096) { MultiMapTest<std::string, 4096>(); }
|
||||||
|
TEST(Btree, multiset_string_1024) { MultiSetTest<std::string, 1024>(); }
|
||||||
|
TEST(Btree, multiset_string_2048) { MultiSetTest<std::string, 2048>(); }
|
||||||
|
TEST(Btree, multiset_string_4096) { MultiSetTest<std::string, 4096>(); }
|
||||||
|
|
||||||
|
// Verify that swapping btrees swaps the key comparision functors.
|
||||||
|
struct SubstringLess {
|
||||||
|
SubstringLess() : n(2) {}
|
||||||
|
SubstringLess(size_t length)
|
||||||
|
: n(length) {
|
||||||
|
}
|
||||||
|
bool operator()(const std::string &a, const std::string &b) const {
|
||||||
|
std::string as(a.data(), std::min(n, a.size()));
|
||||||
|
std::string bs(b.data(), std::min(n, b.size()));
|
||||||
|
return as < bs;
|
||||||
|
}
|
||||||
|
size_t n;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(Btree, SwapKeyCompare) {
|
||||||
|
typedef btree_set<std::string, SubstringLess> SubstringSet;
|
||||||
|
SubstringSet s1(SubstringLess(1), SubstringSet::allocator_type());
|
||||||
|
SubstringSet s2(SubstringLess(2), SubstringSet::allocator_type());
|
||||||
|
|
||||||
|
ASSERT_TRUE(s1.insert("a").second);
|
||||||
|
ASSERT_FALSE(s1.insert("aa").second);
|
||||||
|
|
||||||
|
ASSERT_TRUE(s2.insert("a").second);
|
||||||
|
ASSERT_TRUE(s2.insert("aa").second);
|
||||||
|
ASSERT_FALSE(s2.insert("aaa").second);
|
||||||
|
|
||||||
|
swap(s1, s2);
|
||||||
|
|
||||||
|
ASSERT_TRUE(s1.insert("b").second);
|
||||||
|
ASSERT_TRUE(s1.insert("bb").second);
|
||||||
|
ASSERT_FALSE(s1.insert("bbb").second);
|
||||||
|
|
||||||
|
ASSERT_TRUE(s2.insert("b").second);
|
||||||
|
ASSERT_FALSE(s2.insert("bb").second);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Btree, UpperBoundRegression) {
|
||||||
|
// Regress a bug where upper_bound would default-construct a new key_compare
|
||||||
|
// instead of copying the existing one.
|
||||||
|
typedef btree_set<std::string, SubstringLess> SubstringSet;
|
||||||
|
SubstringSet my_set(SubstringLess(3));
|
||||||
|
my_set.insert("aab");
|
||||||
|
my_set.insert("abb");
|
||||||
|
// We call upper_bound("aaa"). If this correctly uses the length 3
|
||||||
|
// comparator, aaa < aab < abb, so we should get aab as the result.
|
||||||
|
// If it instead uses the default-constructed length 2 comparator,
|
||||||
|
// aa == aa < ab, so we'll get abb as our result.
|
||||||
|
SubstringSet::iterator it = my_set.upper_bound("aaa");
|
||||||
|
ASSERT_TRUE(it != my_set.end());
|
||||||
|
EXPECT_EQ("aab", *it);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(Btree, IteratorIncrementBy) {
|
||||||
|
// Test that increment_by returns the same position as increment.
|
||||||
|
const int kSetSize = 2341;
|
||||||
|
btree_set<int32_t> my_set;
|
||||||
|
for (int i = 0; i < kSetSize; ++i) {
|
||||||
|
my_set.insert(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Simple increment vs. increment by.
|
||||||
|
btree_set<int32_t>::iterator a = my_set.begin();
|
||||||
|
btree_set<int32_t>::iterator b = my_set.begin();
|
||||||
|
a.increment();
|
||||||
|
b.increment_by(1);
|
||||||
|
EXPECT_EQ(*a, *b);
|
||||||
|
}
|
||||||
|
|
||||||
|
btree_set<int32_t>::iterator a = my_set.begin();
|
||||||
|
for (int i = 1; i < kSetSize; ++i) {
|
||||||
|
++a;
|
||||||
|
// increment_by
|
||||||
|
btree_set<int32_t>::iterator b = my_set.begin();
|
||||||
|
b.increment_by(i);
|
||||||
|
EXPECT_EQ(*a, *b) << ": i=" << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Btree, Comparison) {
|
||||||
|
const int kSetSize = 1201;
|
||||||
|
btree_set<int64_t> my_set;
|
||||||
|
for (int i = 0; i < kSetSize; ++i) {
|
||||||
|
my_set.insert(i);
|
||||||
|
}
|
||||||
|
btree_set<int64_t> my_set_copy(my_set);
|
||||||
|
EXPECT_TRUE(my_set_copy == my_set);
|
||||||
|
EXPECT_TRUE(my_set == my_set_copy);
|
||||||
|
EXPECT_FALSE(my_set_copy != my_set);
|
||||||
|
EXPECT_FALSE(my_set != my_set_copy);
|
||||||
|
|
||||||
|
my_set.insert(kSetSize);
|
||||||
|
EXPECT_FALSE(my_set_copy == my_set);
|
||||||
|
EXPECT_FALSE(my_set == my_set_copy);
|
||||||
|
EXPECT_TRUE(my_set_copy != my_set);
|
||||||
|
EXPECT_TRUE(my_set != my_set_copy);
|
||||||
|
|
||||||
|
my_set.erase(kSetSize - 1);
|
||||||
|
EXPECT_FALSE(my_set_copy == my_set);
|
||||||
|
EXPECT_FALSE(my_set == my_set_copy);
|
||||||
|
EXPECT_TRUE(my_set_copy != my_set);
|
||||||
|
EXPECT_TRUE(my_set != my_set_copy);
|
||||||
|
|
||||||
|
btree_map<std::string, int64_t> my_map;
|
||||||
|
for (int i = 0; i < kSetSize; ++i) {
|
||||||
|
my_map[std::string(i, 'a')] = i;
|
||||||
|
}
|
||||||
|
btree_map<std::string, int64_t> my_map_copy(my_map);
|
||||||
|
EXPECT_TRUE(my_map_copy == my_map);
|
||||||
|
EXPECT_TRUE(my_map == my_map_copy);
|
||||||
|
EXPECT_FALSE(my_map_copy != my_map);
|
||||||
|
EXPECT_FALSE(my_map != my_map_copy);
|
||||||
|
|
||||||
|
++my_map_copy[std::string(7, 'a')];
|
||||||
|
EXPECT_FALSE(my_map_copy == my_map);
|
||||||
|
EXPECT_FALSE(my_map == my_map_copy);
|
||||||
|
EXPECT_TRUE(my_map_copy != my_map);
|
||||||
|
EXPECT_TRUE(my_map != my_map_copy);
|
||||||
|
|
||||||
|
my_map_copy = my_map;
|
||||||
|
my_map["hello"] = kSetSize;
|
||||||
|
EXPECT_FALSE(my_map_copy == my_map);
|
||||||
|
EXPECT_FALSE(my_map == my_map_copy);
|
||||||
|
EXPECT_TRUE(my_map_copy != my_map);
|
||||||
|
EXPECT_TRUE(my_map != my_map_copy);
|
||||||
|
|
||||||
|
my_map.erase(std::string(kSetSize - 1, 'a'));
|
||||||
|
EXPECT_FALSE(my_map_copy == my_map);
|
||||||
|
EXPECT_FALSE(my_map == my_map_copy);
|
||||||
|
EXPECT_TRUE(my_map_copy != my_map);
|
||||||
|
EXPECT_TRUE(my_map != my_map_copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Btree, RangeCtorSanity) {
|
||||||
|
typedef btree_set<int, std::less<int>, std::allocator<int>, 256> test_set;
|
||||||
|
typedef btree_map<int, int, std::less<int>, std::allocator<int>, 256>
|
||||||
|
test_map;
|
||||||
|
typedef btree_multiset<int, std::less<int>, std::allocator<int>, 256>
|
||||||
|
test_mset;
|
||||||
|
typedef btree_multimap<int, int, std::less<int>, std::allocator<int>, 256>
|
||||||
|
test_mmap;
|
||||||
|
std::vector<int> ivec;
|
||||||
|
ivec.push_back(1);
|
||||||
|
std::map<int, int> imap;
|
||||||
|
imap.insert(std::make_pair(1, 2));
|
||||||
|
test_mset tmset(ivec.begin(), ivec.end());
|
||||||
|
test_mmap tmmap(imap.begin(), imap.end());
|
||||||
|
test_set tset(ivec.begin(), ivec.end());
|
||||||
|
test_map tmap(imap.begin(), imap.end());
|
||||||
|
EXPECT_EQ(1, tmset.size());
|
||||||
|
EXPECT_EQ(1, tmmap.size());
|
||||||
|
EXPECT_EQ(1, tset.size());
|
||||||
|
EXPECT_EQ(1, tmap.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace btree
|
940
lib/xdelta3/cpp-btree/btree_test.h
Normal file
940
lib/xdelta3/cpp-btree/btree_test.h
Normal file
|
@ -0,0 +1,940 @@
|
||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef UTIL_BTREE_BTREE_TEST_H__
|
||||||
|
#define UTIL_BTREE_BTREE_TEST_H__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "gflags/gflags.h"
|
||||||
|
#include "btree_container.h"
|
||||||
|
|
||||||
|
DECLARE_int32(test_values);
|
||||||
|
DECLARE_int32(benchmark_values);
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
// Provide operator<< support for std::pair<T, U>.
|
||||||
|
template <typename T, typename U>
|
||||||
|
ostream& operator<<(ostream &os, const std::pair<T, U> &p) {
|
||||||
|
os << "(" << p.first << "," << p.second << ")";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provide pair equality testing that works as long as x.first is comparable to
|
||||||
|
// y.first and x.second is comparable to y.second. Needed in the test for
|
||||||
|
// comparing std::pair<T, U> to std::pair<const T, U>.
|
||||||
|
template <typename T, typename U, typename V, typename W>
|
||||||
|
bool operator==(const std::pair<T, U> &x, const std::pair<V, W> &y) {
|
||||||
|
return x.first == y.first && x.second == y.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Partial specialization of remove_const that propagates the removal through
|
||||||
|
// std::pair.
|
||||||
|
template <typename T, typename U>
|
||||||
|
struct remove_const<pair<T, U> > {
|
||||||
|
typedef pair<typename remove_const<T>::type,
|
||||||
|
typename remove_const<U>::type> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
namespace btree {
|
||||||
|
|
||||||
|
// Select the first member of a pair.
|
||||||
|
template <class _Pair>
|
||||||
|
struct select1st : public std::unary_function<_Pair, typename _Pair::first_type> {
|
||||||
|
const typename _Pair::first_type& operator()(const _Pair& __x) const {
|
||||||
|
return __x.first;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Utility class to provide an accessor for a key given a value. The default
|
||||||
|
// behavior is to treat the value as a pair and return the first element.
|
||||||
|
template <typename K, typename V>
|
||||||
|
struct KeyOfValue {
|
||||||
|
typedef select1st<V> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct identity {
|
||||||
|
inline const T& operator()(const T& t) const { return t; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Partial specialization of KeyOfValue class for when the key and value are
|
||||||
|
// the same type such as in set<> and btree_set<>.
|
||||||
|
template <typename K>
|
||||||
|
struct KeyOfValue<K, K> {
|
||||||
|
typedef identity<K> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Counts the number of occurances of "c" in a buffer.
|
||||||
|
inline ptrdiff_t strcount(const char* buf_begin, const char* buf_end, char c) {
|
||||||
|
if (buf_begin == NULL)
|
||||||
|
return 0;
|
||||||
|
if (buf_end <= buf_begin)
|
||||||
|
return 0;
|
||||||
|
ptrdiff_t num = 0;
|
||||||
|
for (const char* bp = buf_begin; bp != buf_end; bp++) {
|
||||||
|
if (*bp == c)
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for when the string is not null-terminated.
|
||||||
|
inline ptrdiff_t strcount(const char* buf, size_t len, char c) {
|
||||||
|
return strcount(buf, buf + len, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ptrdiff_t strcount(const std::string& buf, char c) {
|
||||||
|
return strcount(buf.c_str(), buf.size(), c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The base class for a sorted associative container checker. TreeType is the
|
||||||
|
// container type to check and CheckerType is the container type to check
|
||||||
|
// against. TreeType is expected to be btree_{set,map,multiset,multimap} and
|
||||||
|
// CheckerType is expected to be {set,map,multiset,multimap}.
|
||||||
|
template <typename TreeType, typename CheckerType>
|
||||||
|
class base_checker {
|
||||||
|
typedef base_checker<TreeType, CheckerType> self_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename TreeType::key_type key_type;
|
||||||
|
typedef typename TreeType::value_type value_type;
|
||||||
|
typedef typename TreeType::key_compare key_compare;
|
||||||
|
typedef typename TreeType::pointer pointer;
|
||||||
|
typedef typename TreeType::const_pointer const_pointer;
|
||||||
|
typedef typename TreeType::reference reference;
|
||||||
|
typedef typename TreeType::const_reference const_reference;
|
||||||
|
typedef typename TreeType::size_type size_type;
|
||||||
|
typedef typename TreeType::difference_type difference_type;
|
||||||
|
typedef typename TreeType::iterator iterator;
|
||||||
|
typedef typename TreeType::const_iterator const_iterator;
|
||||||
|
typedef typename TreeType::reverse_iterator reverse_iterator;
|
||||||
|
typedef typename TreeType::const_reverse_iterator const_reverse_iterator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Default constructor.
|
||||||
|
base_checker()
|
||||||
|
: const_tree_(tree_) {
|
||||||
|
}
|
||||||
|
// Copy constructor.
|
||||||
|
base_checker(const self_type &x)
|
||||||
|
: tree_(x.tree_),
|
||||||
|
const_tree_(tree_),
|
||||||
|
checker_(x.checker_) {
|
||||||
|
}
|
||||||
|
// Range constructor.
|
||||||
|
template <typename InputIterator>
|
||||||
|
base_checker(InputIterator b, InputIterator e)
|
||||||
|
: tree_(b, e),
|
||||||
|
const_tree_(tree_),
|
||||||
|
checker_(b, e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterator routines.
|
||||||
|
iterator begin() { return tree_.begin(); }
|
||||||
|
const_iterator begin() const { return tree_.begin(); }
|
||||||
|
iterator end() { return tree_.end(); }
|
||||||
|
const_iterator end() const { return tree_.end(); }
|
||||||
|
reverse_iterator rbegin() { return tree_.rbegin(); }
|
||||||
|
const_reverse_iterator rbegin() const { return tree_.rbegin(); }
|
||||||
|
reverse_iterator rend() { return tree_.rend(); }
|
||||||
|
const_reverse_iterator rend() const { return tree_.rend(); }
|
||||||
|
|
||||||
|
// Helper routines.
|
||||||
|
template <typename IterType, typename CheckerIterType>
|
||||||
|
IterType iter_check(
|
||||||
|
IterType tree_iter, CheckerIterType checker_iter) const {
|
||||||
|
if (tree_iter == tree_.end()) {
|
||||||
|
EXPECT_EQ(checker_iter, checker_.end());
|
||||||
|
} else {
|
||||||
|
EXPECT_EQ(*tree_iter, *checker_iter);
|
||||||
|
}
|
||||||
|
return tree_iter;
|
||||||
|
}
|
||||||
|
template <typename IterType, typename CheckerIterType>
|
||||||
|
IterType riter_check(
|
||||||
|
IterType tree_iter, CheckerIterType checker_iter) const {
|
||||||
|
if (tree_iter == tree_.rend()) {
|
||||||
|
EXPECT_EQ(checker_iter, checker_.rend());
|
||||||
|
} else {
|
||||||
|
EXPECT_EQ(*tree_iter, *checker_iter);
|
||||||
|
}
|
||||||
|
return tree_iter;
|
||||||
|
}
|
||||||
|
void value_check(const value_type &x) {
|
||||||
|
typename KeyOfValue<typename TreeType::key_type,
|
||||||
|
typename TreeType::value_type>::type key_of_value;
|
||||||
|
const key_type &key = key_of_value(x);
|
||||||
|
EXPECT_EQ(*find(key), x);
|
||||||
|
lower_bound(key);
|
||||||
|
upper_bound(key);
|
||||||
|
equal_range(key);
|
||||||
|
count(key);
|
||||||
|
}
|
||||||
|
void erase_check(const key_type &key) {
|
||||||
|
EXPECT_TRUE(tree_.find(key) == const_tree_.end());
|
||||||
|
EXPECT_TRUE(const_tree_.find(key) == tree_.end());
|
||||||
|
EXPECT_TRUE(tree_.equal_range(key).first ==
|
||||||
|
const_tree_.equal_range(key).second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup routines.
|
||||||
|
iterator lower_bound(const key_type &key) {
|
||||||
|
return iter_check(tree_.lower_bound(key), checker_.lower_bound(key));
|
||||||
|
}
|
||||||
|
const_iterator lower_bound(const key_type &key) const {
|
||||||
|
return iter_check(tree_.lower_bound(key), checker_.lower_bound(key));
|
||||||
|
}
|
||||||
|
iterator upper_bound(const key_type &key) {
|
||||||
|
return iter_check(tree_.upper_bound(key), checker_.upper_bound(key));
|
||||||
|
}
|
||||||
|
const_iterator upper_bound(const key_type &key) const {
|
||||||
|
return iter_check(tree_.upper_bound(key), checker_.upper_bound(key));
|
||||||
|
}
|
||||||
|
std::pair<iterator,iterator> equal_range(const key_type &key) {
|
||||||
|
std::pair<typename CheckerType::iterator,
|
||||||
|
typename CheckerType::iterator> checker_res =
|
||||||
|
checker_.equal_range(key);
|
||||||
|
std::pair<iterator, iterator> tree_res = tree_.equal_range(key);
|
||||||
|
iter_check(tree_res.first, checker_res.first);
|
||||||
|
iter_check(tree_res.second, checker_res.second);
|
||||||
|
return tree_res;
|
||||||
|
}
|
||||||
|
std::pair<const_iterator,const_iterator> equal_range(const key_type &key) const {
|
||||||
|
std::pair<typename CheckerType::const_iterator,
|
||||||
|
typename CheckerType::const_iterator> checker_res =
|
||||||
|
checker_.equal_range(key);
|
||||||
|
std::pair<const_iterator, const_iterator> tree_res = tree_.equal_range(key);
|
||||||
|
iter_check(tree_res.first, checker_res.first);
|
||||||
|
iter_check(tree_res.second, checker_res.second);
|
||||||
|
return tree_res;
|
||||||
|
}
|
||||||
|
iterator find(const key_type &key) {
|
||||||
|
return iter_check(tree_.find(key), checker_.find(key));
|
||||||
|
}
|
||||||
|
const_iterator find(const key_type &key) const {
|
||||||
|
return iter_check(tree_.find(key), checker_.find(key));
|
||||||
|
}
|
||||||
|
size_type count(const key_type &key) const {
|
||||||
|
size_type res = checker_.count(key);
|
||||||
|
EXPECT_EQ(res, tree_.count(key));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assignment operator.
|
||||||
|
self_type& operator=(const self_type &x) {
|
||||||
|
tree_ = x.tree_;
|
||||||
|
checker_ = x.checker_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletion routines.
|
||||||
|
int erase(const key_type &key) {
|
||||||
|
int size = tree_.size();
|
||||||
|
int res = checker_.erase(key);
|
||||||
|
EXPECT_EQ(res, tree_.count(key));
|
||||||
|
EXPECT_EQ(res, tree_.erase(key));
|
||||||
|
EXPECT_EQ(tree_.count(key), 0);
|
||||||
|
EXPECT_EQ(tree_.size(), size - res);
|
||||||
|
erase_check(key);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
iterator erase(iterator iter) {
|
||||||
|
key_type key = iter.key();
|
||||||
|
int size = tree_.size();
|
||||||
|
int count = tree_.count(key);
|
||||||
|
typename CheckerType::iterator checker_iter = checker_.find(key);
|
||||||
|
for (iterator tmp(tree_.find(key)); tmp != iter; ++tmp) {
|
||||||
|
++checker_iter;
|
||||||
|
}
|
||||||
|
typename CheckerType::iterator checker_next = checker_iter;
|
||||||
|
++checker_next;
|
||||||
|
checker_.erase(checker_iter);
|
||||||
|
iter = tree_.erase(iter);
|
||||||
|
EXPECT_EQ(tree_.size(), checker_.size());
|
||||||
|
EXPECT_EQ(tree_.size(), size - 1);
|
||||||
|
EXPECT_EQ(tree_.count(key), count - 1);
|
||||||
|
if (count == 1) {
|
||||||
|
erase_check(key);
|
||||||
|
}
|
||||||
|
return iter_check(iter, checker_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase(iterator begin, iterator end) {
|
||||||
|
int size = tree_.size();
|
||||||
|
int count = distance(begin, end);
|
||||||
|
typename CheckerType::iterator checker_begin = checker_.find(begin.key());
|
||||||
|
for (iterator tmp(tree_.find(begin.key())); tmp != begin; ++tmp) {
|
||||||
|
++checker_begin;
|
||||||
|
}
|
||||||
|
typename CheckerType::iterator checker_end =
|
||||||
|
end == tree_.end() ? checker_.end() : checker_.find(end.key());
|
||||||
|
if (end != tree_.end()) {
|
||||||
|
for (iterator tmp(tree_.find(end.key())); tmp != end; ++tmp) {
|
||||||
|
++checker_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checker_.erase(checker_begin, checker_end);
|
||||||
|
tree_.erase(begin, end);
|
||||||
|
EXPECT_EQ(tree_.size(), checker_.size());
|
||||||
|
EXPECT_EQ(tree_.size(), size - count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility routines.
|
||||||
|
void clear() {
|
||||||
|
tree_.clear();
|
||||||
|
checker_.clear();
|
||||||
|
}
|
||||||
|
void swap(self_type &x) {
|
||||||
|
tree_.swap(x.tree_);
|
||||||
|
checker_.swap(x.checker_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void verify() const {
|
||||||
|
tree_.verify();
|
||||||
|
EXPECT_EQ(tree_.size(), checker_.size());
|
||||||
|
|
||||||
|
// Move through the forward iterators using increment.
|
||||||
|
typename CheckerType::const_iterator
|
||||||
|
checker_iter(checker_.begin());
|
||||||
|
const_iterator tree_iter(tree_.begin());
|
||||||
|
for (; tree_iter != tree_.end();
|
||||||
|
++tree_iter, ++checker_iter) {
|
||||||
|
EXPECT_EQ(*tree_iter, *checker_iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move through the forward iterators using decrement.
|
||||||
|
for (int n = tree_.size() - 1; n >= 0; --n) {
|
||||||
|
iter_check(tree_iter, checker_iter);
|
||||||
|
--tree_iter;
|
||||||
|
--checker_iter;
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(tree_iter == tree_.begin());
|
||||||
|
EXPECT_TRUE(checker_iter == checker_.begin());
|
||||||
|
|
||||||
|
// Move through the reverse iterators using increment.
|
||||||
|
typename CheckerType::const_reverse_iterator
|
||||||
|
checker_riter(checker_.rbegin());
|
||||||
|
const_reverse_iterator tree_riter(tree_.rbegin());
|
||||||
|
for (; tree_riter != tree_.rend();
|
||||||
|
++tree_riter, ++checker_riter) {
|
||||||
|
EXPECT_EQ(*tree_riter, *checker_riter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move through the reverse iterators using decrement.
|
||||||
|
for (int n = tree_.size() - 1; n >= 0; --n) {
|
||||||
|
riter_check(tree_riter, checker_riter);
|
||||||
|
--tree_riter;
|
||||||
|
--checker_riter;
|
||||||
|
}
|
||||||
|
EXPECT_EQ(tree_riter, tree_.rbegin());
|
||||||
|
EXPECT_EQ(checker_riter, checker_.rbegin());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Access to the underlying btree.
|
||||||
|
const TreeType& tree() const { return tree_; }
|
||||||
|
|
||||||
|
// Size routines.
|
||||||
|
size_type size() const {
|
||||||
|
EXPECT_EQ(tree_.size(), checker_.size());
|
||||||
|
return tree_.size();
|
||||||
|
}
|
||||||
|
size_type max_size() const { return tree_.max_size(); }
|
||||||
|
bool empty() const {
|
||||||
|
EXPECT_EQ(tree_.empty(), checker_.empty());
|
||||||
|
return tree_.empty();
|
||||||
|
}
|
||||||
|
size_type height() const { return tree_.height(); }
|
||||||
|
size_type internal_nodes() const { return tree_.internal_nodes(); }
|
||||||
|
size_type leaf_nodes() const { return tree_.leaf_nodes(); }
|
||||||
|
size_type nodes() const { return tree_.nodes(); }
|
||||||
|
size_type bytes_used() const { return tree_.bytes_used(); }
|
||||||
|
double fullness() const { return tree_.fullness(); }
|
||||||
|
double overhead() const { return tree_.overhead(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TreeType tree_;
|
||||||
|
const TreeType &const_tree_;
|
||||||
|
CheckerType checker_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A checker for unique sorted associative containers. TreeType is expected to
|
||||||
|
// be btree_{set,map} and CheckerType is expected to be {set,map}.
|
||||||
|
template <typename TreeType, typename CheckerType>
|
||||||
|
class unique_checker : public base_checker<TreeType, CheckerType> {
|
||||||
|
typedef base_checker<TreeType, CheckerType> super_type;
|
||||||
|
typedef unique_checker<TreeType, CheckerType> self_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename super_type::iterator iterator;
|
||||||
|
typedef typename super_type::value_type value_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Default constructor.
|
||||||
|
unique_checker()
|
||||||
|
: super_type() {
|
||||||
|
}
|
||||||
|
// Copy constructor.
|
||||||
|
unique_checker(const self_type &x)
|
||||||
|
: super_type(x) {
|
||||||
|
}
|
||||||
|
// Range constructor.
|
||||||
|
template <class InputIterator>
|
||||||
|
unique_checker(InputIterator b, InputIterator e)
|
||||||
|
: super_type(b, e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insertion routines.
|
||||||
|
std::pair<iterator,bool> insert(const value_type &x) {
|
||||||
|
int size = this->tree_.size();
|
||||||
|
std::pair<typename CheckerType::iterator,bool> checker_res =
|
||||||
|
this->checker_.insert(x);
|
||||||
|
std::pair<iterator,bool> tree_res = this->tree_.insert(x);
|
||||||
|
EXPECT_EQ(*tree_res.first, *checker_res.first);
|
||||||
|
EXPECT_EQ(tree_res.second, checker_res.second);
|
||||||
|
EXPECT_EQ(this->tree_.size(), this->checker_.size());
|
||||||
|
EXPECT_EQ(this->tree_.size(), size + tree_res.second);
|
||||||
|
return tree_res;
|
||||||
|
}
|
||||||
|
iterator insert(iterator position, const value_type &x) {
|
||||||
|
int size = this->tree_.size();
|
||||||
|
std::pair<typename CheckerType::iterator,bool> checker_res =
|
||||||
|
this->checker_.insert(x);
|
||||||
|
iterator tree_res = this->tree_.insert(position, x);
|
||||||
|
EXPECT_EQ(*tree_res, *checker_res.first);
|
||||||
|
EXPECT_EQ(this->tree_.size(), this->checker_.size());
|
||||||
|
EXPECT_EQ(this->tree_.size(), size + checker_res.second);
|
||||||
|
return tree_res;
|
||||||
|
}
|
||||||
|
template <typename InputIterator>
|
||||||
|
void insert(InputIterator b, InputIterator e) {
|
||||||
|
for (; b != e; ++b) {
|
||||||
|
insert(*b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A checker for multiple sorted associative containers. TreeType is expected
|
||||||
|
// to be btree_{multiset,multimap} and CheckerType is expected to be
|
||||||
|
// {multiset,multimap}.
|
||||||
|
template <typename TreeType, typename CheckerType>
|
||||||
|
class multi_checker : public base_checker<TreeType, CheckerType> {
|
||||||
|
typedef base_checker<TreeType, CheckerType> super_type;
|
||||||
|
typedef multi_checker<TreeType, CheckerType> self_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename super_type::iterator iterator;
|
||||||
|
typedef typename super_type::value_type value_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Default constructor.
|
||||||
|
multi_checker()
|
||||||
|
: super_type() {
|
||||||
|
}
|
||||||
|
// Copy constructor.
|
||||||
|
multi_checker(const self_type &x)
|
||||||
|
: super_type(x) {
|
||||||
|
}
|
||||||
|
// Range constructor.
|
||||||
|
template <class InputIterator>
|
||||||
|
multi_checker(InputIterator b, InputIterator e)
|
||||||
|
: super_type(b, e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insertion routines.
|
||||||
|
iterator insert(const value_type &x) {
|
||||||
|
int size = this->tree_.size();
|
||||||
|
typename CheckerType::iterator checker_res = this->checker_.insert(x);
|
||||||
|
iterator tree_res = this->tree_.insert(x);
|
||||||
|
EXPECT_EQ(*tree_res, *checker_res);
|
||||||
|
EXPECT_EQ(this->tree_.size(), this->checker_.size());
|
||||||
|
EXPECT_EQ(this->tree_.size(), size + 1);
|
||||||
|
return tree_res;
|
||||||
|
}
|
||||||
|
iterator insert(iterator position, const value_type &x) {
|
||||||
|
int size = this->tree_.size();
|
||||||
|
typename CheckerType::iterator checker_res = this->checker_.insert(x);
|
||||||
|
iterator tree_res = this->tree_.insert(position, x);
|
||||||
|
EXPECT_EQ(*tree_res, *checker_res);
|
||||||
|
EXPECT_EQ(this->tree_.size(), this->checker_.size());
|
||||||
|
EXPECT_EQ(this->tree_.size(), size + 1);
|
||||||
|
return tree_res;
|
||||||
|
}
|
||||||
|
template <typename InputIterator>
|
||||||
|
void insert(InputIterator b, InputIterator e) {
|
||||||
|
for (; b != e; ++b) {
|
||||||
|
insert(*b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
char* GenerateDigits(char buf[16], int val, int maxval) {
|
||||||
|
EXPECT_LE(val, maxval);
|
||||||
|
int p = 15;
|
||||||
|
buf[p--] = 0;
|
||||||
|
while (maxval > 0) {
|
||||||
|
buf[p--] = '0' + (val % 10);
|
||||||
|
val /= 10;
|
||||||
|
maxval /= 10;
|
||||||
|
}
|
||||||
|
return buf + p + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename K>
|
||||||
|
struct Generator {
|
||||||
|
int maxval;
|
||||||
|
Generator(int m)
|
||||||
|
: maxval(m) {
|
||||||
|
}
|
||||||
|
K operator()(int i) const {
|
||||||
|
EXPECT_LE(i, maxval);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct Generator<std::string> {
|
||||||
|
int maxval;
|
||||||
|
Generator(int m)
|
||||||
|
: maxval(m) {
|
||||||
|
}
|
||||||
|
std::string operator()(int i) const {
|
||||||
|
char buf[16];
|
||||||
|
return GenerateDigits(buf, i, maxval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
struct Generator<std::pair<T, U> > {
|
||||||
|
Generator<typename std::remove_const<T>::type> tgen;
|
||||||
|
Generator<typename std::remove_const<U>::type> ugen;
|
||||||
|
|
||||||
|
Generator(int m)
|
||||||
|
: tgen(m),
|
||||||
|
ugen(m) {
|
||||||
|
}
|
||||||
|
std::pair<T, U> operator()(int i) const {
|
||||||
|
return std::make_pair(tgen(i), ugen(i));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate values for our tests and benchmarks. Value range is [0, maxval].
|
||||||
|
const std::vector<int>& GenerateNumbers(int n, int maxval) {
|
||||||
|
static std::vector<int> values;
|
||||||
|
static std::set<int> unique_values;
|
||||||
|
|
||||||
|
if (values.size() < n) {
|
||||||
|
|
||||||
|
for (int i = values.size(); i < n; i++) {
|
||||||
|
int value;
|
||||||
|
do {
|
||||||
|
value = rand() % (maxval + 1);
|
||||||
|
} while (unique_values.find(value) != unique_values.end());
|
||||||
|
|
||||||
|
values.push_back(value);
|
||||||
|
unique_values.insert(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates values in the range
|
||||||
|
// [0, 4 * min(FLAGS_benchmark_values, FLAGS_test_values)]
|
||||||
|
template <typename V>
|
||||||
|
std::vector<V> GenerateValues(int n) {
|
||||||
|
int two_times_max = 2 * std::max(FLAGS_benchmark_values, FLAGS_test_values);
|
||||||
|
int four_times_max = 2 * two_times_max;
|
||||||
|
EXPECT_LE(n, two_times_max);
|
||||||
|
const std::vector<int> &nums = GenerateNumbers(n, four_times_max);
|
||||||
|
Generator<V> gen(four_times_max);
|
||||||
|
std::vector<V> vec;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
vec.push_back(gen(nums[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename V>
|
||||||
|
void DoTest(const char *name, T *b, const std::vector<V> &values) {
|
||||||
|
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||||
|
|
||||||
|
T &mutable_b = *b;
|
||||||
|
const T &const_b = *b;
|
||||||
|
|
||||||
|
// Test insert.
|
||||||
|
for (int i = 0; i < values.size(); ++i) {
|
||||||
|
mutable_b.insert(values[i]);
|
||||||
|
mutable_b.value_check(values[i]);
|
||||||
|
}
|
||||||
|
assert(mutable_b.size() == values.size());
|
||||||
|
|
||||||
|
const_b.verify();
|
||||||
|
printf(" %s fullness=%0.2f overhead=%0.2f bytes-per-value=%0.2f\n",
|
||||||
|
name, const_b.fullness(), const_b.overhead(),
|
||||||
|
double(const_b.bytes_used()) / const_b.size());
|
||||||
|
|
||||||
|
// Test copy constructor.
|
||||||
|
T b_copy(const_b);
|
||||||
|
EXPECT_EQ(b_copy.size(), const_b.size());
|
||||||
|
EXPECT_LE(b_copy.height(), const_b.height());
|
||||||
|
EXPECT_LE(b_copy.internal_nodes(), const_b.internal_nodes());
|
||||||
|
EXPECT_LE(b_copy.leaf_nodes(), const_b.leaf_nodes());
|
||||||
|
for (int i = 0; i < values.size(); ++i) {
|
||||||
|
EXPECT_EQ(*b_copy.find(key_of_value(values[i])), values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test range constructor.
|
||||||
|
T b_range(const_b.begin(), const_b.end());
|
||||||
|
EXPECT_EQ(b_range.size(), const_b.size());
|
||||||
|
EXPECT_LE(b_range.height(), const_b.height());
|
||||||
|
EXPECT_LE(b_range.internal_nodes(), const_b.internal_nodes());
|
||||||
|
EXPECT_LE(b_range.leaf_nodes(), const_b.leaf_nodes());
|
||||||
|
for (int i = 0; i < values.size(); ++i) {
|
||||||
|
EXPECT_EQ(*b_range.find(key_of_value(values[i])), values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test range insertion for values that already exist.
|
||||||
|
b_range.insert(b_copy.begin(), b_copy.end());
|
||||||
|
b_range.verify();
|
||||||
|
|
||||||
|
// Test range insertion for new values.
|
||||||
|
b_range.clear();
|
||||||
|
b_range.insert(b_copy.begin(), b_copy.end());
|
||||||
|
EXPECT_EQ(b_range.size(), b_copy.size());
|
||||||
|
EXPECT_EQ(b_range.height(), b_copy.height());
|
||||||
|
EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
|
||||||
|
EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
|
||||||
|
for (int i = 0; i < values.size(); ++i) {
|
||||||
|
EXPECT_EQ(*b_range.find(key_of_value(values[i])), values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test assignment to self. Nothing should change.
|
||||||
|
b_range.operator=(b_range);
|
||||||
|
EXPECT_EQ(b_range.size(), b_copy.size());
|
||||||
|
EXPECT_EQ(b_range.height(), b_copy.height());
|
||||||
|
EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
|
||||||
|
EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
|
||||||
|
|
||||||
|
// Test assignment of new values.
|
||||||
|
b_range.clear();
|
||||||
|
b_range = b_copy;
|
||||||
|
EXPECT_EQ(b_range.size(), b_copy.size());
|
||||||
|
EXPECT_EQ(b_range.height(), b_copy.height());
|
||||||
|
EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
|
||||||
|
EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
|
||||||
|
|
||||||
|
// Test swap.
|
||||||
|
b_range.clear();
|
||||||
|
b_range.swap(b_copy);
|
||||||
|
EXPECT_EQ(b_copy.size(), 0);
|
||||||
|
EXPECT_EQ(b_range.size(), const_b.size());
|
||||||
|
for (int i = 0; i < values.size(); ++i) {
|
||||||
|
EXPECT_EQ(*b_range.find(key_of_value(values[i])), values[i]);
|
||||||
|
}
|
||||||
|
b_range.swap(b_copy);
|
||||||
|
|
||||||
|
// Test erase via values.
|
||||||
|
for (int i = 0; i < values.size(); ++i) {
|
||||||
|
mutable_b.erase(key_of_value(values[i]));
|
||||||
|
// Erasing a non-existent key should have no effect.
|
||||||
|
EXPECT_EQ(mutable_b.erase(key_of_value(values[i])), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_b.verify();
|
||||||
|
EXPECT_EQ(const_b.internal_nodes(), 0);
|
||||||
|
EXPECT_EQ(const_b.leaf_nodes(), 0);
|
||||||
|
EXPECT_EQ(const_b.size(), 0);
|
||||||
|
|
||||||
|
// Test erase via iterators.
|
||||||
|
mutable_b = b_copy;
|
||||||
|
for (int i = 0; i < values.size(); ++i) {
|
||||||
|
mutable_b.erase(mutable_b.find(key_of_value(values[i])));
|
||||||
|
}
|
||||||
|
|
||||||
|
const_b.verify();
|
||||||
|
EXPECT_EQ(const_b.internal_nodes(), 0);
|
||||||
|
EXPECT_EQ(const_b.leaf_nodes(), 0);
|
||||||
|
EXPECT_EQ(const_b.size(), 0);
|
||||||
|
|
||||||
|
// Test insert with hint.
|
||||||
|
for (int i = 0; i < values.size(); i++) {
|
||||||
|
mutable_b.insert(mutable_b.upper_bound(key_of_value(values[i])), values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_b.verify();
|
||||||
|
|
||||||
|
// Test dumping of the btree to an ostream. There should be 1 line for each
|
||||||
|
// value.
|
||||||
|
std::stringstream strm;
|
||||||
|
strm << mutable_b.tree();
|
||||||
|
EXPECT_EQ(mutable_b.size(), strcount(strm.str(), '\n'));
|
||||||
|
|
||||||
|
// Test range erase.
|
||||||
|
mutable_b.erase(mutable_b.begin(), mutable_b.end());
|
||||||
|
EXPECT_EQ(mutable_b.size(), 0);
|
||||||
|
const_b.verify();
|
||||||
|
|
||||||
|
// First half.
|
||||||
|
mutable_b = b_copy;
|
||||||
|
typename T::iterator mutable_iter_end = mutable_b.begin();
|
||||||
|
for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_end;
|
||||||
|
mutable_b.erase(mutable_b.begin(), mutable_iter_end);
|
||||||
|
EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 2);
|
||||||
|
const_b.verify();
|
||||||
|
|
||||||
|
// Second half.
|
||||||
|
mutable_b = b_copy;
|
||||||
|
typename T::iterator mutable_iter_begin = mutable_b.begin();
|
||||||
|
for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_begin;
|
||||||
|
mutable_b.erase(mutable_iter_begin, mutable_b.end());
|
||||||
|
EXPECT_EQ(mutable_b.size(), values.size() / 2);
|
||||||
|
const_b.verify();
|
||||||
|
|
||||||
|
// Second quarter.
|
||||||
|
mutable_b = b_copy;
|
||||||
|
mutable_iter_begin = mutable_b.begin();
|
||||||
|
for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_begin;
|
||||||
|
mutable_iter_end = mutable_iter_begin;
|
||||||
|
for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_end;
|
||||||
|
mutable_b.erase(mutable_iter_begin, mutable_iter_end);
|
||||||
|
EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 4);
|
||||||
|
const_b.verify();
|
||||||
|
|
||||||
|
mutable_b.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void ConstTest() {
|
||||||
|
typedef typename T::value_type value_type;
|
||||||
|
typename KeyOfValue<typename T::key_type, value_type>::type key_of_value;
|
||||||
|
|
||||||
|
T mutable_b;
|
||||||
|
const T &const_b = mutable_b;
|
||||||
|
|
||||||
|
// Insert a single value into the container and test looking it up.
|
||||||
|
value_type value = Generator<value_type>(2)(2);
|
||||||
|
mutable_b.insert(value);
|
||||||
|
EXPECT_TRUE(mutable_b.find(key_of_value(value)) != const_b.end());
|
||||||
|
EXPECT_TRUE(const_b.find(key_of_value(value)) != mutable_b.end());
|
||||||
|
EXPECT_EQ(*const_b.lower_bound(key_of_value(value)), value);
|
||||||
|
EXPECT_TRUE(const_b.upper_bound(key_of_value(value)) == const_b.end());
|
||||||
|
EXPECT_EQ(*const_b.equal_range(key_of_value(value)).first, value);
|
||||||
|
|
||||||
|
// We can only create a non-const iterator from a non-const container.
|
||||||
|
typename T::iterator mutable_iter(mutable_b.begin());
|
||||||
|
EXPECT_TRUE(mutable_iter == const_b.begin());
|
||||||
|
EXPECT_TRUE(mutable_iter != const_b.end());
|
||||||
|
EXPECT_TRUE(const_b.begin() == mutable_iter);
|
||||||
|
EXPECT_TRUE(const_b.end() != mutable_iter);
|
||||||
|
typename T::reverse_iterator mutable_riter(mutable_b.rbegin());
|
||||||
|
EXPECT_TRUE(mutable_riter == const_b.rbegin());
|
||||||
|
EXPECT_TRUE(mutable_riter != const_b.rend());
|
||||||
|
EXPECT_TRUE(const_b.rbegin() == mutable_riter);
|
||||||
|
EXPECT_TRUE(const_b.rend() != mutable_riter);
|
||||||
|
|
||||||
|
// We can create a const iterator from a non-const iterator.
|
||||||
|
typename T::const_iterator const_iter(mutable_iter);
|
||||||
|
EXPECT_TRUE(const_iter == mutable_b.begin());
|
||||||
|
EXPECT_TRUE(const_iter != mutable_b.end());
|
||||||
|
EXPECT_TRUE(mutable_b.begin() == const_iter);
|
||||||
|
EXPECT_TRUE(mutable_b.end() != const_iter);
|
||||||
|
typename T::const_reverse_iterator const_riter(mutable_riter);
|
||||||
|
EXPECT_EQ(const_riter, mutable_b.rbegin());
|
||||||
|
EXPECT_TRUE(const_riter != mutable_b.rend());
|
||||||
|
EXPECT_EQ(mutable_b.rbegin(), const_riter);
|
||||||
|
EXPECT_TRUE(mutable_b.rend() != const_riter);
|
||||||
|
|
||||||
|
// Make sure various methods can be invoked on a const container.
|
||||||
|
const_b.verify();
|
||||||
|
EXPECT_FALSE(const_b.empty());
|
||||||
|
EXPECT_EQ(const_b.size(), 1);
|
||||||
|
EXPECT_GT(const_b.max_size(), 0);
|
||||||
|
EXPECT_EQ(const_b.height(), 1);
|
||||||
|
EXPECT_EQ(const_b.count(key_of_value(value)), 1);
|
||||||
|
EXPECT_EQ(const_b.internal_nodes(), 0);
|
||||||
|
EXPECT_EQ(const_b.leaf_nodes(), 1);
|
||||||
|
EXPECT_EQ(const_b.nodes(), 1);
|
||||||
|
EXPECT_GT(const_b.bytes_used(), 0);
|
||||||
|
EXPECT_GT(const_b.fullness(), 0);
|
||||||
|
EXPECT_GT(const_b.overhead(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename C>
|
||||||
|
void BtreeTest() {
|
||||||
|
ConstTest<T>();
|
||||||
|
|
||||||
|
typedef typename std::remove_const<typename T::value_type>::type V;
|
||||||
|
std::vector<V> random_values = GenerateValues<V>(FLAGS_test_values);
|
||||||
|
|
||||||
|
unique_checker<T, C> container;
|
||||||
|
|
||||||
|
// Test key insertion/deletion in sorted order.
|
||||||
|
std::vector<V> sorted_values(random_values);
|
||||||
|
sort(sorted_values.begin(), sorted_values.end());
|
||||||
|
DoTest("sorted: ", &container, sorted_values);
|
||||||
|
|
||||||
|
// Test key insertion/deletion in reverse sorted order.
|
||||||
|
reverse(sorted_values.begin(), sorted_values.end());
|
||||||
|
DoTest("rsorted: ", &container, sorted_values);
|
||||||
|
|
||||||
|
// Test key insertion/deletion in random order.
|
||||||
|
DoTest("random: ", &container, random_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename C>
|
||||||
|
void BtreeMultiTest() {
|
||||||
|
ConstTest<T>();
|
||||||
|
|
||||||
|
typedef typename std::remove_const<typename T::value_type>::type V;
|
||||||
|
const std::vector<V>& random_values = GenerateValues<V>(FLAGS_test_values);
|
||||||
|
|
||||||
|
multi_checker<T, C> container;
|
||||||
|
|
||||||
|
// Test keys in sorted order.
|
||||||
|
std::vector<V> sorted_values(random_values);
|
||||||
|
sort(sorted_values.begin(), sorted_values.end());
|
||||||
|
DoTest("sorted: ", &container, sorted_values);
|
||||||
|
|
||||||
|
// Test keys in reverse sorted order.
|
||||||
|
reverse(sorted_values.begin(), sorted_values.end());
|
||||||
|
DoTest("rsorted: ", &container, sorted_values);
|
||||||
|
|
||||||
|
// Test keys in random order.
|
||||||
|
DoTest("random: ", &container, random_values);
|
||||||
|
|
||||||
|
// Test keys in random order w/ duplicates.
|
||||||
|
std::vector<V> duplicate_values(random_values);
|
||||||
|
duplicate_values.insert(
|
||||||
|
duplicate_values.end(), random_values.begin(), random_values.end());
|
||||||
|
DoTest("duplicates:", &container, duplicate_values);
|
||||||
|
|
||||||
|
// Test all identical keys.
|
||||||
|
std::vector<V> identical_values(100);
|
||||||
|
fill(identical_values.begin(), identical_values.end(), Generator<V>(2)(2));
|
||||||
|
DoTest("identical: ", &container, identical_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Alloc = std::allocator<T> >
|
||||||
|
class TestAllocator : public Alloc {
|
||||||
|
public:
|
||||||
|
typedef typename Alloc::pointer pointer;
|
||||||
|
typedef typename Alloc::size_type size_type;
|
||||||
|
|
||||||
|
TestAllocator() : bytes_used_(NULL) { }
|
||||||
|
TestAllocator(int64_t *bytes_used) : bytes_used_(bytes_used) { }
|
||||||
|
|
||||||
|
// Constructor used for rebinding
|
||||||
|
template <class U>
|
||||||
|
TestAllocator(const TestAllocator<U>& x)
|
||||||
|
: Alloc(x),
|
||||||
|
bytes_used_(x.bytes_used()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer allocate(size_type n, std::allocator<void>::const_pointer hint = 0) {
|
||||||
|
EXPECT_TRUE(bytes_used_ != NULL);
|
||||||
|
*bytes_used_ += n * sizeof(T);
|
||||||
|
return Alloc::allocate(n, hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(pointer p, size_type n) {
|
||||||
|
Alloc::deallocate(p, n);
|
||||||
|
EXPECT_TRUE(bytes_used_ != NULL);
|
||||||
|
*bytes_used_ -= n * sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebind allows an allocator<T> to be used for a different type
|
||||||
|
template <class U> struct rebind {
|
||||||
|
typedef TestAllocator<U, typename Alloc::template rebind<U>::other> other;
|
||||||
|
};
|
||||||
|
|
||||||
|
int64_t* bytes_used() const { return bytes_used_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int64_t *bytes_used_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void BtreeAllocatorTest() {
|
||||||
|
typedef typename T::value_type value_type;
|
||||||
|
|
||||||
|
int64_t alloc1 = 0;
|
||||||
|
int64_t alloc2 = 0;
|
||||||
|
T b1(typename T::key_compare(), &alloc1);
|
||||||
|
T b2(typename T::key_compare(), &alloc2);
|
||||||
|
|
||||||
|
// This should swap the allocators!
|
||||||
|
swap(b1, b2);
|
||||||
|
|
||||||
|
for (int i = 0; i < 1000; i++) {
|
||||||
|
b1.insert(Generator<value_type>(1000)(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should have allocated out of alloc2!
|
||||||
|
EXPECT_LE(b1.bytes_used(), alloc2 + sizeof(b1));
|
||||||
|
EXPECT_GT(alloc2, alloc1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void BtreeMapTest() {
|
||||||
|
typedef typename T::value_type value_type;
|
||||||
|
typedef typename T::mapped_type mapped_type;
|
||||||
|
|
||||||
|
mapped_type m = Generator<mapped_type>(0)(0);
|
||||||
|
(void) m;
|
||||||
|
|
||||||
|
T b;
|
||||||
|
|
||||||
|
// Verify we can insert using operator[].
|
||||||
|
for (int i = 0; i < 1000; i++) {
|
||||||
|
value_type v = Generator<value_type>(1000)(i);
|
||||||
|
b[v.first] = v.second;
|
||||||
|
}
|
||||||
|
EXPECT_EQ(b.size(), 1000);
|
||||||
|
|
||||||
|
// Test whether we can use the "->" operator on iterators and
|
||||||
|
// reverse_iterators. This stresses the btree_map_params::pair_pointer
|
||||||
|
// mechanism.
|
||||||
|
EXPECT_EQ(b.begin()->first, Generator<value_type>(1000)(0).first);
|
||||||
|
EXPECT_EQ(b.begin()->second, Generator<value_type>(1000)(0).second);
|
||||||
|
EXPECT_EQ(b.rbegin()->first, Generator<value_type>(1000)(999).first);
|
||||||
|
EXPECT_EQ(b.rbegin()->second, Generator<value_type>(1000)(999).second);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void BtreeMultiMapTest() {
|
||||||
|
typedef typename T::mapped_type mapped_type;
|
||||||
|
mapped_type m = Generator<mapped_type>(0)(0);
|
||||||
|
(void) m;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace btree
|
||||||
|
|
||||||
|
#endif // UTIL_BTREE_BTREE_TEST_H__
|
20
lib/xdelta3/cpp-btree/btree_test_flags.cc
Normal file
20
lib/xdelta3/cpp-btree/btree_test_flags.cc
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gflags/gflags.h"
|
||||||
|
|
||||||
|
DEFINE_int32(test_values, 10000,
|
||||||
|
"The number of values to use for tests.");
|
||||||
|
DEFINE_int32(benchmark_values, 1000000,
|
||||||
|
"The number of values to use for benchmarks.");
|
395
lib/xdelta3/cpp-btree/safe_btree.h
Normal file
395
lib/xdelta3/cpp-btree/safe_btree.h
Normal file
|
@ -0,0 +1,395 @@
|
||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// A safe_btree<> wraps around a btree<> and removes the caveat that insertion
|
||||||
|
// and deletion invalidate iterators. A safe_btree<> maintains a generation
|
||||||
|
// number that is incremented on every mutation. A safe_btree<>::iterator keeps
|
||||||
|
// a pointer to the safe_btree<> it came from, the generation of the tree when
|
||||||
|
// it was last validated and the key the underlying btree<>::iterator points
|
||||||
|
// to. If an iterator is accessed and its generation differs from the tree
|
||||||
|
// generation it is revalidated.
|
||||||
|
//
|
||||||
|
// References and pointers returned by safe_btree iterators are not safe.
|
||||||
|
//
|
||||||
|
// See the incorrect usage examples mentioned in safe_btree_set.h and
|
||||||
|
// safe_btree_map.h.
|
||||||
|
|
||||||
|
#ifndef UTIL_BTREE_SAFE_BTREE_H__
|
||||||
|
#define UTIL_BTREE_SAFE_BTREE_H__
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "btree.h"
|
||||||
|
|
||||||
|
namespace btree {
|
||||||
|
|
||||||
|
template <typename Tree, typename Iterator>
|
||||||
|
class safe_btree_iterator {
|
||||||
|
public:
|
||||||
|
typedef typename Iterator::key_type key_type;
|
||||||
|
typedef typename Iterator::value_type value_type;
|
||||||
|
typedef typename Iterator::size_type size_type;
|
||||||
|
typedef typename Iterator::difference_type difference_type;
|
||||||
|
typedef typename Iterator::pointer pointer;
|
||||||
|
typedef typename Iterator::reference reference;
|
||||||
|
typedef typename Iterator::const_pointer const_pointer;
|
||||||
|
typedef typename Iterator::const_reference const_reference;
|
||||||
|
typedef typename Iterator::iterator_category iterator_category;
|
||||||
|
typedef typename Tree::iterator iterator;
|
||||||
|
typedef typename Tree::const_iterator const_iterator;
|
||||||
|
typedef safe_btree_iterator<Tree, Iterator> self_type;
|
||||||
|
|
||||||
|
void update() const {
|
||||||
|
if (iter_ != tree_->internal_btree()->end()) {
|
||||||
|
// A positive generation indicates a valid key.
|
||||||
|
generation_ = tree_->generation();
|
||||||
|
key_ = iter_.key();
|
||||||
|
} else {
|
||||||
|
// Use a negative generation to indicate iter_ points to end().
|
||||||
|
generation_ = -tree_->generation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
safe_btree_iterator()
|
||||||
|
: generation_(0),
|
||||||
|
key_(),
|
||||||
|
iter_(),
|
||||||
|
tree_(NULL) {
|
||||||
|
}
|
||||||
|
safe_btree_iterator(const iterator &x)
|
||||||
|
: generation_(x.generation()),
|
||||||
|
key_(x.key()),
|
||||||
|
iter_(x.iter()),
|
||||||
|
tree_(x.tree()) {
|
||||||
|
}
|
||||||
|
safe_btree_iterator(Tree *tree, const Iterator &iter)
|
||||||
|
: generation_(),
|
||||||
|
key_(),
|
||||||
|
iter_(iter),
|
||||||
|
tree_(tree) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Tree* tree() const { return tree_; }
|
||||||
|
int64_t generation() const { return generation_; }
|
||||||
|
|
||||||
|
Iterator* mutable_iter() const {
|
||||||
|
if (generation_ != tree_->generation()) {
|
||||||
|
if (generation_ > 0) {
|
||||||
|
// This does the wrong thing for a multi{set,map}. If my iter was
|
||||||
|
// pointing to the 2nd of 2 values with the same key, then this will
|
||||||
|
// reset it to point to the first. This is why we don't provide a
|
||||||
|
// safe_btree_multi{set,map}.
|
||||||
|
iter_ = tree_->internal_btree()->lower_bound(key_);
|
||||||
|
update();
|
||||||
|
} else if (-generation_ != tree_->generation()) {
|
||||||
|
iter_ = tree_->internal_btree()->end();
|
||||||
|
generation_ = -tree_->generation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &iter_;
|
||||||
|
}
|
||||||
|
const Iterator& iter() const {
|
||||||
|
return *mutable_iter();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equality/inequality operators.
|
||||||
|
bool operator==(const const_iterator &x) const {
|
||||||
|
return iter() == x.iter();
|
||||||
|
}
|
||||||
|
bool operator!=(const const_iterator &x) const {
|
||||||
|
return iter() != x.iter();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accessors for the key/value the iterator is pointing at.
|
||||||
|
const key_type& key() const {
|
||||||
|
return key_;
|
||||||
|
}
|
||||||
|
// This reference value is potentially invalidated by any non-const
|
||||||
|
// method on the tree; it is NOT safe.
|
||||||
|
reference operator*() const {
|
||||||
|
assert(generation_ > 0);
|
||||||
|
return iter().operator*();
|
||||||
|
}
|
||||||
|
// This pointer value is potentially invalidated by any non-const
|
||||||
|
// method on the tree; it is NOT safe.
|
||||||
|
pointer operator->() const {
|
||||||
|
assert(generation_ > 0);
|
||||||
|
return iter().operator->();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment/decrement operators.
|
||||||
|
self_type& operator++() {
|
||||||
|
++(*mutable_iter());
|
||||||
|
update();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
self_type& operator--() {
|
||||||
|
--(*mutable_iter());
|
||||||
|
update();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
self_type operator++(int) {
|
||||||
|
self_type tmp = *this;
|
||||||
|
++*this;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
self_type operator--(int) {
|
||||||
|
self_type tmp = *this;
|
||||||
|
--*this;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The generation of the tree when "iter" was updated.
|
||||||
|
mutable int64_t generation_;
|
||||||
|
// The key the iterator points to.
|
||||||
|
mutable key_type key_;
|
||||||
|
// The underlying iterator.
|
||||||
|
mutable Iterator iter_;
|
||||||
|
// The tree the iterator is associated with.
|
||||||
|
Tree *tree_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Params>
|
||||||
|
class safe_btree {
|
||||||
|
typedef safe_btree<Params> self_type;
|
||||||
|
|
||||||
|
typedef btree<Params> btree_type;
|
||||||
|
typedef typename btree_type::iterator tree_iterator;
|
||||||
|
typedef typename btree_type::const_iterator tree_const_iterator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename btree_type::params_type params_type;
|
||||||
|
typedef typename btree_type::key_type key_type;
|
||||||
|
typedef typename btree_type::data_type data_type;
|
||||||
|
typedef typename btree_type::mapped_type mapped_type;
|
||||||
|
typedef typename btree_type::value_type value_type;
|
||||||
|
typedef typename btree_type::key_compare key_compare;
|
||||||
|
typedef typename btree_type::allocator_type allocator_type;
|
||||||
|
typedef typename btree_type::pointer pointer;
|
||||||
|
typedef typename btree_type::const_pointer const_pointer;
|
||||||
|
typedef typename btree_type::reference reference;
|
||||||
|
typedef typename btree_type::const_reference const_reference;
|
||||||
|
typedef typename btree_type::size_type size_type;
|
||||||
|
typedef typename btree_type::difference_type difference_type;
|
||||||
|
typedef safe_btree_iterator<self_type, tree_iterator> iterator;
|
||||||
|
typedef safe_btree_iterator<
|
||||||
|
const self_type, tree_const_iterator> const_iterator;
|
||||||
|
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||||
|
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Default constructor.
|
||||||
|
safe_btree(const key_compare &comp, const allocator_type &alloc)
|
||||||
|
: tree_(comp, alloc),
|
||||||
|
generation_(1) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
safe_btree(const self_type &x)
|
||||||
|
: tree_(x.tree_),
|
||||||
|
generation_(1) {
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin() {
|
||||||
|
return iterator(this, tree_.begin());
|
||||||
|
}
|
||||||
|
const_iterator begin() const {
|
||||||
|
return const_iterator(this, tree_.begin());
|
||||||
|
}
|
||||||
|
iterator end() {
|
||||||
|
return iterator(this, tree_.end());
|
||||||
|
}
|
||||||
|
const_iterator end() const {
|
||||||
|
return const_iterator(this, tree_.end());
|
||||||
|
}
|
||||||
|
reverse_iterator rbegin() {
|
||||||
|
return reverse_iterator(end());
|
||||||
|
}
|
||||||
|
const_reverse_iterator rbegin() const {
|
||||||
|
return const_reverse_iterator(end());
|
||||||
|
}
|
||||||
|
reverse_iterator rend() {
|
||||||
|
return reverse_iterator(begin());
|
||||||
|
}
|
||||||
|
const_reverse_iterator rend() const {
|
||||||
|
return const_reverse_iterator(begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup routines.
|
||||||
|
iterator lower_bound(const key_type &key) {
|
||||||
|
return iterator(this, tree_.lower_bound(key));
|
||||||
|
}
|
||||||
|
const_iterator lower_bound(const key_type &key) const {
|
||||||
|
return const_iterator(this, tree_.lower_bound(key));
|
||||||
|
}
|
||||||
|
iterator upper_bound(const key_type &key) {
|
||||||
|
return iterator(this, tree_.upper_bound(key));
|
||||||
|
}
|
||||||
|
const_iterator upper_bound(const key_type &key) const {
|
||||||
|
return const_iterator(this, tree_.upper_bound(key));
|
||||||
|
}
|
||||||
|
std::pair<iterator, iterator> equal_range(const key_type &key) {
|
||||||
|
std::pair<tree_iterator, tree_iterator> p = tree_.equal_range(key);
|
||||||
|
return std::make_pair(iterator(this, p.first),
|
||||||
|
iterator(this, p.second));
|
||||||
|
}
|
||||||
|
std::pair<const_iterator, const_iterator> equal_range(const key_type &key) const {
|
||||||
|
std::pair<tree_const_iterator, tree_const_iterator> p = tree_.equal_range(key);
|
||||||
|
return std::make_pair(const_iterator(this, p.first),
|
||||||
|
const_iterator(this, p.second));
|
||||||
|
}
|
||||||
|
iterator find_unique(const key_type &key) {
|
||||||
|
return iterator(this, tree_.find_unique(key));
|
||||||
|
}
|
||||||
|
const_iterator find_unique(const key_type &key) const {
|
||||||
|
return const_iterator(this, tree_.find_unique(key));
|
||||||
|
}
|
||||||
|
iterator find_multi(const key_type &key) {
|
||||||
|
return iterator(this, tree_.find_multi(key));
|
||||||
|
}
|
||||||
|
const_iterator find_multi(const key_type &key) const {
|
||||||
|
return const_iterator(this, tree_.find_multi(key));
|
||||||
|
}
|
||||||
|
size_type count_unique(const key_type &key) const {
|
||||||
|
return tree_.count_unique(key);
|
||||||
|
}
|
||||||
|
size_type count_multi(const key_type &key) const {
|
||||||
|
return tree_.count_multi(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insertion routines.
|
||||||
|
template <typename ValuePointer>
|
||||||
|
std::pair<iterator, bool> insert_unique(const key_type &key, ValuePointer value) {
|
||||||
|
std::pair<tree_iterator, bool> p = tree_.insert_unique(key, value);
|
||||||
|
generation_ += p.second;
|
||||||
|
return std::make_pair(iterator(this, p.first), p.second);
|
||||||
|
}
|
||||||
|
std::pair<iterator, bool> insert_unique(const value_type &v) {
|
||||||
|
std::pair<tree_iterator, bool> p = tree_.insert_unique(v);
|
||||||
|
generation_ += p.second;
|
||||||
|
return std::make_pair(iterator(this, p.first), p.second);
|
||||||
|
}
|
||||||
|
iterator insert_unique(iterator position, const value_type &v) {
|
||||||
|
tree_iterator tree_pos = position.iter();
|
||||||
|
++generation_;
|
||||||
|
return iterator(this, tree_.insert_unique(tree_pos, v));
|
||||||
|
}
|
||||||
|
template <typename InputIterator>
|
||||||
|
void insert_unique(InputIterator b, InputIterator e) {
|
||||||
|
for (; b != e; ++b) {
|
||||||
|
insert_unique(*b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iterator insert_multi(const value_type &v) {
|
||||||
|
++generation_;
|
||||||
|
return iterator(this, tree_.insert_multi(v));
|
||||||
|
}
|
||||||
|
iterator insert_multi(iterator position, const value_type &v) {
|
||||||
|
tree_iterator tree_pos = position.iter();
|
||||||
|
++generation_;
|
||||||
|
return iterator(this, tree_.insert_multi(tree_pos, v));
|
||||||
|
}
|
||||||
|
template <typename InputIterator>
|
||||||
|
void insert_multi(InputIterator b, InputIterator e) {
|
||||||
|
for (; b != e; ++b) {
|
||||||
|
insert_multi(*b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self_type& operator=(const self_type &x) {
|
||||||
|
if (&x == this) {
|
||||||
|
// Don't copy onto ourselves.
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
++generation_;
|
||||||
|
tree_ = x.tree_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletion routines.
|
||||||
|
void erase(const iterator &begin, const iterator &end) {
|
||||||
|
tree_.erase(begin.iter(), end.iter());
|
||||||
|
++generation_;
|
||||||
|
}
|
||||||
|
// Erase the specified iterator from the btree. The iterator must be valid
|
||||||
|
// (i.e. not equal to end()). Return an iterator pointing to the node after
|
||||||
|
// the one that was erased (or end() if none exists).
|
||||||
|
iterator erase(iterator iter) {
|
||||||
|
tree_iterator res = tree_.erase(iter.iter());
|
||||||
|
++generation_;
|
||||||
|
return iterator(this, res);
|
||||||
|
}
|
||||||
|
int erase_unique(const key_type &key) {
|
||||||
|
int res = tree_.erase_unique(key);
|
||||||
|
generation_ += res;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
int erase_multi(const key_type &key) {
|
||||||
|
int res = tree_.erase_multi(key);
|
||||||
|
generation_ += res;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Access to the underlying btree.
|
||||||
|
btree_type* internal_btree() { return &tree_; }
|
||||||
|
const btree_type* internal_btree() const { return &tree_; }
|
||||||
|
|
||||||
|
// Utility routines.
|
||||||
|
void clear() {
|
||||||
|
++generation_;
|
||||||
|
tree_.clear();
|
||||||
|
}
|
||||||
|
void swap(self_type &x) {
|
||||||
|
++generation_;
|
||||||
|
++x.generation_;
|
||||||
|
tree_.swap(x.tree_);
|
||||||
|
}
|
||||||
|
void dump(std::ostream &os) const {
|
||||||
|
tree_.dump(os);
|
||||||
|
}
|
||||||
|
void verify() const {
|
||||||
|
tree_.verify();
|
||||||
|
}
|
||||||
|
int64_t generation() const {
|
||||||
|
return generation_;
|
||||||
|
}
|
||||||
|
key_compare key_comp() const { return tree_.key_comp(); }
|
||||||
|
|
||||||
|
// Size routines.
|
||||||
|
size_type size() const { return tree_.size(); }
|
||||||
|
size_type max_size() const { return tree_.max_size(); }
|
||||||
|
bool empty() const { return tree_.empty(); }
|
||||||
|
size_type height() const { return tree_.height(); }
|
||||||
|
size_type internal_nodes() const { return tree_.internal_nodes(); }
|
||||||
|
size_type leaf_nodes() const { return tree_.leaf_nodes(); }
|
||||||
|
size_type nodes() const { return tree_.nodes(); }
|
||||||
|
size_type bytes_used() const { return tree_.bytes_used(); }
|
||||||
|
static double average_bytes_per_value() {
|
||||||
|
return btree_type::average_bytes_per_value();
|
||||||
|
}
|
||||||
|
double fullness() const { return tree_.fullness(); }
|
||||||
|
double overhead() const { return tree_.overhead(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
btree_type tree_;
|
||||||
|
int64_t generation_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace btree
|
||||||
|
|
||||||
|
#endif // UTIL_BTREE_SAFE_BTREE_H__
|
89
lib/xdelta3/cpp-btree/safe_btree_map.h
Normal file
89
lib/xdelta3/cpp-btree/safe_btree_map.h
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// The safe_btree_map<> is like btree_map<> except that it removes the caveat
|
||||||
|
// about insertion and deletion invalidating existing iterators at a small cost
|
||||||
|
// in making iterators larger and slower.
|
||||||
|
//
|
||||||
|
// Revalidation occurs whenever an iterator is accessed. References
|
||||||
|
// and pointers returned by safe_btree_map<> iterators are not stable,
|
||||||
|
// they are potentially invalidated by any non-const method on the map.
|
||||||
|
//
|
||||||
|
// BEGIN INCORRECT EXAMPLE
|
||||||
|
// for (auto i = safe_map->begin(); i != safe_map->end(); ++i) {
|
||||||
|
// const T *value = &i->second; // DO NOT DO THIS
|
||||||
|
// [code that modifies safe_map and uses value];
|
||||||
|
// }
|
||||||
|
// END INCORRECT EXAMPLE
|
||||||
|
#ifndef UTIL_BTREE_SAFE_BTREE_MAP_H__
|
||||||
|
#define UTIL_BTREE_SAFE_BTREE_MAP_H__
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "btree_container.h"
|
||||||
|
#include "btree_map.h"
|
||||||
|
#include "safe_btree.h"
|
||||||
|
|
||||||
|
namespace btree {
|
||||||
|
|
||||||
|
// The safe_btree_map class is needed mainly for its constructors.
|
||||||
|
template <typename Key, typename Value,
|
||||||
|
typename Compare = std::less<Key>,
|
||||||
|
typename Alloc = std::allocator<std::pair<const Key, Value> >,
|
||||||
|
int TargetNodeSize = 256>
|
||||||
|
class safe_btree_map : public btree_map_container<
|
||||||
|
safe_btree<btree_map_params<Key, Value, Compare, Alloc, TargetNodeSize> > > {
|
||||||
|
|
||||||
|
typedef safe_btree_map<Key, Value, Compare, Alloc, TargetNodeSize> self_type;
|
||||||
|
typedef btree_map_params<
|
||||||
|
Key, Value, Compare, Alloc, TargetNodeSize> params_type;
|
||||||
|
typedef safe_btree<params_type> btree_type;
|
||||||
|
typedef btree_map_container<btree_type> super_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename btree_type::key_compare key_compare;
|
||||||
|
typedef typename btree_type::allocator_type allocator_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Default constructor.
|
||||||
|
safe_btree_map(const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(comp, alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
safe_btree_map(const self_type &x)
|
||||||
|
: super_type(x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range constructor.
|
||||||
|
template <class InputIterator>
|
||||||
|
safe_btree_map(InputIterator b, InputIterator e,
|
||||||
|
const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(b, e, comp, alloc) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K, typename V, typename C, typename A, int N>
|
||||||
|
inline void swap(safe_btree_map<K, V, C, A, N> &x,
|
||||||
|
safe_btree_map<K, V, C, A, N> &y) {
|
||||||
|
x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace btree
|
||||||
|
|
||||||
|
#endif // UTIL_BTREE_SAFE_BTREE_MAP_H__
|
88
lib/xdelta3/cpp-btree/safe_btree_set.h
Normal file
88
lib/xdelta3/cpp-btree/safe_btree_set.h
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// The safe_btree_set<> is like btree_set<> except that it removes the caveat
|
||||||
|
// about insertion and deletion invalidating existing iterators at a small cost
|
||||||
|
// in making iterators larger and slower.
|
||||||
|
//
|
||||||
|
// Revalidation occurs whenever an iterator is accessed. References
|
||||||
|
// and pointers returned by safe_btree_map<> iterators are not stable,
|
||||||
|
// they are potentially invalidated by any non-const method on the set.
|
||||||
|
//
|
||||||
|
// BEGIN INCORRECT EXAMPLE
|
||||||
|
// for (auto i = safe_set->begin(); i != safe_set->end(); ++i) {
|
||||||
|
// const T &value = *i; // DO NOT DO THIS
|
||||||
|
// [code that modifies safe_set and uses value];
|
||||||
|
// }
|
||||||
|
// END INCORRECT EXAMPLE
|
||||||
|
|
||||||
|
#ifndef UTIL_BTREE_SAFE_BTREE_SET_H__
|
||||||
|
#define UTIL_BTREE_SAFE_BTREE_SET_H__
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "btree_container.h"
|
||||||
|
#include "btree_set.h"
|
||||||
|
#include "safe_btree.h"
|
||||||
|
|
||||||
|
namespace btree {
|
||||||
|
|
||||||
|
// The safe_btree_set class is needed mainly for its constructors.
|
||||||
|
template <typename Key,
|
||||||
|
typename Compare = std::less<Key>,
|
||||||
|
typename Alloc = std::allocator<Key>,
|
||||||
|
int TargetNodeSize = 256>
|
||||||
|
class safe_btree_set : public btree_unique_container<
|
||||||
|
safe_btree<btree_set_params<Key, Compare, Alloc, TargetNodeSize> > > {
|
||||||
|
|
||||||
|
typedef safe_btree_set<Key, Compare, Alloc, TargetNodeSize> self_type;
|
||||||
|
typedef btree_set_params<Key, Compare, Alloc, TargetNodeSize> params_type;
|
||||||
|
typedef safe_btree<params_type> btree_type;
|
||||||
|
typedef btree_unique_container<btree_type> super_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename btree_type::key_compare key_compare;
|
||||||
|
typedef typename btree_type::allocator_type allocator_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Default constructor.
|
||||||
|
safe_btree_set(const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(comp, alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
safe_btree_set(const self_type &x)
|
||||||
|
: super_type(x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range constructor.
|
||||||
|
template <class InputIterator>
|
||||||
|
safe_btree_set(InputIterator b, InputIterator e,
|
||||||
|
const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(b, e, comp, alloc) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K, typename C, typename A, int N>
|
||||||
|
inline void swap(safe_btree_set<K, C, A, N> &x,
|
||||||
|
safe_btree_set<K, C, A, N> &y) {
|
||||||
|
x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace btree
|
||||||
|
|
||||||
|
#endif // UTIL_BTREE_SAFE_BTREE_SET_H__
|
116
lib/xdelta3/cpp-btree/safe_btree_test.cc
Normal file
116
lib/xdelta3/cpp-btree/safe_btree_test.cc
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// TODO(pmattis): Add some tests that iterators are not invalidated by
|
||||||
|
// insertion and deletion.
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "btree_test.h"
|
||||||
|
#include "safe_btree_map.h"
|
||||||
|
#include "safe_btree_set.h"
|
||||||
|
|
||||||
|
class UnsafeArena;
|
||||||
|
|
||||||
|
namespace btree {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <typename K, int N>
|
||||||
|
void SetTest() {
|
||||||
|
typedef TestAllocator<K> TestAlloc;
|
||||||
|
BtreeTest<safe_btree_set<K, std::less<K>, std::allocator<K>, N>, std::set<K> >();
|
||||||
|
BtreeAllocatorTest<safe_btree_set<K, std::less<K>, TestAlloc, N> >();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename K, int N>
|
||||||
|
void MapTest() {
|
||||||
|
typedef TestAllocator<K> TestAlloc;
|
||||||
|
BtreeTest<safe_btree_map<K, K, std::less<K>, std::allocator<K>, N>, std::map<K, K> >();
|
||||||
|
BtreeAllocatorTest<safe_btree_map<K, K, std::less<K>, TestAlloc, N> >();
|
||||||
|
BtreeMapTest<safe_btree_map<K, K, std::less<K>, std::allocator<K>, N> >();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SafeBtree, set_int32_32) { SetTest<int32_t, 32>(); }
|
||||||
|
TEST(SafeBtree, set_int32_64) { SetTest<int32_t, 64>(); }
|
||||||
|
TEST(SafeBtree, set_int32_128) { SetTest<int32_t, 128>(); }
|
||||||
|
TEST(SafeBtree, set_int32_256) { SetTest<int32_t, 256>(); }
|
||||||
|
TEST(SafeBtree, set_int64_256) { SetTest<int64_t, 256>(); }
|
||||||
|
TEST(SafeBtree, set_string_256) { SetTest<std::string, 256>(); }
|
||||||
|
TEST(SafeBtree, set_pair_256) { SetTest<std::pair<int, int>, 256>(); }
|
||||||
|
TEST(SafeBtree, map_int32_256) { MapTest<int32_t, 256>(); }
|
||||||
|
TEST(SafeBtree, map_int64_256) { MapTest<int64_t, 256>(); }
|
||||||
|
TEST(SafeBtree, map_string_256) { MapTest<std::string, 256>(); }
|
||||||
|
TEST(SafeBtree, map_pair_256) { MapTest<std::pair<int, int>, 256>(); }
|
||||||
|
|
||||||
|
TEST(SafeBtree, Comparison) {
|
||||||
|
const int kSetSize = 1201;
|
||||||
|
safe_btree_set<int64_t> my_set;
|
||||||
|
for (int i = 0; i < kSetSize; ++i) {
|
||||||
|
my_set.insert(i);
|
||||||
|
}
|
||||||
|
safe_btree_set<int64_t> my_set_copy(my_set);
|
||||||
|
EXPECT_TRUE(my_set_copy == my_set);
|
||||||
|
EXPECT_TRUE(my_set == my_set_copy);
|
||||||
|
EXPECT_FALSE(my_set_copy != my_set);
|
||||||
|
EXPECT_FALSE(my_set != my_set_copy);
|
||||||
|
|
||||||
|
my_set.insert(kSetSize);
|
||||||
|
EXPECT_FALSE(my_set_copy == my_set);
|
||||||
|
EXPECT_FALSE(my_set == my_set_copy);
|
||||||
|
EXPECT_TRUE(my_set_copy != my_set);
|
||||||
|
EXPECT_TRUE(my_set != my_set_copy);
|
||||||
|
|
||||||
|
my_set.erase(kSetSize - 1);
|
||||||
|
EXPECT_FALSE(my_set_copy == my_set);
|
||||||
|
EXPECT_FALSE(my_set == my_set_copy);
|
||||||
|
EXPECT_TRUE(my_set_copy != my_set);
|
||||||
|
EXPECT_TRUE(my_set != my_set_copy);
|
||||||
|
|
||||||
|
safe_btree_map<std::string, int64_t> my_map;
|
||||||
|
for (int i = 0; i < kSetSize; ++i) {
|
||||||
|
my_map[std::string(i, 'a')] = i;
|
||||||
|
}
|
||||||
|
safe_btree_map<std::string, int64_t> my_map_copy(my_map);
|
||||||
|
EXPECT_TRUE(my_map_copy == my_map);
|
||||||
|
EXPECT_TRUE(my_map == my_map_copy);
|
||||||
|
EXPECT_FALSE(my_map_copy != my_map);
|
||||||
|
EXPECT_FALSE(my_map != my_map_copy);
|
||||||
|
|
||||||
|
++my_map_copy[std::string(7, 'a')];
|
||||||
|
EXPECT_FALSE(my_map_copy == my_map);
|
||||||
|
EXPECT_FALSE(my_map == my_map_copy);
|
||||||
|
EXPECT_TRUE(my_map_copy != my_map);
|
||||||
|
EXPECT_TRUE(my_map != my_map_copy);
|
||||||
|
|
||||||
|
my_map_copy = my_map;
|
||||||
|
my_map["hello"] = kSetSize;
|
||||||
|
EXPECT_FALSE(my_map_copy == my_map);
|
||||||
|
EXPECT_FALSE(my_map == my_map_copy);
|
||||||
|
EXPECT_TRUE(my_map_copy != my_map);
|
||||||
|
EXPECT_TRUE(my_map != my_map_copy);
|
||||||
|
|
||||||
|
my_map.erase(std::string(kSetSize - 1, 'a'));
|
||||||
|
EXPECT_FALSE(my_map_copy == my_map);
|
||||||
|
EXPECT_FALSE(my_map == my_map_copy);
|
||||||
|
EXPECT_TRUE(my_map_copy != my_map);
|
||||||
|
EXPECT_TRUE(my_map != my_map_copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace btree
|
1322
lib/xdelta3/draft-korn-vcdiff.txt
Normal file
1322
lib/xdelta3/draft-korn-vcdiff.txt
Normal file
File diff suppressed because it is too large
Load diff
32
lib/xdelta3/examples/Makefile
Normal file
32
lib/xdelta3/examples/Makefile
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
CFLAGS = -g -Wall -I.. -DXD3_DEBUG=1 -DNDEBUG=0 -DSIZEOF_SIZE_T=8 -DSIZEOF_UNSIGNED_LONG_LONG=8
|
||||||
|
#CFLAGS = -O3 -Wall -I.. -DXD3_DEBUG=0 -fno-builtin -DNDEBUG=1
|
||||||
|
# -pg
|
||||||
|
|
||||||
|
SOURCES = small_page_test.c encode_decode_test.c speed_test.c
|
||||||
|
|
||||||
|
DEPS = ../*.h ../*.c *.h
|
||||||
|
|
||||||
|
TARGETS = small_page_test encode_decode_test speed_test32 speed_test64 compare_test checksum_test
|
||||||
|
|
||||||
|
all: $(TARGETS)
|
||||||
|
|
||||||
|
small_page_test: small_page_test.c $(DEPS)
|
||||||
|
$(CC) $(CFLAGS) small_page_test.c -o small_page_test -DXD3_USE_LARGEFILE64=0 -DSECONDARY_DJW=1
|
||||||
|
|
||||||
|
encode_decode_test: encode_decode_test.c $(DEPS)
|
||||||
|
$(CC) $(CFLAGS) encode_decode_test.c -o encode_decode_test
|
||||||
|
|
||||||
|
speed_test32: speed_test.c $(DEPS)
|
||||||
|
$(CC) $(CFLAGS) -DXD3_USE_LARGEFILE64=0 speed_test.c -o speed_test32
|
||||||
|
|
||||||
|
speed_test64: speed_test.c $(DEPS)
|
||||||
|
$(CC) $(CFLAGS) -DXD3_USE_LARGEFILE64=1 speed_test.c -o speed_test64
|
||||||
|
|
||||||
|
compare_test: compare_test.c
|
||||||
|
$(CC) $(CFLAGS) compare_test.c -o compare_test
|
||||||
|
|
||||||
|
checksum_test: checksum_test.cc
|
||||||
|
$(CXX) $(CFLAGS) checksum_test.cc -o checksum_test
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -r -f *.exe *.stackdump $(TARGETS) *.dSYM *~
|
8
lib/xdelta3/examples/README.md
Normal file
8
lib/xdelta3/examples/README.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Files in this directory demonstrate how to use the Xdelta3 API. Copyrights
|
||||||
|
are held by the respective authors.
|
||||||
|
|
||||||
|
small_page_test.c -- how to use xdelta3 in an environment such as the kernel
|
||||||
|
for small pages with little memory
|
||||||
|
|
||||||
|
encode_decode_test.c -- how to use xdelta3 to process (encode/decode) data in
|
||||||
|
multiple windows with the non-blocking API
|
138
lib/xdelta3/examples/compare_test.c
Normal file
138
lib/xdelta3/examples/compare_test.c
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
/* xdelta3 - delta compression tools and library
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "xdelta3.h"
|
||||||
|
|
||||||
|
#define NUM (1<<20)
|
||||||
|
#define ITERS 100
|
||||||
|
|
||||||
|
/* From wikipedia on RDTSC */
|
||||||
|
inline uint64_t rdtsc() {
|
||||||
|
uint32_t lo, hi;
|
||||||
|
asm volatile ("rdtsc" : "=a" (lo), "=d" (hi));
|
||||||
|
return (uint64_t)hi << 32 | lo;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef int (*test_func)(const char *s1, const char *s2, int n);
|
||||||
|
|
||||||
|
void run_test(const char *buf1, const char *buf2,
|
||||||
|
const char *name, test_func func) {
|
||||||
|
uint64_t start, end;
|
||||||
|
uint64_t accum = 0;
|
||||||
|
int i, x;
|
||||||
|
|
||||||
|
for (i = 0; i < ITERS; i++) {
|
||||||
|
start = rdtsc();
|
||||||
|
x = func(buf1, buf2, NUM);
|
||||||
|
end = rdtsc();
|
||||||
|
accum += end - start;
|
||||||
|
assert(x == NUM - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
accum /= ITERS;
|
||||||
|
|
||||||
|
printf("%s : %qu cycles\n", name, accum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build w/ -fno-builtin for this to be fast, this assumes that there
|
||||||
|
* is a difference at s1[n-1] */
|
||||||
|
int memcmp_fake(const char *s1, const char *s2, int n) {
|
||||||
|
int x = memcmp(s1, s2, n);
|
||||||
|
return x < 0 ? n - 1 : n + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UNALIGNED_OK 1
|
||||||
|
static inline int
|
||||||
|
test2(const char *s1c, const char *s2c, int n)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
#if UNALIGNED_OK
|
||||||
|
int nint = n / sizeof(int);
|
||||||
|
|
||||||
|
if (nint >> 3)
|
||||||
|
{
|
||||||
|
int j = 0;
|
||||||
|
const int *s1 = (const int*)s1c;
|
||||||
|
const int *s2 = (const int*)s2c;
|
||||||
|
int nint_8 = nint - 8;
|
||||||
|
|
||||||
|
while (i <= nint_8 &&
|
||||||
|
s1[i++] == s2[j++] &&
|
||||||
|
s1[i++] == s2[j++] &&
|
||||||
|
s1[i++] == s2[j++] &&
|
||||||
|
s1[i++] == s2[j++] &&
|
||||||
|
s1[i++] == s2[j++] &&
|
||||||
|
s1[i++] == s2[j++] &&
|
||||||
|
s1[i++] == s2[j++] &&
|
||||||
|
s1[i++] == s2[j++]) { }
|
||||||
|
|
||||||
|
i = (i - 1) * sizeof(int);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (i < n && s1c[i] == s2c[i])
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
test1(const char *s1c, const char *s2c, int n) {
|
||||||
|
int i = 0;
|
||||||
|
while (i < n && s1c[i] == s2c[i])
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(/*int argc, char **argv*/) {
|
||||||
|
char *buf1 = malloc(NUM+1);
|
||||||
|
char *buf2 = malloc(NUM+1);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM; i++) {
|
||||||
|
buf1[i] = buf2[i] = rand();
|
||||||
|
}
|
||||||
|
|
||||||
|
buf2[NUM-1]++;
|
||||||
|
|
||||||
|
printf ("ALIGNED\n");
|
||||||
|
|
||||||
|
run_test(buf1, buf2, "memcmp", &memcmp_fake);
|
||||||
|
run_test(buf1, buf2, "test1", &test1);
|
||||||
|
run_test(buf1, buf2, "test2", &test2);
|
||||||
|
|
||||||
|
for (i = 0; i < NUM; i++) {
|
||||||
|
buf1[i] = buf2[i+1] = rand();
|
||||||
|
}
|
||||||
|
|
||||||
|
buf2[NUM]++;
|
||||||
|
|
||||||
|
printf ("UNALIGNED\n");
|
||||||
|
|
||||||
|
run_test(buf1, buf2+1, "memcmp", &memcmp_fake);
|
||||||
|
run_test(buf1, buf2+1, "test1", &test1);
|
||||||
|
run_test(buf1, buf2+1, "test2", &test2);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
203
lib/xdelta3/examples/encode_decode_test.c
Normal file
203
lib/xdelta3/examples/encode_decode_test.c
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
// Permission to distribute this example by
|
||||||
|
// Copyright (C) 2007 Ralf Junker
|
||||||
|
// Ralf Junker <delphi@yunqa.de>
|
||||||
|
// http://www.yunqa.de/delphi/
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "xdelta3.h"
|
||||||
|
#include "xdelta3.c"
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int code (
|
||||||
|
int encode,
|
||||||
|
FILE* InFile,
|
||||||
|
FILE* SrcFile ,
|
||||||
|
FILE* OutFile,
|
||||||
|
int BufSize )
|
||||||
|
{
|
||||||
|
int r, ret;
|
||||||
|
struct stat statbuf;
|
||||||
|
xd3_stream stream;
|
||||||
|
xd3_config config;
|
||||||
|
xd3_source source;
|
||||||
|
void* Input_Buf;
|
||||||
|
int Input_Buf_Read;
|
||||||
|
|
||||||
|
if (BufSize < XD3_ALLOCSIZE)
|
||||||
|
BufSize = XD3_ALLOCSIZE;
|
||||||
|
|
||||||
|
memset (&stream, 0, sizeof (stream));
|
||||||
|
memset (&source, 0, sizeof (source));
|
||||||
|
|
||||||
|
xd3_init_config(&config, XD3_ADLER32);
|
||||||
|
config.winsize = BufSize;
|
||||||
|
xd3_config_stream(&stream, &config);
|
||||||
|
|
||||||
|
if (SrcFile)
|
||||||
|
{
|
||||||
|
r = fstat(fileno(SrcFile), &statbuf);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
source.blksize = BufSize;
|
||||||
|
source.curblk = malloc(source.blksize);
|
||||||
|
|
||||||
|
/* Load 1st block of stream. */
|
||||||
|
r = fseek(SrcFile, 0, SEEK_SET);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
source.onblk = fread((void*)source.curblk, 1, source.blksize, SrcFile);
|
||||||
|
source.curblkno = 0;
|
||||||
|
/* Set the stream. */
|
||||||
|
xd3_set_source(&stream, &source);
|
||||||
|
}
|
||||||
|
|
||||||
|
Input_Buf = malloc(BufSize);
|
||||||
|
|
||||||
|
fseek(InFile, 0, SEEK_SET);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Input_Buf_Read = fread(Input_Buf, 1, BufSize, InFile);
|
||||||
|
if (Input_Buf_Read < BufSize)
|
||||||
|
{
|
||||||
|
xd3_set_flags(&stream, XD3_FLUSH | stream.flags);
|
||||||
|
}
|
||||||
|
xd3_avail_input(&stream, Input_Buf, Input_Buf_Read);
|
||||||
|
|
||||||
|
process:
|
||||||
|
if (encode)
|
||||||
|
ret = xd3_encode_input(&stream);
|
||||||
|
else
|
||||||
|
ret = xd3_decode_input(&stream);
|
||||||
|
|
||||||
|
switch (ret)
|
||||||
|
{
|
||||||
|
case XD3_INPUT:
|
||||||
|
{
|
||||||
|
fprintf (stderr,"XD3_INPUT\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
case XD3_OUTPUT:
|
||||||
|
{
|
||||||
|
fprintf (stderr,"XD3_OUTPUT\n");
|
||||||
|
r = fwrite(stream.next_out, 1, stream.avail_out, OutFile);
|
||||||
|
if (r != (int)stream.avail_out)
|
||||||
|
return r;
|
||||||
|
xd3_consume_output(&stream);
|
||||||
|
goto process;
|
||||||
|
}
|
||||||
|
|
||||||
|
case XD3_GETSRCBLK:
|
||||||
|
{
|
||||||
|
fprintf (stderr,"XD3_GETSRCBLK %qd\n", source.getblkno);
|
||||||
|
if (SrcFile)
|
||||||
|
{
|
||||||
|
r = fseek(SrcFile, source.blksize * source.getblkno, SEEK_SET);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
source.onblk = fread((void*)source.curblk, 1,
|
||||||
|
source.blksize, SrcFile);
|
||||||
|
source.curblkno = source.getblkno;
|
||||||
|
}
|
||||||
|
goto process;
|
||||||
|
}
|
||||||
|
|
||||||
|
case XD3_GOTHEADER:
|
||||||
|
{
|
||||||
|
fprintf (stderr,"XD3_GOTHEADER\n");
|
||||||
|
goto process;
|
||||||
|
}
|
||||||
|
|
||||||
|
case XD3_WINSTART:
|
||||||
|
{
|
||||||
|
fprintf (stderr,"XD3_WINSTART\n");
|
||||||
|
goto process;
|
||||||
|
}
|
||||||
|
|
||||||
|
case XD3_WINFINISH:
|
||||||
|
{
|
||||||
|
fprintf (stderr,"XD3_WINFINISH\n");
|
||||||
|
goto process;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
fprintf (stderr,"!!! INVALID %s %d !!!\n",
|
||||||
|
stream.msg, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
while (Input_Buf_Read == BufSize);
|
||||||
|
|
||||||
|
free(Input_Buf);
|
||||||
|
|
||||||
|
free((void*)source.curblk);
|
||||||
|
xd3_close_stream(&stream);
|
||||||
|
xd3_free_stream(&stream);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
FILE* InFile;
|
||||||
|
FILE* SrcFile;
|
||||||
|
FILE* OutFile;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
fprintf (stderr, "usage: %s source input\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *input = argv[2];
|
||||||
|
char *source = argv[1];
|
||||||
|
const char *output = "encoded.testdata";
|
||||||
|
const char *decoded = "decoded.testdata";
|
||||||
|
|
||||||
|
/* Encode */
|
||||||
|
|
||||||
|
InFile = fopen(input, "rb");
|
||||||
|
SrcFile = fopen(source, "rb");
|
||||||
|
OutFile = fopen(output, "wb");
|
||||||
|
|
||||||
|
r = code (1, InFile, SrcFile, OutFile, 0x1000);
|
||||||
|
|
||||||
|
fclose(OutFile);
|
||||||
|
fclose(SrcFile);
|
||||||
|
fclose(InFile);
|
||||||
|
|
||||||
|
if (r) {
|
||||||
|
fprintf (stderr, "Encode error: %d\n", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
|
||||||
|
InFile = fopen(output, "rb");
|
||||||
|
SrcFile = fopen(source, "rb");
|
||||||
|
OutFile = fopen(decoded, "wb");
|
||||||
|
|
||||||
|
r = code (0, InFile, SrcFile, OutFile, 0x1000);
|
||||||
|
|
||||||
|
fclose(OutFile);
|
||||||
|
fclose(SrcFile);
|
||||||
|
fclose(InFile);
|
||||||
|
|
||||||
|
if (r) {
|
||||||
|
fprintf (stderr, "Decode error: %d\n", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,389 @@
|
||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 46;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
B9001B65158D008900B9E855 /* xdelta3.c in Sources */ = {isa = PBXBuildFile; fileRef = B9001B63158D008900B9E855 /* xdelta3.c */; };
|
||||||
|
B9313C3C158D11BA001C1F28 /* file_v1_to_v2.bin in Resources */ = {isa = PBXBuildFile; fileRef = B9313C39158D11BA001C1F28 /* file_v1_to_v2.bin */; };
|
||||||
|
B9313C3D158D11BA001C1F28 /* file_v1.bin in Resources */ = {isa = PBXBuildFile; fileRef = B9313C3A158D11BA001C1F28 /* file_v1.bin */; };
|
||||||
|
B9313C3E158D11BA001C1F28 /* file_v2.bin in Resources */ = {isa = PBXBuildFile; fileRef = B9313C3B158D11BA001C1F28 /* file_v2.bin */; };
|
||||||
|
B9ADC6BF158CFD36007EF999 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9ADC6BE158CFD36007EF999 /* UIKit.framework */; };
|
||||||
|
B9ADC6C1158CFD36007EF999 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9ADC6C0158CFD36007EF999 /* Foundation.framework */; };
|
||||||
|
B9ADC6C3158CFD36007EF999 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9ADC6C2158CFD36007EF999 /* CoreGraphics.framework */; };
|
||||||
|
B9ADC6C9158CFD36007EF999 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B9ADC6C7158CFD36007EF999 /* InfoPlist.strings */; };
|
||||||
|
B9ADC6CB158CFD36007EF999 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B9ADC6CA158CFD36007EF999 /* main.m */; };
|
||||||
|
B9ADC6CF158CFD36007EF999 /* Xd3iOSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B9ADC6CE158CFD36007EF999 /* Xd3iOSAppDelegate.m */; };
|
||||||
|
B9ADC6D2158CFD36007EF999 /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B9ADC6D0158CFD36007EF999 /* MainStoryboard_iPhone.storyboard */; };
|
||||||
|
B9ADC6D5158CFD36007EF999 /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B9ADC6D3158CFD36007EF999 /* MainStoryboard_iPad.storyboard */; };
|
||||||
|
B9ADC6D8158CFD36007EF999 /* Xd3iOSViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B9ADC6D7158CFD36007EF999 /* Xd3iOSViewController.m */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
B9001B56158D008900B9E855 /* xdelta3-blkcache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-blkcache.h"; path = "../../../../xdelta3-blkcache.h"; sourceTree = "<group>"; };
|
||||||
|
B9001B57158D008900B9E855 /* xdelta3-cfgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-cfgs.h"; path = "../../../../xdelta3-cfgs.h"; sourceTree = "<group>"; };
|
||||||
|
B9001B58158D008900B9E855 /* xdelta3-decode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-decode.h"; path = "../../../../xdelta3-decode.h"; sourceTree = "<group>"; };
|
||||||
|
B9001B59158D008900B9E855 /* xdelta3-djw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-djw.h"; path = "../../../../xdelta3-djw.h"; sourceTree = "<group>"; };
|
||||||
|
B9001B5A158D008900B9E855 /* xdelta3-fgk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-fgk.h"; path = "../../../../xdelta3-fgk.h"; sourceTree = "<group>"; };
|
||||||
|
B9001B5B158D008900B9E855 /* xdelta3-hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-hash.h"; path = "../../../../xdelta3-hash.h"; sourceTree = "<group>"; };
|
||||||
|
B9001B5C158D008900B9E855 /* xdelta3-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-internal.h"; path = "../../../../xdelta3-internal.h"; sourceTree = "<group>"; };
|
||||||
|
B9001B5D158D008900B9E855 /* xdelta3-list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-list.h"; path = "../../../../xdelta3-list.h"; sourceTree = "<group>"; };
|
||||||
|
B9001B5E158D008900B9E855 /* xdelta3-main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-main.h"; path = "../../../../xdelta3-main.h"; sourceTree = "<group>"; };
|
||||||
|
B9001B5F158D008900B9E855 /* xdelta3-merge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-merge.h"; path = "../../../../xdelta3-merge.h"; sourceTree = "<group>"; };
|
||||||
|
B9001B60158D008900B9E855 /* xdelta3-python.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-python.h"; path = "../../../../xdelta3-python.h"; sourceTree = "<group>"; };
|
||||||
|
B9001B61158D008900B9E855 /* xdelta3-second.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-second.h"; path = "../../../../xdelta3-second.h"; sourceTree = "<group>"; };
|
||||||
|
B9001B62158D008900B9E855 /* xdelta3-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-test.h"; path = "../../../../xdelta3-test.h"; sourceTree = "<group>"; };
|
||||||
|
B9001B63158D008900B9E855 /* xdelta3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = xdelta3.c; path = ../../../../xdelta3.c; sourceTree = "<group>"; };
|
||||||
|
B9001B64158D008900B9E855 /* xdelta3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xdelta3.h; path = ../../../../xdelta3.h; sourceTree = "<group>"; };
|
||||||
|
B9313C39158D11BA001C1F28 /* file_v1_to_v2.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = file_v1_to_v2.bin; sourceTree = "<group>"; };
|
||||||
|
B9313C3A158D11BA001C1F28 /* file_v1.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = file_v1.bin; sourceTree = "<group>"; };
|
||||||
|
B9313C3B158D11BA001C1F28 /* file_v2.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = file_v2.bin; sourceTree = "<group>"; };
|
||||||
|
B9ADC6BA158CFD36007EF999 /* xdelta3-ios-test.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "xdelta3-ios-test.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
B9ADC6BE158CFD36007EF999 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||||
|
B9ADC6C0158CFD36007EF999 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||||
|
B9ADC6C2158CFD36007EF999 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
||||||
|
B9ADC6C6158CFD36007EF999 /* xdelta3-ios-test-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "xdelta3-ios-test-Info.plist"; sourceTree = "<group>"; };
|
||||||
|
B9ADC6C8158CFD36007EF999 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
|
B9ADC6CA158CFD36007EF999 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||||
|
B9ADC6CC158CFD36007EF999 /* xdelta3-ios-test-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "xdelta3-ios-test-Prefix.pch"; sourceTree = "<group>"; };
|
||||||
|
B9ADC6CD158CFD36007EF999 /* Xd3iOSAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Xd3iOSAppDelegate.h; sourceTree = "<group>"; };
|
||||||
|
B9ADC6CE158CFD36007EF999 /* Xd3iOSAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Xd3iOSAppDelegate.m; sourceTree = "<group>"; };
|
||||||
|
B9ADC6D1158CFD36007EF999 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPhone.storyboard; sourceTree = "<group>"; };
|
||||||
|
B9ADC6D4158CFD36007EF999 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPad.storyboard; sourceTree = "<group>"; };
|
||||||
|
B9ADC6D6158CFD36007EF999 /* Xd3iOSViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Xd3iOSViewController.h; sourceTree = "<group>"; };
|
||||||
|
B9ADC6D7158CFD36007EF999 /* Xd3iOSViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Xd3iOSViewController.m; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
B9ADC6B7158CFD36007EF999 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
B9ADC6BF158CFD36007EF999 /* UIKit.framework in Frameworks */,
|
||||||
|
B9ADC6C1158CFD36007EF999 /* Foundation.framework in Frameworks */,
|
||||||
|
B9ADC6C3158CFD36007EF999 /* CoreGraphics.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
B9ADC6AF158CFD36007EF999 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B9ADC6C4158CFD36007EF999 /* xdelta3-ios-test */,
|
||||||
|
B9ADC6BD158CFD36007EF999 /* Frameworks */,
|
||||||
|
B9ADC6BB158CFD36007EF999 /* Products */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
B9ADC6BB158CFD36007EF999 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B9ADC6BA158CFD36007EF999 /* xdelta3-ios-test.app */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
B9ADC6BD158CFD36007EF999 /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B9ADC6BE158CFD36007EF999 /* UIKit.framework */,
|
||||||
|
B9ADC6C0158CFD36007EF999 /* Foundation.framework */,
|
||||||
|
B9ADC6C2158CFD36007EF999 /* CoreGraphics.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
B9ADC6C4158CFD36007EF999 /* xdelta3-ios-test */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B9001B56158D008900B9E855 /* xdelta3-blkcache.h */,
|
||||||
|
B9001B57158D008900B9E855 /* xdelta3-cfgs.h */,
|
||||||
|
B9001B58158D008900B9E855 /* xdelta3-decode.h */,
|
||||||
|
B9001B59158D008900B9E855 /* xdelta3-djw.h */,
|
||||||
|
B9001B5A158D008900B9E855 /* xdelta3-fgk.h */,
|
||||||
|
B9001B5B158D008900B9E855 /* xdelta3-hash.h */,
|
||||||
|
B9001B5C158D008900B9E855 /* xdelta3-internal.h */,
|
||||||
|
B9001B5D158D008900B9E855 /* xdelta3-list.h */,
|
||||||
|
B9001B5E158D008900B9E855 /* xdelta3-main.h */,
|
||||||
|
B9001B5F158D008900B9E855 /* xdelta3-merge.h */,
|
||||||
|
B9001B60158D008900B9E855 /* xdelta3-python.h */,
|
||||||
|
B9001B61158D008900B9E855 /* xdelta3-second.h */,
|
||||||
|
B9001B62158D008900B9E855 /* xdelta3-test.h */,
|
||||||
|
B9001B63158D008900B9E855 /* xdelta3.c */,
|
||||||
|
B9001B64158D008900B9E855 /* xdelta3.h */,
|
||||||
|
B9ADC6CD158CFD36007EF999 /* Xd3iOSAppDelegate.h */,
|
||||||
|
B9ADC6CE158CFD36007EF999 /* Xd3iOSAppDelegate.m */,
|
||||||
|
B9ADC6D0158CFD36007EF999 /* MainStoryboard_iPhone.storyboard */,
|
||||||
|
B9ADC6D3158CFD36007EF999 /* MainStoryboard_iPad.storyboard */,
|
||||||
|
B9ADC6D6158CFD36007EF999 /* Xd3iOSViewController.h */,
|
||||||
|
B9ADC6D7158CFD36007EF999 /* Xd3iOSViewController.m */,
|
||||||
|
B9ADC6C5158CFD36007EF999 /* Supporting Files */,
|
||||||
|
);
|
||||||
|
path = "xdelta3-ios-test";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
B9ADC6C5158CFD36007EF999 /* Supporting Files */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B9313C39158D11BA001C1F28 /* file_v1_to_v2.bin */,
|
||||||
|
B9313C3A158D11BA001C1F28 /* file_v1.bin */,
|
||||||
|
B9313C3B158D11BA001C1F28 /* file_v2.bin */,
|
||||||
|
B9ADC6C6158CFD36007EF999 /* xdelta3-ios-test-Info.plist */,
|
||||||
|
B9ADC6C7158CFD36007EF999 /* InfoPlist.strings */,
|
||||||
|
B9ADC6CA158CFD36007EF999 /* main.m */,
|
||||||
|
B9ADC6CC158CFD36007EF999 /* xdelta3-ios-test-Prefix.pch */,
|
||||||
|
);
|
||||||
|
name = "Supporting Files";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
B9ADC6B9158CFD36007EF999 /* xdelta3-ios-test */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = B9ADC6DB158CFD36007EF999 /* Build configuration list for PBXNativeTarget "xdelta3-ios-test" */;
|
||||||
|
buildPhases = (
|
||||||
|
B9ADC6B6158CFD36007EF999 /* Sources */,
|
||||||
|
B9ADC6B7158CFD36007EF999 /* Frameworks */,
|
||||||
|
B9ADC6B8158CFD36007EF999 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = "xdelta3-ios-test";
|
||||||
|
productName = "xdelta3-ios-test";
|
||||||
|
productReference = B9ADC6BA158CFD36007EF999 /* xdelta3-ios-test.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
B9ADC6B1158CFD36007EF999 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
LastUpgradeCheck = 0420;
|
||||||
|
};
|
||||||
|
buildConfigurationList = B9ADC6B4158CFD36007EF999 /* Build configuration list for PBXProject "xdelta3-ios-test" */;
|
||||||
|
compatibilityVersion = "Xcode 3.2";
|
||||||
|
developmentRegion = English;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
);
|
||||||
|
mainGroup = B9ADC6AF158CFD36007EF999;
|
||||||
|
productRefGroup = B9ADC6BB158CFD36007EF999 /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
B9ADC6B9158CFD36007EF999 /* xdelta3-ios-test */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
B9ADC6B8158CFD36007EF999 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
B9ADC6C9158CFD36007EF999 /* InfoPlist.strings in Resources */,
|
||||||
|
B9ADC6D2158CFD36007EF999 /* MainStoryboard_iPhone.storyboard in Resources */,
|
||||||
|
B9ADC6D5158CFD36007EF999 /* MainStoryboard_iPad.storyboard in Resources */,
|
||||||
|
B9313C3C158D11BA001C1F28 /* file_v1_to_v2.bin in Resources */,
|
||||||
|
B9313C3D158D11BA001C1F28 /* file_v1.bin in Resources */,
|
||||||
|
B9313C3E158D11BA001C1F28 /* file_v2.bin in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
B9ADC6B6158CFD36007EF999 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
B9ADC6CB158CFD36007EF999 /* main.m in Sources */,
|
||||||
|
B9ADC6CF158CFD36007EF999 /* Xd3iOSAppDelegate.m in Sources */,
|
||||||
|
B9ADC6D8158CFD36007EF999 /* Xd3iOSViewController.m in Sources */,
|
||||||
|
B9001B65158D008900B9E855 /* xdelta3.c in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXVariantGroup section */
|
||||||
|
B9ADC6C7158CFD36007EF999 /* InfoPlist.strings */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
B9ADC6C8158CFD36007EF999 /* en */,
|
||||||
|
);
|
||||||
|
name = InfoPlist.strings;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
B9ADC6D0158CFD36007EF999 /* MainStoryboard_iPhone.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
B9ADC6D1158CFD36007EF999 /* en */,
|
||||||
|
);
|
||||||
|
name = MainStoryboard_iPhone.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
B9ADC6D3158CFD36007EF999 /* MainStoryboard_iPad.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
B9ADC6D4158CFD36007EF999 /* en */,
|
||||||
|
);
|
||||||
|
name = MainStoryboard_iPad.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
B9ADC6D9158CFD36007EF999 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_INPUT_FILETYPE = sourcecode.c.objc;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"XD3_USE_LARGEFILE64=0",
|
||||||
|
"XD3_POSIX=1",
|
||||||
|
"EXTERNAL_COMPRESSION=0",
|
||||||
|
"NOT_MAIN=1",
|
||||||
|
"XD3_MAIN=1",
|
||||||
|
"SECONDARY_DJW=1",
|
||||||
|
"XD3_DEBUG=1",
|
||||||
|
"REGRESSION_TEST=1",
|
||||||
|
"SHELL_TESTS=0",
|
||||||
|
"SECONDARY_FGK=1",
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||||
|
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
|
||||||
|
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 5.0;
|
||||||
|
OTHER_CFLAGS = (
|
||||||
|
"-DXD3_USE_LARGEFILE64=0",
|
||||||
|
"-DXD3_POSIX=1",
|
||||||
|
"-DEXTERNAL_COMPRESSION=0",
|
||||||
|
"-DNOT_MAIN=1",
|
||||||
|
"-DXD3_MAIN=1",
|
||||||
|
"-DSECONDARY_DJW=1",
|
||||||
|
"-DXD3_DEBUG=1",
|
||||||
|
"-DREGRESSION_TEST=1",
|
||||||
|
"-DSHELL_TESTS=0",
|
||||||
|
"-DSECONDARY_FGK=1",
|
||||||
|
);
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
B9ADC6DA158CFD36007EF999 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_INPUT_FILETYPE = sourcecode.c.objc;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"XD3_USE_LARGEFILE64=0",
|
||||||
|
"XD3_POSIX=1",
|
||||||
|
"EXTERNAL_COMPRESSION=0",
|
||||||
|
"NOT_MAIN=1",
|
||||||
|
"XD3_MAIN=1",
|
||||||
|
"SECONDARY_DJW=1",
|
||||||
|
"XD3_DEBUG=1",
|
||||||
|
"REGRESSION_TEST=1",
|
||||||
|
"SHELL_TESTS=0",
|
||||||
|
"SECONDARY_FGK=1",
|
||||||
|
);
|
||||||
|
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
|
||||||
|
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 5.0;
|
||||||
|
OTHER_CFLAGS = (
|
||||||
|
"-DXD3_USE_LARGEFILE64=0",
|
||||||
|
"-DXD3_POSIX=1",
|
||||||
|
"-DEXTERNAL_COMPRESSION=0",
|
||||||
|
"-DNOT_MAIN=1",
|
||||||
|
"-DXD3_MAIN=1",
|
||||||
|
"-DSECONDARY_DJW=1",
|
||||||
|
"-DXD3_DEBUG=1",
|
||||||
|
"-DREGRESSION_TEST=1",
|
||||||
|
"-DSHELL_TESTS=0",
|
||||||
|
"-DSECONDARY_FGK=1",
|
||||||
|
);
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
B9ADC6DC158CFD36007EF999 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
|
GCC_PREFIX_HEADER = "xdelta3-ios-test/xdelta3-ios-test-Prefix.pch";
|
||||||
|
INFOPLIST_FILE = "xdelta3-ios-test/xdelta3-ios-test-Info.plist";
|
||||||
|
OTHER_CFLAGS = "";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
WRAPPER_EXTENSION = app;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
B9ADC6DD158CFD36007EF999 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
|
GCC_PREFIX_HEADER = "xdelta3-ios-test/xdelta3-ios-test-Prefix.pch";
|
||||||
|
INFOPLIST_FILE = "xdelta3-ios-test/xdelta3-ios-test-Info.plist";
|
||||||
|
OTHER_CFLAGS = "";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
WRAPPER_EXTENSION = app;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
B9ADC6B4158CFD36007EF999 /* Build configuration list for PBXProject "xdelta3-ios-test" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
B9ADC6D9158CFD36007EF999 /* Debug */,
|
||||||
|
B9ADC6DA158CFD36007EF999 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
B9ADC6DB158CFD36007EF999 /* Build configuration list for PBXNativeTarget "xdelta3-ios-test" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
B9ADC6DC158CFD36007EF999 /* Debug */,
|
||||||
|
B9ADC6DD158CFD36007EF999 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = B9ADC6B1158CFD36007EF999 /* Project object */;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: objc *-*
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@interface Xd3iOSAppDelegate : UIResponder <UIApplicationDelegate>
|
||||||
|
|
||||||
|
@property (strong, nonatomic) UIWindow *window;
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: objc *-*
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "Xd3iOSAppDelegate.h"
|
||||||
|
|
||||||
|
@implementation Xd3iOSAppDelegate
|
||||||
|
|
||||||
|
@synthesize window = _window;
|
||||||
|
|
||||||
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||||
|
{
|
||||||
|
// Override point for customization after application launch.
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillResignActive:(UIApplication *)application
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||||
|
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidEnterBackground:(UIApplication *)application
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||||
|
If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillEnterForeground:(UIApplication *)application
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidBecomeActive:(UIApplication *)application
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillTerminate:(UIApplication *)application
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Called when the application is about to terminate.
|
||||||
|
Save data if appropriate.
|
||||||
|
See also applicationDidEnterBackground:.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: objc *-*
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@interface Xd3iOSViewController : UIViewController <UITextViewDelegate> {
|
||||||
|
NSString *inputSeed;
|
||||||
|
}
|
||||||
|
- (IBAction)startTest:(id)sender;
|
||||||
|
@property (weak, nonatomic) IBOutlet UITextField *theSeed;
|
||||||
|
@property (weak, nonatomic) IBOutlet UITextView *theView;
|
||||||
|
@property (atomic, retain) NSMutableString *theOutput;
|
||||||
|
@property (nonatomic) BOOL inTest;
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,177 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: objc *-*
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "Xd3iOSViewController.h"
|
||||||
|
#include "xdelta3.h"
|
||||||
|
#include "dispatch/queue.h"
|
||||||
|
#include "Foundation/NSBundle.h"
|
||||||
|
|
||||||
|
extern void (*xprintf_message_func)(const char* msg);
|
||||||
|
void print_to_view(const char* buf);
|
||||||
|
int xd3_main_cmdline(int argc, char **argv);
|
||||||
|
void do_localfile_test(void);
|
||||||
|
int compare_files(const char* file1, const char* file2);
|
||||||
|
Xd3iOSViewController *static_ptr;
|
||||||
|
|
||||||
|
@implementation Xd3iOSViewController
|
||||||
|
@synthesize theSeed = _theSeed;
|
||||||
|
@synthesize theView = _theView;
|
||||||
|
@synthesize theOutput = _theOutput;
|
||||||
|
@synthesize inTest = _inTest;
|
||||||
|
|
||||||
|
- (void)didReceiveMemoryWarning
|
||||||
|
{
|
||||||
|
[super didReceiveMemoryWarning];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - View lifecycle
|
||||||
|
|
||||||
|
- (void)viewDidLoad
|
||||||
|
{
|
||||||
|
[super viewDidLoad];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidUnload
|
||||||
|
{
|
||||||
|
[self setTheSeed:nil];
|
||||||
|
[self setTheView:nil];
|
||||||
|
[self setTheView:nil];
|
||||||
|
[super viewDidUnload];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillAppear:(BOOL)animated
|
||||||
|
{
|
||||||
|
[super viewWillAppear:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidAppear:(BOOL)animated
|
||||||
|
{
|
||||||
|
[super viewDidAppear:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillDisappear:(BOOL)animated
|
||||||
|
{
|
||||||
|
[super viewWillDisappear:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidDisappear:(BOOL)animated
|
||||||
|
{
|
||||||
|
[super viewDidDisappear:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||||
|
{
|
||||||
|
switch (interfaceOrientation) {
|
||||||
|
case UIInterfaceOrientationPortrait:
|
||||||
|
case UIInterfaceOrientationPortraitUpsideDown:
|
||||||
|
return YES;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
- (BOOL)textFieldShouldReturn:(UITextField*)theTextField {
|
||||||
|
if (theTextField == self.theSeed) {
|
||||||
|
[theTextField resignFirstResponder];
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
- (IBAction)startTest:(id)sender {
|
||||||
|
if (self.inTest) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.inTest = YES;
|
||||||
|
NSString *seedString = self.theSeed.text;
|
||||||
|
if ([seedString length] == 0) {
|
||||||
|
seedString = @"RFC3284";
|
||||||
|
}
|
||||||
|
static_ptr = self;
|
||||||
|
xprintf_message_func = &print_to_view;
|
||||||
|
self.theOutput = [[NSMutableString alloc] initWithFormat:@"Starting test (seed=%@)\n", seedString];
|
||||||
|
self.theView.text = self.theOutput;
|
||||||
|
dispatch_queue_t mq = dispatch_get_main_queue();
|
||||||
|
dispatch_queue_t dq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||||
|
dispatch_async(dq, ^{
|
||||||
|
do_localfile_test();
|
||||||
|
char *argv[] = { "xdelta3", "test", NULL };
|
||||||
|
xd3_main_cmdline(2, argv);
|
||||||
|
print_to_view("Finished unittest: success");
|
||||||
|
dispatch_async(mq, ^{
|
||||||
|
self.inTest = NO;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void printns_to_view(NSString* ns);
|
||||||
|
void printns_to_view(NSString* ns) {
|
||||||
|
dispatch_queue_t mq = dispatch_get_main_queue();
|
||||||
|
dispatch_async(mq, ^{
|
||||||
|
if ([static_ptr.theOutput length] < 25000) {
|
||||||
|
[static_ptr.theOutput appendString:ns];
|
||||||
|
} else {
|
||||||
|
static_ptr.theOutput = [[NSMutableString alloc] initWithString:ns];
|
||||||
|
}
|
||||||
|
static_ptr.theView.text = static_ptr.theOutput;
|
||||||
|
CGSize size = static_ptr.theView.contentSize;
|
||||||
|
[static_ptr.theView scrollRectToVisible:CGRectMake(0, size.height - 1, 1, 1) animated:NO];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_to_view(const char* buf) {
|
||||||
|
NSString *ns = [NSString stringWithCString:buf encoding:NSASCIIStringEncoding];
|
||||||
|
printns_to_view(ns);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_localfile_test(void) {
|
||||||
|
NSBundle *bundle;
|
||||||
|
bundle = [NSBundle mainBundle];
|
||||||
|
NSString *localfile1 = [bundle pathForResource:@"file_v1" ofType:@"bin"];
|
||||||
|
NSString *localfile2 = [bundle pathForResource:@"file_v2" ofType:@"bin"];
|
||||||
|
NSString *localfiled = [bundle pathForResource:@"file_v1_to_v2" ofType:@"bin"];
|
||||||
|
printns_to_view([localfile1 stringByAppendingString:@"\n"]);
|
||||||
|
printns_to_view([localfile2 stringByAppendingString:@"\n"]);
|
||||||
|
printns_to_view([localfiled stringByAppendingString:@"\n"]);
|
||||||
|
NSString *tmpdir = NSTemporaryDirectory();
|
||||||
|
NSString *tmpfile = [tmpdir stringByAppendingPathComponent:@"delta.tmp"];
|
||||||
|
printns_to_view([tmpfile stringByAppendingString:@"\n"]);
|
||||||
|
char *argv[] = {
|
||||||
|
"xdelta3", "-dfvv", "-s",
|
||||||
|
(char*)[localfile1 UTF8String],
|
||||||
|
(char*)[localfiled UTF8String],
|
||||||
|
(char*)[tmpfile UTF8String] };
|
||||||
|
xd3_main_cmdline(6, argv);
|
||||||
|
|
||||||
|
NSFileManager *filemgr;
|
||||||
|
|
||||||
|
filemgr = [NSFileManager defaultManager];
|
||||||
|
|
||||||
|
if ([filemgr contentsEqualAtPath: localfile2 andPath: tmpfile] == YES) {
|
||||||
|
printns_to_view(@"File contents match\n");
|
||||||
|
} else {
|
||||||
|
NSError *err1 = NULL;
|
||||||
|
NSDictionary *d1 = [filemgr attributesOfItemAtPath: tmpfile error: &err1];
|
||||||
|
if (err1 != NULL) {
|
||||||
|
printns_to_view([@"File localfile2 could not stat %s\n" stringByAppendingString: tmpfile]);
|
||||||
|
} else {
|
||||||
|
printns_to_view([@"File contents do not match!!!! tmpfile size=" stringByAppendingString:
|
||||||
|
[[NSMutableString alloc] initWithFormat:@"%llu\n", [d1 fileSize]]]);
|
||||||
|
}
|
||||||
|
compare_files([localfile2 UTF8String], [tmpfile UTF8String]);
|
||||||
|
}
|
||||||
|
print_to_view("Finished localfile test.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,2 @@
|
||||||
|
/* Localized versions of Info.plist keys */
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="1.0" toolsVersion="1938" systemVersion="11C74" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" initialViewController="2">
|
||||||
|
<dependencies>
|
||||||
|
<development defaultVersion="4200" identifier="xcode"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="933"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<scene sceneID="4">
|
||||||
|
<objects>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="3" sceneMemberID="firstResponder"/>
|
||||||
|
<viewController id="2" customClass="Xd3iOSViewController" sceneMemberID="viewController">
|
||||||
|
<view key="view" contentMode="scaleToFill" id="5">
|
||||||
|
<rect key="frame" x="0.0" y="20" width="768" height="1004"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="d7Y-KS-zOa">
|
||||||
|
<rect key="frame" x="258" y="28" width="197" height="37"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||||
|
<state key="normal" title="Start test">
|
||||||
|
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
|
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</state>
|
||||||
|
<state key="highlighted">
|
||||||
|
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</state>
|
||||||
|
<connections>
|
||||||
|
<action selector="startTest:" destination="2" eventType="touchUpInside" id="f4X-jg-ZsU"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Random seed" minimumFontSize="17" id="TZ8-OW-wjf">
|
||||||
|
<rect key="frame" x="27" y="28" width="197" height="31"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||||
|
<textInputTraits key="textInputTraits" autocorrectionType="no"/>
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="2" id="hjY-Ym-Fcw"/>
|
||||||
|
</connections>
|
||||||
|
</textField>
|
||||||
|
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" editable="NO" id="LHz-h6-ZBC">
|
||||||
|
<rect key="frame" x="27" y="88" width="721" height="887"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||||
|
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="2" id="fwY-fT-bCV"/>
|
||||||
|
</connections>
|
||||||
|
</textView>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" red="0.13337372065218178" green="0.1801924475036723" blue="0.21739130434782605" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
|
</view>
|
||||||
|
<connections>
|
||||||
|
<outlet property="theSeed" destination="TZ8-OW-wjf" id="QuA-uT-5IR"/>
|
||||||
|
<outlet property="theView" destination="LHz-h6-ZBC" id="s64-32-fBA"/>
|
||||||
|
</connections>
|
||||||
|
</viewController>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="-601" y="-1021"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
<classes>
|
||||||
|
<class className="Xd3iOSViewController" superclassName="UIViewController">
|
||||||
|
<source key="sourceIdentifier" type="project" relativePath="./Classes/Xd3iOSViewController.h"/>
|
||||||
|
<relationships>
|
||||||
|
<relationship kind="action" name="startTest:"/>
|
||||||
|
<relationship kind="outlet" name="theSeed" candidateClass="UITextField"/>
|
||||||
|
<relationship kind="outlet" name="theView" candidateClass="UITextView"/>
|
||||||
|
</relationships>
|
||||||
|
</class>
|
||||||
|
</classes>
|
||||||
|
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
||||||
|
<simulatedStatusBarMetrics key="statusBar" statusBarStyle="blackTranslucent"/>
|
||||||
|
<simulatedOrientationMetrics key="orientation"/>
|
||||||
|
<simulatedScreenMetrics key="destination"/>
|
||||||
|
</simulatedMetricsContainer>
|
||||||
|
</document>
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="1.0" toolsVersion="1906" systemVersion="11A511" targetRuntime="iOS.CocoaTouch" nextObjectID="6" propertyAccessControl="none" initialViewController="2">
|
||||||
|
<dependencies>
|
||||||
|
<development defaultVersion="4200" identifier="xcode"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="902"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<scene sceneID="5">
|
||||||
|
<objects>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="4" sceneMemberID="firstResponder"/>
|
||||||
|
<viewController id="2" customClass="Xd3iOSViewController" sceneMemberID="viewController">
|
||||||
|
<view key="view" contentMode="scaleToFill" id="3">
|
||||||
|
<rect key="frame" x="0.0" y="20" width="320" height="460"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<subviews/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
</objects>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
||||||
|
<simulatedStatusBarMetrics key="statusBar"/>
|
||||||
|
<simulatedOrientationMetrics key="orientation"/>
|
||||||
|
<simulatedScreenMetrics key="destination"/>
|
||||||
|
</simulatedMetricsContainer>
|
||||||
|
</document>
|
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,25 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: objc *-*
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
#import "Xd3iOSAppDelegate.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
@autoreleasepool {
|
||||||
|
return UIApplicationMain(argc, argv, nil, NSStringFromClass([Xd3iOSAppDelegate class]));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>${PRODUCT_NAME}</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>${EXECUTABLE_NAME}</string>
|
||||||
|
<key>CFBundleIconFiles</key>
|
||||||
|
<array/>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>Joshua-MacDonald.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>${PRODUCT_NAME}</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UIMainStoryboardFile</key>
|
||||||
|
<string>MainStoryboard_iPhone</string>
|
||||||
|
<key>UIMainStoryboardFile~ipad</key>
|
||||||
|
<string>MainStoryboard_iPad</string>
|
||||||
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
|
<array>
|
||||||
|
<string>armv7</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,14 @@
|
||||||
|
//
|
||||||
|
// Prefix header for all source files of the 'xdelta3-ios-test' target in the 'xdelta3-ios-test' project
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Availability.h>
|
||||||
|
|
||||||
|
#ifndef __IPHONE_5_0
|
||||||
|
#warning "This project uses features only available in iOS SDK 5.0 and later."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __OBJC__
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#endif
|
215
lib/xdelta3/examples/small_page_test.c
Normal file
215
lib/xdelta3/examples/small_page_test.c
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
/* xdelta3 - delta compression tools and library
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
|
||||||
|
#define SPACE_MAX 131072 // how much memory per process
|
||||||
|
#define OUTPUT_MAX 1024 // max size for output
|
||||||
|
#define XD3_ALLOCSIZE 256 // internal size for various buffers
|
||||||
|
#define IOPT_SIZE 128 // instruction buffer
|
||||||
|
|
||||||
|
// SPACE_MAX of 32K is sufficient for most inputs with XD3_COMPLEVEL_1
|
||||||
|
// XD3_COMPLEVEL_9 requires about 4x more space than XD3_COMPLEVEL_1
|
||||||
|
|
||||||
|
#include "xdelta3.h"
|
||||||
|
#include "xdelta3.c"
|
||||||
|
|
||||||
|
typedef struct _context {
|
||||||
|
uint8_t *buffer;
|
||||||
|
int allocated;
|
||||||
|
} context_t;
|
||||||
|
|
||||||
|
static int max_allocated = 0;
|
||||||
|
|
||||||
|
void*
|
||||||
|
process_alloc (void* opaque, usize_t items, usize_t size)
|
||||||
|
{
|
||||||
|
context_t *ctx = (context_t*) opaque;
|
||||||
|
usize_t t = items * size;
|
||||||
|
void *ret;
|
||||||
|
|
||||||
|
if (ctx->allocated + t > SPACE_MAX)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ctx->buffer + ctx->allocated;
|
||||||
|
ctx->allocated += t;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
process_free (void* opaque, void *ptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
process_page (int is_encode,
|
||||||
|
int (*func) (xd3_stream *),
|
||||||
|
const uint8_t *input,
|
||||||
|
usize_t input_size,
|
||||||
|
const uint8_t *source,
|
||||||
|
uint8_t *output,
|
||||||
|
usize_t *output_size,
|
||||||
|
usize_t output_size_max,
|
||||||
|
int flags) {
|
||||||
|
|
||||||
|
/* On my x86 this is 1072 of objects on the stack */
|
||||||
|
xd3_stream stream;
|
||||||
|
xd3_config config;
|
||||||
|
xd3_source src;
|
||||||
|
context_t *ctx = calloc(SPACE_MAX, 1);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset (&config, 0, sizeof(config));
|
||||||
|
|
||||||
|
if (ctx == NULL)
|
||||||
|
{
|
||||||
|
printf("calloc failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->buffer = (uint8_t*)ctx;
|
||||||
|
ctx->allocated = sizeof(*ctx);
|
||||||
|
|
||||||
|
config.flags = flags;
|
||||||
|
config.winsize = PAGE_SIZE;
|
||||||
|
config.sprevsz = PAGE_SIZE;
|
||||||
|
config.srcwin_maxsz = PAGE_SIZE;
|
||||||
|
config.iopt_size = IOPT_SIZE;
|
||||||
|
config.alloc = &process_alloc;
|
||||||
|
config.freef = &process_free;
|
||||||
|
config.opaque = (void*) ctx;
|
||||||
|
|
||||||
|
src.blksize = PAGE_SIZE;
|
||||||
|
src.onblk = PAGE_SIZE;
|
||||||
|
src.curblk = source;
|
||||||
|
src.curblkno = 0;
|
||||||
|
|
||||||
|
if ((ret = xd3_config_stream (&stream, &config)) != 0 ||
|
||||||
|
(ret = xd3_set_source_and_size (&stream, &src, PAGE_SIZE)) != 0 ||
|
||||||
|
(ret = xd3_process_stream (is_encode,
|
||||||
|
&stream,
|
||||||
|
func, 1,
|
||||||
|
input, input_size,
|
||||||
|
output, output_size,
|
||||||
|
output_size_max)) != 0)
|
||||||
|
{
|
||||||
|
if (stream.msg != NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "stream message: %s\n", stream.msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xd3_free_stream (&stream);
|
||||||
|
if (max_allocated < ctx->allocated)
|
||||||
|
{
|
||||||
|
max_allocated = ctx->allocated;
|
||||||
|
fprintf(stderr, "max allocated %d\n", max_allocated);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ctx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test(int stride, int encode_flags)
|
||||||
|
{
|
||||||
|
uint8_t frompg[PAGE_SIZE];
|
||||||
|
uint8_t topg[PAGE_SIZE];
|
||||||
|
uint8_t output[OUTPUT_MAX];
|
||||||
|
uint8_t reout[PAGE_SIZE];
|
||||||
|
usize_t output_size;
|
||||||
|
usize_t re_size;
|
||||||
|
int i, j, ret;
|
||||||
|
|
||||||
|
for (i = 0; i < PAGE_SIZE; i++)
|
||||||
|
{
|
||||||
|
topg[i] = frompg[i] = (rand() >> 3 ^ rand() >> 6 ^ rand() >> 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
// change 1 byte every stride
|
||||||
|
if (stride > 0)
|
||||||
|
{
|
||||||
|
for (j = stride; j <= PAGE_SIZE; j += stride)
|
||||||
|
{
|
||||||
|
topg[j - 1] ^= 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = process_page (1, xd3_encode_input,
|
||||||
|
topg, PAGE_SIZE,
|
||||||
|
frompg, output,
|
||||||
|
&output_size, OUTPUT_MAX,
|
||||||
|
encode_flags)) != 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "encode failed: stride %u flags 0x%x\n",
|
||||||
|
stride, encode_flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = process_page (0, xd3_decode_input,
|
||||||
|
output, output_size,
|
||||||
|
frompg, reout,
|
||||||
|
&re_size, PAGE_SIZE,
|
||||||
|
0)) != 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "decode failed: stride %u output_size %u flags 0x%x\n",
|
||||||
|
stride, output_size, encode_flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output_size > OUTPUT_MAX || re_size != PAGE_SIZE)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "internal error: %u != %u\n", output_size, re_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < PAGE_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (reout[i] != topg[i])
|
||||||
|
{
|
||||||
|
fprintf (stderr, "encode-decode error: position %d\n", i);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "stride %d flags 0x%x size %u ",
|
||||||
|
stride, encode_flags, output_size);
|
||||||
|
fprintf(stderr, "%s\n", (ret == 0) ? "OK" : "FAIL");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int stride;
|
||||||
|
int level;
|
||||||
|
|
||||||
|
for (level = 1; level < 10; level = (level == 1 ? 3 : level + 3))
|
||||||
|
{
|
||||||
|
int lflag = level << XD3_COMPLEVEL_SHIFT;
|
||||||
|
|
||||||
|
for (stride = 2; stride <= PAGE_SIZE; stride += 2)
|
||||||
|
{
|
||||||
|
test(stride, lflag);
|
||||||
|
test(stride, lflag | XD3_SEC_DJW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
87
lib/xdelta3/examples/speed_test.c
Normal file
87
lib/xdelta3/examples/speed_test.c
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/* xdelta3 - delta compression tools and library
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
usize_t bench_speed(const uint8_t *from_buf, const size_t from_len,
|
||||||
|
const uint8_t *to_buf, const size_t to_len,
|
||||||
|
uint8_t *delta_buf, const size_t delta_alloc,
|
||||||
|
int flags) {
|
||||||
|
usize_t delta_size;
|
||||||
|
int ret = xd3_encode_memory(to_buf, to_len, from_buf, from_len,
|
||||||
|
delta_buf, &delta_size, delta_alloc, flags);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "encode failure: %d: %s\n", ret, xd3_strerror(ret));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return delta_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
int repeat, level;
|
||||||
|
char *from, *to;
|
||||||
|
uint8_t *from_buf = NULL, *to_buf = NULL, *delta_buf = NULL;
|
||||||
|
size_t from_len = 0, to_len, delta_alloc, delta_size = 0;
|
||||||
|
long start, finish;
|
||||||
|
int i, ret;
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
if (argc != 5) {
|
||||||
|
fprintf(stderr, "usage: speed_test LEVEL COUNT FROM TO\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
level = atoi(argv[1]);
|
||||||
|
repeat = atoi(argv[2]);
|
||||||
|
from = argv[3];
|
||||||
|
to = argv[4];
|
||||||
|
flags = (level << XD3_COMPLEVEL_SHIFT) & XD3_COMPLEVEL_MASK;
|
||||||
|
|
||||||
|
if ((strcmp(from, "null") != 0 &&
|
||||||
|
(ret = read_whole_file(from, &from_buf, &from_len))) ||
|
||||||
|
(ret = read_whole_file(to, &to_buf, &to_len))) {
|
||||||
|
fprintf(stderr, "read_whole_file error\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
delta_alloc = to_len * 11 / 10;
|
||||||
|
delta_buf = main_malloc(delta_alloc);
|
||||||
|
|
||||||
|
start = get_millisecs_now();
|
||||||
|
|
||||||
|
for (i = 0; i < repeat; ++i) {
|
||||||
|
delta_size = bench_speed(from_buf, from_len,
|
||||||
|
to_buf, to_len, delta_buf, delta_alloc, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
finish = get_millisecs_now();
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"STAT: encode %3.2f ms from %s to %s repeat %d %zdbit delta %zd\n",
|
||||||
|
(double)(finish - start) / repeat, from, to, repeat, sizeof (xoff_t) * 8, delta_size);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
if (0) {
|
||||||
|
exit:
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
main_free(to_buf);
|
||||||
|
main_free(from_buf);
|
||||||
|
main_free(delta_buf);
|
||||||
|
return ret;
|
||||||
|
}
|
56
lib/xdelta3/examples/test.h
Normal file
56
lib/xdelta3/examples/test.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/* xdelta3 - delta compression tools and library
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define NOT_MAIN 1
|
||||||
|
|
||||||
|
#include "xdelta3.h"
|
||||||
|
#include "xdelta3.c"
|
||||||
|
|
||||||
|
static int read_whole_file(const char *name,
|
||||||
|
uint8_t **buf_ptr,
|
||||||
|
size_t *buf_len) {
|
||||||
|
main_file file;
|
||||||
|
int ret;
|
||||||
|
xoff_t len;
|
||||||
|
usize_t nread;
|
||||||
|
main_file_init(&file);
|
||||||
|
file.filename = name;
|
||||||
|
ret = main_file_open(&file, name, XO_READ);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "open failed\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
ret = main_file_stat(&file, &len);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "stat failed\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*buf_len) = (size_t)len;
|
||||||
|
(*buf_ptr) = (uint8_t*) main_malloc(*buf_len);
|
||||||
|
ret = main_file_read(&file, *buf_ptr, *buf_len, &nread,
|
||||||
|
"read failed");
|
||||||
|
if (ret == 0 && *buf_len == nread) {
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "invalid read\n");
|
||||||
|
ret = XD3_INTERNAL;
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
main_file_cleanup(&file);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
8
lib/xdelta3/generate_build_files.sh
Normal file
8
lib/xdelta3/generate_build_files.sh
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
aclocal &&
|
||||||
|
autoreconf --install &&
|
||||||
|
libtoolize &&
|
||||||
|
autoconf &&
|
||||||
|
automake --add-missing &&
|
||||||
|
automake
|
274
lib/xdelta3/go/src/regtest.go
Normal file
274
lib/xdelta3/go/src/regtest.go
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"path"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"xdelta"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
xdataset = "/volume/home/jmacd/src/testdata"
|
||||||
|
xcompare = "/volume/home/jmacd/src/xdelta-devel/xdelta3/build/x86_64-pc-linux-gnu-m64/xoff64/xdelta3"
|
||||||
|
xdelta3 = "/volume/home/jmacd/src/xdelta-64bithash/xdelta3/build/x86_64-pc-linux-gnu-m64/usize64/xoff64/xdelta3"
|
||||||
|
seed = 1422253499919909358
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
srcbuf_size int64
|
||||||
|
window_size int64
|
||||||
|
blocksize int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewC() Config {
|
||||||
|
// TODO make these (and above) flags
|
||||||
|
return Config{1<<26, 1<<22, 1<<16}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) smokeTest(t *xdelta.TestGroup, p xdelta.Program) {
|
||||||
|
target := "Hello world!"
|
||||||
|
source := "Hello world, nice to meet you!"
|
||||||
|
|
||||||
|
enc, err := t.Exec("encode", p, true, []string{"-e"})
|
||||||
|
if err != nil {
|
||||||
|
t.Panic(err)
|
||||||
|
}
|
||||||
|
dec, err := t.Exec("decode", p, true, []string{"-d"})
|
||||||
|
if err != nil {
|
||||||
|
t.Panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
encodeout := t.Drain(enc.Stdout, "encode.stdout")
|
||||||
|
decodeout := t.Drain(dec.Stdout, "decode.stdout")
|
||||||
|
|
||||||
|
t.Empty(enc.Stderr, "encode")
|
||||||
|
t.Empty(dec.Stderr, "decode")
|
||||||
|
|
||||||
|
t.TestWrite("encode.stdin", enc.Stdin, []byte(target))
|
||||||
|
t.TestWrite("encode.srcin", enc.Srcin, []byte(source))
|
||||||
|
|
||||||
|
t.TestWrite("decode.stdin", dec.Stdin, <-encodeout)
|
||||||
|
t.TestWrite("decode.srcin", dec.Srcin, []byte(source))
|
||||||
|
|
||||||
|
if do := string(<-decodeout); do != target {
|
||||||
|
t.Panic(fmt.Errorf("It's not working! %s\n!=\n%s\n", do, target))
|
||||||
|
}
|
||||||
|
t.Wait(enc, dec)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PairTest struct {
|
||||||
|
// Input
|
||||||
|
Config
|
||||||
|
program xdelta.Program
|
||||||
|
source, target string
|
||||||
|
|
||||||
|
// Output
|
||||||
|
TestOutput
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestOutput struct {
|
||||||
|
encoded int64
|
||||||
|
encDuration time.Duration
|
||||||
|
decDuration time.Duration
|
||||||
|
encSysDuration time.Duration
|
||||||
|
decSysDuration time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (to *TestOutput) Add(a TestOutput) {
|
||||||
|
to.encoded += a.encoded
|
||||||
|
to.encDuration += a.encDuration
|
||||||
|
to.decDuration += a.decDuration
|
||||||
|
to.encSysDuration += a.encSysDuration
|
||||||
|
to.decSysDuration += a.decSysDuration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (to *TestOutput) String() string {
|
||||||
|
return fmt.Sprintf("SIZE: %v\tT: %v\tTSYS: %v\tDT: %v\tDTSYS: %v",
|
||||||
|
to.encoded, to.encDuration, to.encSysDuration, to.decDuration, to.encSysDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
// P is the test program, Q is the reference version.
|
||||||
|
func (cfg Config) datasetTest(t *xdelta.TestGroup, p, q xdelta.Program) {
|
||||||
|
dir, err := os.Open(xdataset)
|
||||||
|
if err != nil {
|
||||||
|
t.Panic(err)
|
||||||
|
}
|
||||||
|
dents, err := dir.Readdir(-1)
|
||||||
|
if err != nil {
|
||||||
|
t.Panic(err)
|
||||||
|
}
|
||||||
|
paths := make([]string, len(dents))
|
||||||
|
var total int64
|
||||||
|
for i, d := range dents {
|
||||||
|
if !d.Mode().IsRegular() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
paths[i] = fmt.Sprint(xdataset, "/", d.Name())
|
||||||
|
total += d.Size()
|
||||||
|
}
|
||||||
|
meansize := total / int64(len(dents))
|
||||||
|
largest := uint(20)
|
||||||
|
for ; largest <= 31 && 1<<largest < meansize; largest++ {}
|
||||||
|
|
||||||
|
sort.Strings(paths)
|
||||||
|
|
||||||
|
testSum := map[uint]*TestOutput{}
|
||||||
|
compSum := map[uint]*TestOutput{}
|
||||||
|
|
||||||
|
for _, in1 := range paths {
|
||||||
|
for _, in2 := range paths {
|
||||||
|
if in1 == in2 { continue }
|
||||||
|
|
||||||
|
// 1/4, 1/2, and 1 of the power-of-2 rounded-up mean size
|
||||||
|
for b := largest - 2; b <= largest; b++ {
|
||||||
|
if _, has := testSum[b]; !has {
|
||||||
|
testSum[b] = &TestOutput{}
|
||||||
|
compSum[b] = &TestOutput{}
|
||||||
|
}
|
||||||
|
c1 := cfg
|
||||||
|
c1.srcbuf_size = 1<<b
|
||||||
|
ptest := &PairTest{c1, p, in1, in2, TestOutput{-1, 0, 0, 0, 0}}
|
||||||
|
ptest.datasetPairTest(t, 1<<b);
|
||||||
|
qtest := &PairTest{c1, q, in1, in2, TestOutput{-1, 0, 0, 0, 0}}
|
||||||
|
qtest.datasetPairTest(t, 1<<b)
|
||||||
|
|
||||||
|
testSum[b].Add(ptest.TestOutput)
|
||||||
|
compSum[b].Add(qtest.TestOutput)
|
||||||
|
|
||||||
|
fmt.Printf("%s, %s: %.2f%% %+d/%d\n\tE:%.2f%%/%s(%.2f%%/%s) D:%.2f%%/%s(%.2f%%/%s) [B=%d]\n",
|
||||||
|
path.Base(in1), path.Base(in2),
|
||||||
|
float64(ptest.encoded - qtest.encoded) * 100.0 / float64(qtest.encoded),
|
||||||
|
ptest.encoded - qtest.encoded,
|
||||||
|
qtest.encoded,
|
||||||
|
(ptest.encDuration - qtest.encDuration).Seconds() * 100.0 / qtest.encDuration.Seconds(),
|
||||||
|
qtest.encDuration,
|
||||||
|
(ptest.decDuration - qtest.decDuration).Seconds() * 100.0 / qtest.decDuration.Seconds(),
|
||||||
|
qtest.encDuration,
|
||||||
|
(ptest.encSysDuration - qtest.encSysDuration).Seconds() * 100.0 / qtest.encSysDuration.Seconds(),
|
||||||
|
qtest.encSysDuration,
|
||||||
|
(ptest.decSysDuration - qtest.decSysDuration).Seconds() * 100.0 / qtest.decSysDuration.Seconds(),
|
||||||
|
qtest.decSysDuration,
|
||||||
|
1<<b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var keys []uint
|
||||||
|
for k, _ := range testSum {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
for _, k := range keys {
|
||||||
|
fmt.Printf("B=%v\nTEST: %v\nCOMP: %v\n", 1<<k, testSum[k], compSum[k])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *PairTest) datasetPairTest(t *xdelta.TestGroup, meanSize int64) {
|
||||||
|
cfg := pt.Config
|
||||||
|
eargs := []string{"-e", fmt.Sprint("-B", cfg.srcbuf_size), // "-q",
|
||||||
|
fmt.Sprint("-W", cfg.window_size), "-s", pt.source,
|
||||||
|
"-I0", "-S", "none", pt.target}
|
||||||
|
enc, err := t.Exec("encode", pt.program, false, eargs)
|
||||||
|
if err != nil {
|
||||||
|
t.Panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dargs := []string{"-dc", fmt.Sprint("-B", cfg.srcbuf_size), //"-q",
|
||||||
|
fmt.Sprint("-W", cfg.window_size), "-s", pt.source,
|
||||||
|
"-S", "none"}
|
||||||
|
|
||||||
|
dec, err := t.Exec("decode", pt.program, false, dargs)
|
||||||
|
if err != nil {
|
||||||
|
t.Panic(err)
|
||||||
|
}
|
||||||
|
tgt_check, err := os.Open(pt.target)
|
||||||
|
if err != nil {
|
||||||
|
t.Panic(err)
|
||||||
|
}
|
||||||
|
tgt_info, err := tgt_check.Stat()
|
||||||
|
if err != nil {
|
||||||
|
t.Panic(err)
|
||||||
|
}
|
||||||
|
t.Empty(enc.Stderr, "encode")
|
||||||
|
t.Empty(dec.Stderr, "decode")
|
||||||
|
t.CopyStreams(enc.Stdout, dec.Stdin, &pt.encoded)
|
||||||
|
t.CompareStreams(dec.Stdout, tgt_check, tgt_info.Size())
|
||||||
|
|
||||||
|
t.Wait(enc, dec)
|
||||||
|
|
||||||
|
pt.decDuration = dec.Cmd.ProcessState.UserTime()
|
||||||
|
pt.encDuration = enc.Cmd.ProcessState.UserTime()
|
||||||
|
pt.decSysDuration = dec.Cmd.ProcessState.SystemTime()
|
||||||
|
pt.encSysDuration = enc.Cmd.ProcessState.SystemTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg Config) offsetTest(t *xdelta.TestGroup, p xdelta.Program, offset, length int64) {
|
||||||
|
eargs := []string{"-e", "-0", fmt.Sprint("-B", cfg.srcbuf_size), "-q",
|
||||||
|
fmt.Sprint("-W", cfg.window_size)}
|
||||||
|
enc, err := t.Exec("encode", p, true, eargs)
|
||||||
|
if err != nil {
|
||||||
|
t.Panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dargs := []string{"-d", fmt.Sprint("-B", cfg.srcbuf_size), "-q",
|
||||||
|
fmt.Sprint("-W", cfg.window_size)}
|
||||||
|
dec, err := t.Exec("decode", p, true, dargs)
|
||||||
|
if err != nil {
|
||||||
|
t.Panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The pipe used to read the decoder output and compare
|
||||||
|
// against the target.
|
||||||
|
read, write := io.Pipe()
|
||||||
|
|
||||||
|
t.Empty(enc.Stderr, "encode")
|
||||||
|
t.Empty(dec.Stderr, "decode")
|
||||||
|
|
||||||
|
var encoded_size int64
|
||||||
|
t.CopyStreams(enc.Stdout, dec.Stdin, &encoded_size)
|
||||||
|
t.CompareStreams(dec.Stdout, read, length)
|
||||||
|
|
||||||
|
// The decoder output ("read", above) is compared with the
|
||||||
|
// test-provided output ("write", below). The following
|
||||||
|
// generates two identical inputs.
|
||||||
|
t.WriteRstreams("encode", seed, offset, length, enc.Srcin, enc.Stdin)
|
||||||
|
t.WriteRstreams("decode", seed, offset, length, dec.Srcin, write)
|
||||||
|
t.Wait(enc, dec)
|
||||||
|
|
||||||
|
expect := cfg.srcbuf_size - offset
|
||||||
|
if float64(encoded_size) < (0.95 * float64(expect)) ||
|
||||||
|
float64(encoded_size) > (1.05 * float64(expect)) {
|
||||||
|
t.Fail("encoded size should be ~=", expect, ", actual ", encoded_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
r, err := xdelta.NewRunner()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer r.Cleanup()
|
||||||
|
|
||||||
|
cfg := NewC()
|
||||||
|
|
||||||
|
prog := xdelta.Program{xdelta3}
|
||||||
|
|
||||||
|
r.RunTest("smoketest", func(t *xdelta.TestGroup) { cfg.smokeTest(t, prog) })
|
||||||
|
|
||||||
|
for i := uint(29); i <= 33; i += 1 {
|
||||||
|
// The arguments to offsetTest are offset, source
|
||||||
|
// window size, and file size. The source window size
|
||||||
|
// is (2 << i) and (in the 3.0x release branch) is
|
||||||
|
// limited to 2^31, so the the greatest value of i is
|
||||||
|
// 30.
|
||||||
|
cfg.srcbuf_size = 2 << i
|
||||||
|
r.RunTest(fmt.Sprint("offset", i), func(t *xdelta.TestGroup) {
|
||||||
|
cfg.offsetTest(t, prog, 1 << i, 3 << i) })
|
||||||
|
}
|
||||||
|
|
||||||
|
comp := xdelta.Program{xcompare}
|
||||||
|
|
||||||
|
r.RunTest("dataset", func(t *xdelta.TestGroup) { cfg.datasetTest(t, prog, comp) })
|
||||||
|
}
|
71
lib/xdelta3/go/src/xdelta/rstream.go
Normal file
71
lib/xdelta3/go/src/xdelta/rstream.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package xdelta
|
||||||
|
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"math/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
blocksize = 1<<17
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t *TestGroup) WriteRstreams(desc string, seed, offset, len int64,
|
||||||
|
src, tgt io.WriteCloser) {
|
||||||
|
t.Go("src-write:"+desc, func (g *Goroutine) {
|
||||||
|
writeOne(g, seed, 0, len, tgt, false)
|
||||||
|
})
|
||||||
|
t.Go("tgt-write:"+desc, func (g *Goroutine) {
|
||||||
|
writeOne(g, seed, offset, len, src, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeOne(g *Goroutine, seed, offset, len int64, stream io.WriteCloser, readall bool) {
|
||||||
|
if !readall {
|
||||||
|
// Allow the source-read to fail or block until the process terminates.
|
||||||
|
// This behavior is reserved for the decoder, which is not required to
|
||||||
|
// read the entire source.
|
||||||
|
g.OK()
|
||||||
|
}
|
||||||
|
if offset != 0 {
|
||||||
|
// Fill with other random data until the offset
|
||||||
|
if err := writeRand(g, rand.New(rand.NewSource(^seed)), offset, stream); err != nil {
|
||||||
|
g.Panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := writeRand(g, rand.New(rand.NewSource(seed)),
|
||||||
|
len - offset, stream); err != nil {
|
||||||
|
g.Panic(err)
|
||||||
|
}
|
||||||
|
if err := stream.Close(); err != nil {
|
||||||
|
g.Panic(err)
|
||||||
|
}
|
||||||
|
g.OK()
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeRand(g *Goroutine, r *rand.Rand, len int64, s io.Writer) error {
|
||||||
|
blk := make([]byte, blocksize)
|
||||||
|
for len > 0 {
|
||||||
|
fillRand(r, blk)
|
||||||
|
c := blocksize
|
||||||
|
if len < blocksize {
|
||||||
|
c = int(len)
|
||||||
|
}
|
||||||
|
if _, err := s.Write(blk[0:c]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
len -= int64(c)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillRand(r *rand.Rand, blk []byte) {
|
||||||
|
for p := 0; p < len(blk); {
|
||||||
|
v := r.Int63()
|
||||||
|
for i := 7; i != 0 && p < len(blk); i-- {
|
||||||
|
blk[p] = byte(v)
|
||||||
|
p++
|
||||||
|
v >>= 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
71
lib/xdelta3/go/src/xdelta/run.go
Normal file
71
lib/xdelta3/go/src/xdelta/run.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package xdelta
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Program struct {
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Run struct {
|
||||||
|
Cmd exec.Cmd
|
||||||
|
Srcfile string
|
||||||
|
Stdin io.WriteCloser
|
||||||
|
Srcin io.WriteCloser
|
||||||
|
Stdout io.ReadCloser
|
||||||
|
Stderr io.ReadCloser
|
||||||
|
}
|
||||||
|
|
||||||
|
type Runner struct {
|
||||||
|
Testdir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Run) Wait() error {
|
||||||
|
return r.Cmd.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRunner() (*Runner, error) {
|
||||||
|
if dir, err := ioutil.TempDir(tmpDir, "xrt"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return &Runner{dir}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Runner) newTestGroup(name string) (*TestGroup) {
|
||||||
|
tg := &TestGroup{Runner: r}
|
||||||
|
tg.WaitGroup.Add(1)
|
||||||
|
g0 := &Goroutine{tg, name, false}
|
||||||
|
tg.running = append(tg.running, g0)
|
||||||
|
tg.main = g0
|
||||||
|
return tg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Runner) Cleanup() {
|
||||||
|
os.RemoveAll(r.Testdir)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Runner) RunTest(name string, f func (t *TestGroup)) {
|
||||||
|
t := r.newTestGroup(name)
|
||||||
|
c := make(chan interface{})
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
rec := recover()
|
||||||
|
c <- rec
|
||||||
|
}()
|
||||||
|
fmt.Println("Testing", name, "...")
|
||||||
|
f(t)
|
||||||
|
c <- nil
|
||||||
|
}()
|
||||||
|
rec := <- c
|
||||||
|
if t.errors == nil && rec == nil {
|
||||||
|
fmt.Println("Success:", name)
|
||||||
|
} else {
|
||||||
|
fmt.Println("FAILED:", name, t.errors, rec)
|
||||||
|
}
|
||||||
|
}
|
164
lib/xdelta3/go/src/xdelta/test.go
Normal file
164
lib/xdelta3/go/src/xdelta/test.go
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
package xdelta
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
tmpDir = "/tmp"
|
||||||
|
srcSeq int64
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t *TestGroup) Drain(f io.ReadCloser, desc string) <-chan []byte {
|
||||||
|
c := make(chan []byte)
|
||||||
|
t.Go(desc, func(g *Goroutine) {
|
||||||
|
if b, err := ioutil.ReadAll(f); err != nil {
|
||||||
|
g.Panic(err)
|
||||||
|
} else {
|
||||||
|
c <- b
|
||||||
|
}
|
||||||
|
g.OK()
|
||||||
|
})
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TestGroup) Empty(f io.ReadCloser, desc string) *Goroutine {
|
||||||
|
return t.Go("empty:"+desc, func (g *Goroutine) {
|
||||||
|
s := bufio.NewScanner(f)
|
||||||
|
for s.Scan() {
|
||||||
|
os.Stderr.Write([]byte(fmt.Sprint(desc, ": ", s.Text(), "\n")))
|
||||||
|
}
|
||||||
|
err := s.Err()
|
||||||
|
f.Close()
|
||||||
|
if err != nil {
|
||||||
|
g.Panic(err)
|
||||||
|
}
|
||||||
|
g.OK()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TestGroup) TestWrite(what string, f io.WriteCloser, b []byte) *Goroutine {
|
||||||
|
return t.Go("write", func(g *Goroutine) {
|
||||||
|
if _, err := f.Write(b); err != nil {
|
||||||
|
g.Panic(err)
|
||||||
|
}
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
g.Panic(err)
|
||||||
|
}
|
||||||
|
g.OK()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TestGroup) CopyStreams(r io.ReadCloser, w io.WriteCloser, written *int64) *Goroutine {
|
||||||
|
return t.Go("copy", func(g *Goroutine) {
|
||||||
|
nwrite, err := io.Copy(w, r)
|
||||||
|
if err != nil {
|
||||||
|
g.Panic(err)
|
||||||
|
}
|
||||||
|
err = r.Close()
|
||||||
|
if err != nil {
|
||||||
|
g.Panic(err)
|
||||||
|
}
|
||||||
|
err = w.Close()
|
||||||
|
if err != nil {
|
||||||
|
g.Panic(err)
|
||||||
|
}
|
||||||
|
g.OK()
|
||||||
|
*written = nwrite
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TestGroup) CompareStreams(r1 io.ReadCloser, r2 io.ReadCloser, length int64) *Goroutine {
|
||||||
|
return t.Go("compare", func(g *Goroutine) {
|
||||||
|
b1 := make([]byte, blocksize)
|
||||||
|
b2 := make([]byte, blocksize)
|
||||||
|
var idx int64
|
||||||
|
for length > 0 {
|
||||||
|
c := blocksize
|
||||||
|
if length < blocksize {
|
||||||
|
c = int(length)
|
||||||
|
}
|
||||||
|
if _, err := io.ReadFull(r1, b1[0:c]); err != nil {
|
||||||
|
g.Panic(err)
|
||||||
|
}
|
||||||
|
if _, err := io.ReadFull(r2, b2[0:c]); err != nil {
|
||||||
|
g.Panic(err)
|
||||||
|
}
|
||||||
|
if bytes.Compare(b1[0:c], b2[0:c]) != 0 {
|
||||||
|
fmt.Println("B1 is", string(b1[0:c]))
|
||||||
|
fmt.Println("B2 is", string(b2[0:c]))
|
||||||
|
g.Panic(errors.New(fmt.Sprint("Bytes do not compare at ", idx)))
|
||||||
|
}
|
||||||
|
length -= int64(c)
|
||||||
|
idx += int64(c)
|
||||||
|
}
|
||||||
|
g.OK()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TestGroup) Exec(desc string, p Program, srcfifo bool, flags []string) (*Run, error) {
|
||||||
|
var err error
|
||||||
|
run := &Run{}
|
||||||
|
args := []string{p.Path}
|
||||||
|
if srcfifo {
|
||||||
|
num := atomic.AddInt64(&srcSeq, 1)
|
||||||
|
run.Srcfile = path.Join(t.Runner.Testdir, fmt.Sprint("source", num))
|
||||||
|
if err = unix.Mkfifo(run.Srcfile, 0600); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
read, write := io.Pipe()
|
||||||
|
t.writeFifo(run.Srcfile, read)
|
||||||
|
run.Srcin = write
|
||||||
|
args = append(args, "-s")
|
||||||
|
args = append(args, run.Srcfile)
|
||||||
|
}
|
||||||
|
if run.Stdin, err = run.Cmd.StdinPipe(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if run.Stdout, err = run.Cmd.StdoutPipe(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if run.Stderr, err = run.Cmd.StderrPipe(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
run.Cmd.Path = p.Path
|
||||||
|
run.Cmd.Args = append(args, flags...)
|
||||||
|
run.Cmd.Dir = t.Runner.Testdir
|
||||||
|
if serr := run.Cmd.Start(); serr != nil {
|
||||||
|
return nil, serr
|
||||||
|
}
|
||||||
|
return run, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TestGroup) Fail(v ...interface{}) {
|
||||||
|
panic(fmt.Sprintln(v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TestGroup) writeFifo(srcfile string, read io.Reader) *Goroutine {
|
||||||
|
return t.Go("compare", func(g *Goroutine) {
|
||||||
|
fifo, err := os.OpenFile(srcfile, os.O_WRONLY, 0600)
|
||||||
|
if err != nil {
|
||||||
|
fifo.Close()
|
||||||
|
g.Panic(err)
|
||||||
|
}
|
||||||
|
if _, err := io.Copy(fifo, read); err != nil {
|
||||||
|
fifo.Close()
|
||||||
|
g.Panic(err)
|
||||||
|
}
|
||||||
|
if err := fifo.Close(); err != nil {
|
||||||
|
g.Panic(err)
|
||||||
|
}
|
||||||
|
g.OK()
|
||||||
|
})
|
||||||
|
}
|
97
lib/xdelta3/go/src/xdelta/tgroup.go
Normal file
97
lib/xdelta3/go/src/xdelta/tgroup.go
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
package xdelta
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestGroup struct {
|
||||||
|
*Runner
|
||||||
|
main *Goroutine
|
||||||
|
sync.Mutex
|
||||||
|
sync.WaitGroup
|
||||||
|
running []*Goroutine
|
||||||
|
errors []error
|
||||||
|
nonerrors []error // For tolerated / expected conditions
|
||||||
|
}
|
||||||
|
|
||||||
|
type Goroutine struct {
|
||||||
|
*TestGroup
|
||||||
|
name string
|
||||||
|
done bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Goroutine) String() string {
|
||||||
|
return fmt.Sprint("[", g.name, "]")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Goroutine) finish(err error) {
|
||||||
|
wait := false
|
||||||
|
tg := g.TestGroup
|
||||||
|
sbuf := make([]byte, 4096)
|
||||||
|
sbuf = sbuf[0:runtime.Stack(sbuf, false)]
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("%v:%v:%v", g.name, err, string(sbuf))
|
||||||
|
}
|
||||||
|
tg.Lock()
|
||||||
|
if g.done {
|
||||||
|
if err != nil {
|
||||||
|
tg.nonerrors = append(tg.nonerrors, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wait = true
|
||||||
|
g.done = true
|
||||||
|
if err != nil {
|
||||||
|
tg.errors = append(tg.errors, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tg.Unlock()
|
||||||
|
if wait {
|
||||||
|
tg.WaitGroup.Done()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Goroutine) OK() {
|
||||||
|
g.finish(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Goroutine) Panic(err error) {
|
||||||
|
g.finish(err)
|
||||||
|
if g != g.TestGroup.main {
|
||||||
|
runtime.Goexit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TestGroup) Main() *Goroutine { return t.main }
|
||||||
|
|
||||||
|
func (t *TestGroup) Panic(err error) { t.Main().Panic(err) }
|
||||||
|
|
||||||
|
func (t *TestGroup) Go(name string, f func(*Goroutine)) *Goroutine {
|
||||||
|
g := &Goroutine{t, name, false}
|
||||||
|
t.Lock()
|
||||||
|
t.WaitGroup.Add(1)
|
||||||
|
t.running = append(t.running, g)
|
||||||
|
t.Unlock()
|
||||||
|
go f(g)
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TestGroup) Wait(procs... *Run) {
|
||||||
|
t.Main().OK()
|
||||||
|
t.WaitGroup.Wait()
|
||||||
|
for _, p := range procs {
|
||||||
|
if err := p.Wait(); err != nil {
|
||||||
|
t.errors = append(t.errors, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, err := range t.errors {
|
||||||
|
fmt.Println(":ERROR:", err)
|
||||||
|
}
|
||||||
|
for _, err := range t.nonerrors {
|
||||||
|
fmt.Println("(ERROR)", err)
|
||||||
|
}
|
||||||
|
if len(t.errors) != 0 {
|
||||||
|
t.Fail("Test failed with", len(t.errors), "errors")
|
||||||
|
}
|
||||||
|
}
|
42
lib/xdelta3/linkxd3lib.c
Normal file
42
lib/xdelta3/linkxd3lib.c
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include "xdelta3.h"
|
||||||
|
|
||||||
|
extern int VVV;
|
||||||
|
|
||||||
|
int VVV;
|
||||||
|
|
||||||
|
void use(int r)
|
||||||
|
{
|
||||||
|
VVV = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
xd3_config config;
|
||||||
|
xd3_stream stream;
|
||||||
|
xd3_source source;
|
||||||
|
|
||||||
|
xd3_init_config (& config, 0);
|
||||||
|
use (xd3_config_stream (&stream, &config));
|
||||||
|
use (xd3_close_stream (&stream));
|
||||||
|
xd3_abort_stream (&stream);
|
||||||
|
xd3_free_stream (&stream);
|
||||||
|
|
||||||
|
xd3_avail_input (& stream, NULL, 0);
|
||||||
|
xd3_consume_output (& stream);
|
||||||
|
|
||||||
|
use (xd3_set_source (& stream, & source));
|
||||||
|
xd3_set_flags (& stream, 0);
|
||||||
|
|
||||||
|
use (xd3_decode_stream (& stream, NULL, 0, NULL, NULL, 0));
|
||||||
|
use (xd3_decode_input (&stream));
|
||||||
|
use (xd3_get_appheader (& stream, NULL, NULL));
|
||||||
|
|
||||||
|
#if XD3_ENCODER
|
||||||
|
use (xd3_encode_input (&stream));
|
||||||
|
use (xd3_encode_stream (& stream, NULL, 0, NULL, NULL, 0));
|
||||||
|
use (xd3_set_appheader (& stream));
|
||||||
|
use (xd3_encoder_used_source (& stream));
|
||||||
|
use (xd3_encoder_srcbase (& stream));
|
||||||
|
use (xd3_encoder_srclen (& stream));
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
84
lib/xdelta3/m4/ax_check_aligned_access_required.m4
Normal file
84
lib/xdelta3/m4/ax_check_aligned_access_required.m4
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
# ====================================================================================
|
||||||
|
# http://www.gnu.org/software/autoconf-archive/ax_check_aligned_access_required.html
|
||||||
|
# ====================================================================================
|
||||||
|
#
|
||||||
|
# SYNOPSIS
|
||||||
|
#
|
||||||
|
# AC_CHECK_ALIGNED_ACCESS_REQUIRED
|
||||||
|
#
|
||||||
|
# DESCRIPTION
|
||||||
|
#
|
||||||
|
# While the x86 CPUs allow access to memory objects to be unaligned it
|
||||||
|
# happens that most of the modern designs require objects to be aligned -
|
||||||
|
# or they will fail with a buserror. That mode is quite known by
|
||||||
|
# big-endian machines (sparc, etc) however the alpha cpu is little-
|
||||||
|
# endian.
|
||||||
|
#
|
||||||
|
# The following function will test for aligned access to be required and
|
||||||
|
# set a config.h define HAVE_ALIGNED_ACCESS_REQUIRED (name derived by
|
||||||
|
# standard usage). Structures loaded from a file (or mmapped to memory)
|
||||||
|
# should be accessed per-byte in that case to avoid segfault type errors.
|
||||||
|
#
|
||||||
|
# LICENSE
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
# Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||||
|
# gives unlimited permission to copy, distribute and modify the configure
|
||||||
|
# scripts that are the output of Autoconf when processing the Macro. You
|
||||||
|
# need not follow the terms of the GNU General Public License when using
|
||||||
|
# or distributing such scripts, even though portions of the text of the
|
||||||
|
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||||
|
# all other use of the material that constitutes the Autoconf Macro.
|
||||||
|
#
|
||||||
|
# This special exception to the GPL applies to versions of the Autoconf
|
||||||
|
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||||
|
# modified version of the Autoconf Macro, you may extend this special
|
||||||
|
# exception to the GPL to apply to your modified version as well.
|
||||||
|
|
||||||
|
#serial 7
|
||||||
|
|
||||||
|
AC_DEFUN([AX_CHECK_ALIGNED_ACCESS_REQUIRED],
|
||||||
|
[AC_CACHE_CHECK([if pointers to integers require aligned access],
|
||||||
|
[ax_cv_have_aligned_access_required],
|
||||||
|
[AC_TRY_RUN([
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
char* string = malloc(40);
|
||||||
|
int i;
|
||||||
|
for (i=0; i < 40; i++) string[[i]] = i;
|
||||||
|
{
|
||||||
|
void* s = string;
|
||||||
|
int* p = s+1;
|
||||||
|
int* q = s+2;
|
||||||
|
|
||||||
|
if (*p == *q) { return 1; }
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[ax_cv_have_aligned_access_required=yes],
|
||||||
|
[ax_cv_have_aligned_access_required=no],
|
||||||
|
[ax_cv_have_aligned_access_required=no])
|
||||||
|
])
|
||||||
|
if test "$ax_cv_have_aligned_access_required" = yes ; then
|
||||||
|
AC_DEFINE([HAVE_ALIGNED_ACCESS_REQUIRED], [1],
|
||||||
|
[Define if pointers to integers require aligned access])
|
||||||
|
fi
|
||||||
|
])
|
135
lib/xdelta3/m4/ax_pkg_swig.m4
Normal file
135
lib/xdelta3/m4/ax_pkg_swig.m4
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
# ===========================================================================
|
||||||
|
# http://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html
|
||||||
|
# ===========================================================================
|
||||||
|
#
|
||||||
|
# SYNOPSIS
|
||||||
|
#
|
||||||
|
# AX_PKG_SWIG([major.minor.micro], [action-if-found], [action-if-not-found])
|
||||||
|
#
|
||||||
|
# DESCRIPTION
|
||||||
|
#
|
||||||
|
# This macro searches for a SWIG installation on your system. If found,
|
||||||
|
# then SWIG is AC_SUBST'd; if not found, then $SWIG is empty. If SWIG is
|
||||||
|
# found, then SWIG_LIB is set to the SWIG library path, and AC_SUBST'd.
|
||||||
|
#
|
||||||
|
# You can use the optional first argument to check if the version of the
|
||||||
|
# available SWIG is greater than or equal to the value of the argument. It
|
||||||
|
# should have the format: N[.N[.N]] (N is a number between 0 and 999. Only
|
||||||
|
# the first N is mandatory.) If the version argument is given (e.g.
|
||||||
|
# 1.3.17), AX_PKG_SWIG checks that the swig package is this version number
|
||||||
|
# or higher.
|
||||||
|
#
|
||||||
|
# As usual, action-if-found is executed if SWIG is found, otherwise
|
||||||
|
# action-if-not-found is executed.
|
||||||
|
#
|
||||||
|
# In configure.in, use as:
|
||||||
|
#
|
||||||
|
# AX_PKG_SWIG(1.3.17, [], [ AC_MSG_ERROR([SWIG is required to build..]) ])
|
||||||
|
# AX_SWIG_ENABLE_CXX
|
||||||
|
# AX_SWIG_MULTI_MODULE_SUPPORT
|
||||||
|
# AX_SWIG_PYTHON
|
||||||
|
#
|
||||||
|
# LICENSE
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
|
||||||
|
# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
|
||||||
|
# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
|
||||||
|
# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
|
||||||
|
# Copyright (c) 2011 Murray Cumming <murrayc@openismus.com>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
# Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||||
|
# gives unlimited permission to copy, distribute and modify the configure
|
||||||
|
# scripts that are the output of Autoconf when processing the Macro. You
|
||||||
|
# need not follow the terms of the GNU General Public License when using
|
||||||
|
# or distributing such scripts, even though portions of the text of the
|
||||||
|
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||||
|
# all other use of the material that constitutes the Autoconf Macro.
|
||||||
|
#
|
||||||
|
# This special exception to the GPL applies to versions of the Autoconf
|
||||||
|
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||||
|
# modified version of the Autoconf Macro, you may extend this special
|
||||||
|
# exception to the GPL to apply to your modified version as well.
|
||||||
|
|
||||||
|
#serial 8
|
||||||
|
|
||||||
|
AC_DEFUN([AX_PKG_SWIG],[
|
||||||
|
# Ubuntu has swig 2.0 as /usr/bin/swig2.0
|
||||||
|
AC_PATH_PROGS([SWIG],[swig swig2.0])
|
||||||
|
if test -z "$SWIG" ; then
|
||||||
|
m4_ifval([$3],[$3],[:])
|
||||||
|
elif test -n "$1" ; then
|
||||||
|
AC_MSG_CHECKING([SWIG version])
|
||||||
|
[swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`]
|
||||||
|
AC_MSG_RESULT([$swig_version])
|
||||||
|
if test -n "$swig_version" ; then
|
||||||
|
# Calculate the required version number components
|
||||||
|
[required=$1]
|
||||||
|
[required_major=`echo $required | sed 's/[^0-9].*//'`]
|
||||||
|
if test -z "$required_major" ; then
|
||||||
|
[required_major=0]
|
||||||
|
fi
|
||||||
|
[required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
|
||||||
|
[required_minor=`echo $required | sed 's/[^0-9].*//'`]
|
||||||
|
if test -z "$required_minor" ; then
|
||||||
|
[required_minor=0]
|
||||||
|
fi
|
||||||
|
[required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
|
||||||
|
[required_patch=`echo $required | sed 's/[^0-9].*//'`]
|
||||||
|
if test -z "$required_patch" ; then
|
||||||
|
[required_patch=0]
|
||||||
|
fi
|
||||||
|
# Calculate the available version number components
|
||||||
|
[available=$swig_version]
|
||||||
|
[available_major=`echo $available | sed 's/[^0-9].*//'`]
|
||||||
|
if test -z "$available_major" ; then
|
||||||
|
[available_major=0]
|
||||||
|
fi
|
||||||
|
[available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
|
||||||
|
[available_minor=`echo $available | sed 's/[^0-9].*//'`]
|
||||||
|
if test -z "$available_minor" ; then
|
||||||
|
[available_minor=0]
|
||||||
|
fi
|
||||||
|
[available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
|
||||||
|
[available_patch=`echo $available | sed 's/[^0-9].*//'`]
|
||||||
|
if test -z "$available_patch" ; then
|
||||||
|
[available_patch=0]
|
||||||
|
fi
|
||||||
|
# Convert the version tuple into a single number for easier comparison.
|
||||||
|
# Using base 100 should be safe since SWIG internally uses BCD values
|
||||||
|
# to encode its version number.
|
||||||
|
required_swig_vernum=`expr $required_major \* 10000 \
|
||||||
|
\+ $required_minor \* 100 \+ $required_patch`
|
||||||
|
available_swig_vernum=`expr $available_major \* 10000 \
|
||||||
|
\+ $available_minor \* 100 \+ $available_patch`
|
||||||
|
|
||||||
|
if test $available_swig_vernum -lt $required_swig_vernum; then
|
||||||
|
AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version.])
|
||||||
|
SWIG=''
|
||||||
|
m4_ifval([$3],[$3],[])
|
||||||
|
else
|
||||||
|
AC_MSG_CHECKING([for SWIG library])
|
||||||
|
SWIG_LIB=`$SWIG -swiglib`
|
||||||
|
AC_MSG_RESULT([$SWIG_LIB])
|
||||||
|
m4_ifval([$2],[$2],[])
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AC_MSG_WARN([cannot determine SWIG version])
|
||||||
|
SWIG=''
|
||||||
|
m4_ifval([$3],[$3],[])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AC_SUBST([SWIG_LIB])
|
||||||
|
])
|
325
lib/xdelta3/m4/ax_python_devel.m4
Normal file
325
lib/xdelta3/m4/ax_python_devel.m4
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
# ===========================================================================
|
||||||
|
# http://www.gnu.org/software/autoconf-archive/ax_python_devel.html
|
||||||
|
# ===========================================================================
|
||||||
|
#
|
||||||
|
# SYNOPSIS
|
||||||
|
#
|
||||||
|
# AX_PYTHON_DEVEL([version])
|
||||||
|
#
|
||||||
|
# DESCRIPTION
|
||||||
|
#
|
||||||
|
# Note: Defines as a precious variable "PYTHON_VERSION". Don't override it
|
||||||
|
# in your configure.ac.
|
||||||
|
#
|
||||||
|
# This macro checks for Python and tries to get the include path to
|
||||||
|
# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LDFLAGS)
|
||||||
|
# output variables. It also exports $(PYTHON_EXTRA_LIBS) and
|
||||||
|
# $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code.
|
||||||
|
#
|
||||||
|
# You can search for some particular version of Python by passing a
|
||||||
|
# parameter to this macro, for example ">= '2.3.1'", or "== '2.4'". Please
|
||||||
|
# note that you *have* to pass also an operator along with the version to
|
||||||
|
# match, and pay special attention to the single quotes surrounding the
|
||||||
|
# version number. Don't use "PYTHON_VERSION" for this: that environment
|
||||||
|
# variable is declared as precious and thus reserved for the end-user.
|
||||||
|
#
|
||||||
|
# This macro should work for all versions of Python >= 2.1.0. As an end
|
||||||
|
# user, you can disable the check for the python version by setting the
|
||||||
|
# PYTHON_NOVERSIONCHECK environment variable to something else than the
|
||||||
|
# empty string.
|
||||||
|
#
|
||||||
|
# If you need to use this macro for an older Python version, please
|
||||||
|
# contact the authors. We're always open for feedback.
|
||||||
|
#
|
||||||
|
# LICENSE
|
||||||
|
#
|
||||||
|
# Copyright (c) 2009 Sebastian Huber <sebastian-huber@web.de>
|
||||||
|
# Copyright (c) 2009 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
|
||||||
|
# Copyright (c) 2009 Rafael Laboissiere <rafael@laboissiere.net>
|
||||||
|
# Copyright (c) 2009 Andrew Collier <colliera@ukzn.ac.za>
|
||||||
|
# Copyright (c) 2009 Matteo Settenvini <matteo@member.fsf.org>
|
||||||
|
# Copyright (c) 2009 Horst Knorr <hk_classes@knoda.org>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU General Public License as published by the
|
||||||
|
# Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
# Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||||
|
# gives unlimited permission to copy, distribute and modify the configure
|
||||||
|
# scripts that are the output of Autoconf when processing the Macro. You
|
||||||
|
# need not follow the terms of the GNU General Public License when using
|
||||||
|
# or distributing such scripts, even though portions of the text of the
|
||||||
|
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||||
|
# all other use of the material that constitutes the Autoconf Macro.
|
||||||
|
#
|
||||||
|
# This special exception to the GPL applies to versions of the Autoconf
|
||||||
|
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||||
|
# modified version of the Autoconf Macro, you may extend this special
|
||||||
|
# exception to the GPL to apply to your modified version as well.
|
||||||
|
|
||||||
|
#serial 8
|
||||||
|
|
||||||
|
AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
|
||||||
|
AC_DEFUN([AX_PYTHON_DEVEL],[
|
||||||
|
#
|
||||||
|
# Allow the use of a (user set) custom python version
|
||||||
|
#
|
||||||
|
AC_ARG_VAR([PYTHON_VERSION],[The installed Python
|
||||||
|
version to use, for example '2.3'. This string
|
||||||
|
will be appended to the Python interpreter
|
||||||
|
canonical name.])
|
||||||
|
|
||||||
|
AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
|
||||||
|
if test -z "$PYTHON"; then
|
||||||
|
AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path])
|
||||||
|
PYTHON_VERSION=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check for a version of Python >= 2.1.0
|
||||||
|
#
|
||||||
|
AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
|
||||||
|
ac_supports_python_ver=`$PYTHON -c "import sys; \
|
||||||
|
ver = sys.version.split ()[[0]]; \
|
||||||
|
print (ver >= '2.1.0')"`
|
||||||
|
if test "$ac_supports_python_ver" != "True"; then
|
||||||
|
if test -z "$PYTHON_NOVERSIONCHECK"; then
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
AC_MSG_FAILURE([
|
||||||
|
This version of the AC@&t@_PYTHON_DEVEL macro
|
||||||
|
doesn't work properly with versions of Python before
|
||||||
|
2.1.0. You may need to re-run configure, setting the
|
||||||
|
variables PYTHON_CPPFLAGS, PYTHON_LDFLAGS, PYTHON_SITE_PKG,
|
||||||
|
PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
|
||||||
|
Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
|
||||||
|
to something else than an empty string.
|
||||||
|
])
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([skip at user request])
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# if the macro parameter ``version'' is set, honour it
|
||||||
|
#
|
||||||
|
if test -n "$1"; then
|
||||||
|
AC_MSG_CHECKING([for a version of Python $1])
|
||||||
|
ac_supports_python_ver=`$PYTHON -c "import sys; \
|
||||||
|
ver = sys.version.split ()[[0]]; \
|
||||||
|
print (ver $1)"`
|
||||||
|
if test "$ac_supports_python_ver" = "True"; then
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
AC_MSG_ERROR([this package requires Python $1.
|
||||||
|
If you have it installed, but it isn't the default Python
|
||||||
|
interpreter in your system path, please pass the PYTHON_VERSION
|
||||||
|
variable to configure. See ``configure --help'' for reference.
|
||||||
|
])
|
||||||
|
PYTHON_VERSION=""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check if you have distutils, else fail
|
||||||
|
#
|
||||||
|
AC_MSG_CHECKING([for the distutils Python package])
|
||||||
|
ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
|
||||||
|
if test -z "$ac_distutils_result"; then
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
AC_MSG_ERROR([cannot import Python module "distutils".
|
||||||
|
Please check your Python installation. The error was:
|
||||||
|
$ac_distutils_result])
|
||||||
|
PYTHON_VERSION=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check for Python include path
|
||||||
|
#
|
||||||
|
AC_MSG_CHECKING([for Python include path])
|
||||||
|
if test -z "$PYTHON_CPPFLAGS"; then
|
||||||
|
python_path=`$PYTHON -c "import distutils.sysconfig; \
|
||||||
|
print (distutils.sysconfig.get_python_inc ());"`
|
||||||
|
if test -n "${python_path}"; then
|
||||||
|
python_path="-I$python_path"
|
||||||
|
fi
|
||||||
|
PYTHON_CPPFLAGS=$python_path
|
||||||
|
fi
|
||||||
|
AC_MSG_RESULT([$PYTHON_CPPFLAGS])
|
||||||
|
AC_SUBST([PYTHON_CPPFLAGS])
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check for Python library path
|
||||||
|
#
|
||||||
|
AC_MSG_CHECKING([for Python library path])
|
||||||
|
if test -z "$PYTHON_LDFLAGS"; then
|
||||||
|
# (makes two attempts to ensure we've got a version number
|
||||||
|
# from the interpreter)
|
||||||
|
ac_python_version=`cat<<EOD | $PYTHON -
|
||||||
|
|
||||||
|
# join all versioning strings, on some systems
|
||||||
|
# major/minor numbers could be in different list elements
|
||||||
|
from distutils.sysconfig import *
|
||||||
|
ret = ''
|
||||||
|
for e in get_config_vars ('VERSION'):
|
||||||
|
if (e != None):
|
||||||
|
ret += e
|
||||||
|
print (ret)
|
||||||
|
EOD`
|
||||||
|
|
||||||
|
if test -z "$ac_python_version"; then
|
||||||
|
if test -n "$PYTHON_VERSION"; then
|
||||||
|
ac_python_version=$PYTHON_VERSION
|
||||||
|
else
|
||||||
|
ac_python_version=`$PYTHON -c "import sys; \
|
||||||
|
print (sys.version[[:3]])"`
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make the versioning information available to the compiler
|
||||||
|
AC_DEFINE_UNQUOTED([HAVE_PYTHON], ["$ac_python_version"],
|
||||||
|
[If available, contains the Python version number currently in use.])
|
||||||
|
|
||||||
|
# First, the library directory:
|
||||||
|
ac_python_libdir=`cat<<EOD | $PYTHON -
|
||||||
|
|
||||||
|
# There should be only one
|
||||||
|
import distutils.sysconfig
|
||||||
|
for e in distutils.sysconfig.get_config_vars ('LIBDIR'):
|
||||||
|
if e != None:
|
||||||
|
print (e)
|
||||||
|
break
|
||||||
|
EOD`
|
||||||
|
|
||||||
|
# Before checking for libpythonX.Y, we need to know
|
||||||
|
# the extension the OS we're on uses for libraries
|
||||||
|
# (we take the first one, if there's more than one fix me!):
|
||||||
|
ac_python_soext=`$PYTHON -c \
|
||||||
|
"import distutils.sysconfig; \
|
||||||
|
print (distutils.sysconfig.get_config_vars('SO')[[0]])"`
|
||||||
|
|
||||||
|
# Now, for the library:
|
||||||
|
ac_python_soname=`$PYTHON -c \
|
||||||
|
"import distutils.sysconfig; \
|
||||||
|
print (distutils.sysconfig.get_config_vars('LDLIBRARY')[[0]])"`
|
||||||
|
|
||||||
|
# Strip away extension from the end to canonicalize its name:
|
||||||
|
ac_python_library=`echo "$ac_python_soname" | sed "s/${ac_python_soext}$//"`
|
||||||
|
|
||||||
|
# This small piece shamelessly adapted from PostgreSQL python macro;
|
||||||
|
# credits goes to momjian, I think. I'd like to put the right name
|
||||||
|
# in the credits, if someone can point me in the right direction... ?
|
||||||
|
#
|
||||||
|
if test -n "$ac_python_libdir" -a -n "$ac_python_library" \
|
||||||
|
-a x"$ac_python_library" != x"$ac_python_soname"
|
||||||
|
then
|
||||||
|
# use the official shared library
|
||||||
|
ac_python_library=`echo "$ac_python_library" | sed "s/^lib//"`
|
||||||
|
PYTHON_LDFLAGS="-L$ac_python_libdir -l$ac_python_library"
|
||||||
|
else
|
||||||
|
# old way: use libpython from python_configdir
|
||||||
|
ac_python_libdir=`$PYTHON -c \
|
||||||
|
"from distutils.sysconfig import get_python_lib as f; \
|
||||||
|
import os; \
|
||||||
|
print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"`
|
||||||
|
PYTHON_LDFLAGS="-L$ac_python_libdir -lpython$ac_python_version"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "PYTHON_LDFLAGS"; then
|
||||||
|
AC_MSG_ERROR([
|
||||||
|
Cannot determine location of your Python DSO. Please check it was installed with
|
||||||
|
dynamic libraries enabled, or try setting PYTHON_LDFLAGS by hand.
|
||||||
|
])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AC_MSG_RESULT([$PYTHON_LDFLAGS])
|
||||||
|
AC_SUBST([PYTHON_LDFLAGS])
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check for site packages
|
||||||
|
#
|
||||||
|
AC_MSG_CHECKING([for Python site-packages path])
|
||||||
|
if test -z "$PYTHON_SITE_PKG"; then
|
||||||
|
PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \
|
||||||
|
print (distutils.sysconfig.get_python_lib(0,0));"`
|
||||||
|
fi
|
||||||
|
AC_MSG_RESULT([$PYTHON_SITE_PKG])
|
||||||
|
AC_SUBST([PYTHON_SITE_PKG])
|
||||||
|
|
||||||
|
#
|
||||||
|
# libraries which must be linked in when embedding
|
||||||
|
#
|
||||||
|
AC_MSG_CHECKING(python extra libraries)
|
||||||
|
if test -z "$PYTHON_EXTRA_LIBS"; then
|
||||||
|
PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \
|
||||||
|
conf = distutils.sysconfig.get_config_var; \
|
||||||
|
print (conf('LOCALMODLIBS') + ' ' + conf('LIBS'))"`
|
||||||
|
fi
|
||||||
|
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
|
||||||
|
AC_SUBST(PYTHON_EXTRA_LIBS)
|
||||||
|
|
||||||
|
#
|
||||||
|
# linking flags needed when embedding
|
||||||
|
#
|
||||||
|
AC_MSG_CHECKING(python extra linking flags)
|
||||||
|
if test -z "$PYTHON_EXTRA_LDFLAGS"; then
|
||||||
|
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \
|
||||||
|
conf = distutils.sysconfig.get_config_var; \
|
||||||
|
print (conf('LINKFORSHARED'))"`
|
||||||
|
fi
|
||||||
|
AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
|
||||||
|
AC_SUBST(PYTHON_EXTRA_LDFLAGS)
|
||||||
|
|
||||||
|
#
|
||||||
|
# final check to see if everything compiles alright
|
||||||
|
#
|
||||||
|
AC_MSG_CHECKING([consistency of all components of python development environment])
|
||||||
|
# save current global flags
|
||||||
|
ac_save_LIBS="$LIBS"
|
||||||
|
ac_save_CPPFLAGS="$CPPFLAGS"
|
||||||
|
LIBS="$ac_save_LIBS $PYTHON_LDFLAGS $PYTHON_EXTRA_LDFLAGS $PYTHON_EXTRA_LIBS"
|
||||||
|
CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
|
||||||
|
AC_LANG_PUSH([C])
|
||||||
|
AC_LINK_IFELSE([
|
||||||
|
AC_LANG_PROGRAM([[#include <Python.h>]],
|
||||||
|
[[Py_Initialize();]])
|
||||||
|
],[pythonexists=yes],[pythonexists=no])
|
||||||
|
AC_LANG_POP([C])
|
||||||
|
# turn back to default flags
|
||||||
|
CPPFLAGS="$ac_save_CPPFLAGS"
|
||||||
|
LIBS="$ac_save_LIBS"
|
||||||
|
|
||||||
|
AC_MSG_RESULT([$pythonexists])
|
||||||
|
|
||||||
|
if test ! "x$pythonexists" = "xyes"; then
|
||||||
|
AC_MSG_FAILURE([
|
||||||
|
Could not link test program to Python. Maybe the main Python library has been
|
||||||
|
installed in some non-standard library path. If so, pass it to configure,
|
||||||
|
via the LDFLAGS environment variable.
|
||||||
|
Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib"
|
||||||
|
============================================================================
|
||||||
|
ERROR!
|
||||||
|
You probably have to install the development version of the Python package
|
||||||
|
for your distribution. The exact name of this package varies among them.
|
||||||
|
============================================================================
|
||||||
|
])
|
||||||
|
PYTHON_VERSION=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# all done!
|
||||||
|
#
|
||||||
|
])
|
64
lib/xdelta3/m4/ax_swig_python.m4
Normal file
64
lib/xdelta3/m4/ax_swig_python.m4
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
# ===========================================================================
|
||||||
|
# http://www.gnu.org/software/autoconf-archive/ax_swig_python.html
|
||||||
|
# ===========================================================================
|
||||||
|
#
|
||||||
|
# SYNOPSIS
|
||||||
|
#
|
||||||
|
# AX_SWIG_PYTHON([use-shadow-classes = {no, yes}])
|
||||||
|
#
|
||||||
|
# DESCRIPTION
|
||||||
|
#
|
||||||
|
# Checks for Python and provides the $(AX_SWIG_PYTHON_CPPFLAGS), and
|
||||||
|
# $(AX_SWIG_PYTHON_OPT) output variables.
|
||||||
|
#
|
||||||
|
# $(AX_SWIG_PYTHON_OPT) contains all necessary SWIG options to generate
|
||||||
|
# code for Python. Shadow classes are enabled unless the value of the
|
||||||
|
# optional first argument is exactly 'no'. If you need multi module
|
||||||
|
# support (provided by the AX_SWIG_MULTI_MODULE_SUPPORT macro) use
|
||||||
|
# $(AX_SWIG_PYTHON_LIBS) to link against the appropriate library. It
|
||||||
|
# contains the SWIG Python runtime library that is needed by the type
|
||||||
|
# check system for example.
|
||||||
|
#
|
||||||
|
# LICENSE
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
|
||||||
|
# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
|
||||||
|
# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
|
||||||
|
# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
# Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||||
|
# gives unlimited permission to copy, distribute and modify the configure
|
||||||
|
# scripts that are the output of Autoconf when processing the Macro. You
|
||||||
|
# need not follow the terms of the GNU General Public License when using
|
||||||
|
# or distributing such scripts, even though portions of the text of the
|
||||||
|
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||||
|
# all other use of the material that constitutes the Autoconf Macro.
|
||||||
|
#
|
||||||
|
# This special exception to the GPL applies to versions of the Autoconf
|
||||||
|
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||||
|
# modified version of the Autoconf Macro, you may extend this special
|
||||||
|
# exception to the GPL to apply to your modified version as well.
|
||||||
|
|
||||||
|
#serial 7
|
||||||
|
|
||||||
|
AU_ALIAS([SWIG_PYTHON], [AX_SWIG_PYTHON])
|
||||||
|
AC_DEFUN([AX_SWIG_PYTHON],[
|
||||||
|
AC_REQUIRE([AX_PKG_SWIG])
|
||||||
|
AC_REQUIRE([AX_PYTHON_DEVEL])
|
||||||
|
test "x$1" != "xno" || swig_shadow=" -noproxy"
|
||||||
|
AC_SUBST([AX_SWIG_PYTHON_OPT],[-python$swig_shadow])
|
||||||
|
AC_SUBST([AX_SWIG_PYTHON_CPPFLAGS],[$PYTHON_CPPFLAGS])
|
||||||
|
])
|
25
lib/xdelta3/plot.sh
Normal file
25
lib/xdelta3/plot.sh
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
G=/usr/bin/gnuplot
|
||||||
|
|
||||||
|
D=./output_dir
|
||||||
|
|
||||||
|
I=$1
|
||||||
|
O=$D/$2
|
||||||
|
|
||||||
|
$G > $O <<EOF
|
||||||
|
|
||||||
|
#set terminal jpeg
|
||||||
|
set terminal png
|
||||||
|
|
||||||
|
f(x) = 1331000 + 30000 * (1 / (x - 2.45))
|
||||||
|
|
||||||
|
# plot [x=1:10] [1:10] f(x)
|
||||||
|
# plot sin(x), cos(x)
|
||||||
|
# , f(x)
|
||||||
|
|
||||||
|
plot "$I" using 1:2
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
mv "$I" "$D"
|
1861
lib/xdelta3/rcs_junk.cc
Normal file
1861
lib/xdelta3/rcs_junk.cc
Normal file
File diff suppressed because it is too large
Load diff
288
lib/xdelta3/run_release.sh
Normal file
288
lib/xdelta3/run_release.sh
Normal file
|
@ -0,0 +1,288 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Run from the source dir.
|
||||||
|
SRCDIR=${PWD}
|
||||||
|
|
||||||
|
# TODO replace w/ wget
|
||||||
|
LZMA="xz-5.2.1"
|
||||||
|
LZMA_FILE="${SRCDIR}/../${LZMA}.tar.gz"
|
||||||
|
|
||||||
|
MAKEFLAGS="-j 10"
|
||||||
|
|
||||||
|
BUILDDIR=${SRCDIR}/build
|
||||||
|
LZMASRC=${BUILDDIR}/${LZMA}
|
||||||
|
|
||||||
|
NONWIN_CFLAGS=""
|
||||||
|
MINGW_CFLAGS="-DEXTERNAL_COMPRESSION=0 -DXD3_WIN32=1 -DSHELL_TESTS=0"
|
||||||
|
|
||||||
|
MYOS=`uname`
|
||||||
|
DATE=`date`
|
||||||
|
|
||||||
|
CLEAN=""
|
||||||
|
|
||||||
|
LINUXTGTS=""
|
||||||
|
LINUXTEST1=""
|
||||||
|
LINUXTEST2=""
|
||||||
|
|
||||||
|
WINTGTS=""
|
||||||
|
WINTEST1=""
|
||||||
|
WINTEST2=""
|
||||||
|
|
||||||
|
OSXTGTS=""
|
||||||
|
OSXTEST1=""
|
||||||
|
OSXTEST2=""
|
||||||
|
|
||||||
|
XTMP="/tmp"
|
||||||
|
if [ "${TMP}" != "" ]; then
|
||||||
|
XTMP="${TMP}"
|
||||||
|
fi
|
||||||
|
if [ "${TMPDIR}" != "" ]; then
|
||||||
|
XTMP="${TMPDIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
BUILDFILES=`ls -A ${BUILDDIR} 2> /dev/null`
|
||||||
|
if [ -d "${BUILDDIR}" ]; then
|
||||||
|
if [ -n "${BUILDFILES}" ]; then
|
||||||
|
echo "Directory ${BUILDDIR} should be empty"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
mkdir "${BUILDDIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
function setup {
|
||||||
|
libtoolize || glibtoolize
|
||||||
|
automake --add-missing
|
||||||
|
aclocal -I m4
|
||||||
|
autoheader
|
||||||
|
automake
|
||||||
|
autoconf
|
||||||
|
}
|
||||||
|
|
||||||
|
function try {
|
||||||
|
local w=$1
|
||||||
|
shift
|
||||||
|
local dir=$1
|
||||||
|
shift
|
||||||
|
echo -n " ${w} ... "
|
||||||
|
(cd "${dir}" && "$@" >${w}.stdout 2>${w}.stderr)
|
||||||
|
local s=$?
|
||||||
|
if [ ${s} -eq 0 ]; then
|
||||||
|
echo " success"
|
||||||
|
else
|
||||||
|
echo " failed!"
|
||||||
|
echo "Error $1 in ${dir}" >&2
|
||||||
|
fi
|
||||||
|
return ${s}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildlzma {
|
||||||
|
host=$1
|
||||||
|
march=$2
|
||||||
|
local target="${BUILDDIR}/lib-${host}${march}"
|
||||||
|
|
||||||
|
echo " ... liblzma"
|
||||||
|
|
||||||
|
mkdir -p ${target}
|
||||||
|
|
||||||
|
try configure-lzma ${target} ${LZMASRC}/configure \
|
||||||
|
--host=${host} \
|
||||||
|
--prefix=${target} \
|
||||||
|
--disable-shared \
|
||||||
|
"CC=${CC}" \
|
||||||
|
"CXX=${CXX}" \
|
||||||
|
"CFLAGS=${march}" \
|
||||||
|
"CXXFLAGS=${march}" \
|
||||||
|
"LDFLAGS=${march}"
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
try build-lzma ${target} make ${MAKEFLAGS}
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
try install-lzma ${target} make install
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildit {
|
||||||
|
local host=$1
|
||||||
|
local march=$2
|
||||||
|
local usizebits=$3
|
||||||
|
local offsetbits=$4
|
||||||
|
local cargs=$5
|
||||||
|
local afl=$6
|
||||||
|
local BM="${host}${march}"
|
||||||
|
local USECC="${CC}"
|
||||||
|
local USECXX="${CXX}"
|
||||||
|
local LIBBM="${BM}"
|
||||||
|
|
||||||
|
if [ "${afl}" = "1" ]; then
|
||||||
|
USECC="afl-gcc"
|
||||||
|
USECXX="afl-g++"
|
||||||
|
BM="${BM}-afl"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local D="build/${BM}/usize${usizebits}/xoff${offsetbits}"
|
||||||
|
local BMD="${BM}-${usizebits}-${offsetbits}"
|
||||||
|
|
||||||
|
local FULLD="${SRCDIR}/${D}"
|
||||||
|
local CFLAGS="${march} ${cargs} -I${SRCDIR}/build/lib-${LIBBM}/include"
|
||||||
|
local CXXFLAGS="${march} ${cargs} -I${SRCDIR}/build/lib-${LIBBM}/include"
|
||||||
|
local CPPFLAGS="-I${SRCDIR}/build/lib-${LIBBM}/include"
|
||||||
|
local LDFLAGS="${march} -L${SRCDIR}/build/lib-${LIBBM}/lib"
|
||||||
|
|
||||||
|
local EXEC_PREAMBLE=""
|
||||||
|
local EXEC_SUFFIX=""
|
||||||
|
|
||||||
|
case ${host} in
|
||||||
|
*mingw*)
|
||||||
|
EXEC_PREAMBLE="wine"
|
||||||
|
EXEC_SUFFIX=".exe"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
mkdir -p ${D}
|
||||||
|
|
||||||
|
echo " ... ${BMD}"
|
||||||
|
|
||||||
|
cat >> Makefile.test <<EOF
|
||||||
|
|
||||||
|
# ${BMD}
|
||||||
|
# ${CFLAGS}
|
||||||
|
.PHONY: build-${BMD}
|
||||||
|
build-${BMD}:
|
||||||
|
(cd ${D} && make all && make install)
|
||||||
|
|
||||||
|
.PHONY: clean-${BMD}
|
||||||
|
clean-${BMD}:
|
||||||
|
(cd ${D} && make clean)
|
||||||
|
|
||||||
|
.PHONY: regtest-${BMD}
|
||||||
|
regtest-${BMD}:
|
||||||
|
(cd ${D} && ${EXEC_PREAMBLE} ./bin/xdelta3regtest${EXEC_SUFFIX} 1> \${TMP}/regtest.${BMD}.stdout 2> \${TMP}/regtest.${BMD}.stderr)
|
||||||
|
|
||||||
|
.PHONY: selftest-${BMD}
|
||||||
|
selftest-${BMD}:
|
||||||
|
(cd ${D} && ${EXEC_PREAMBLE} ./bin/xdelta3${EXEC_SUFFIX} test 1> \${TMP}/selftest.${BMD}.stdout 2> \${TMP}/selftest.${BMD}.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
case ${host} in
|
||||||
|
*linux*)
|
||||||
|
LINUXTGTS="${LINUXTGTS} build-${BMD}"
|
||||||
|
LINUXTEST1="${LINUXTEST1} selftest-${BMD}"
|
||||||
|
LINUXTEST2="${LINUXTEST2} regtest-${BMD}"
|
||||||
|
;;
|
||||||
|
*mingw*)
|
||||||
|
WINTGTS="${WINTGTS} build-${BMD}"
|
||||||
|
WINTEST1="${WINTEST1} selftest-${BMD}"
|
||||||
|
WINTEST2="${WINTEST2} regtest-${BMD}"
|
||||||
|
;;
|
||||||
|
*apple*)
|
||||||
|
OSXTGTS="${OSXTGTS} build-${BMD}"
|
||||||
|
OSXTEST1="${OSXTEST1} selftest-${BMD}"
|
||||||
|
OSXTEST2="${OSXTEST2} regtest-${BMD}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
CLEAN="${CLEAN} clean-${BMD}"
|
||||||
|
|
||||||
|
try configure-xdelta ${FULLD} ${SRCDIR}/configure \
|
||||||
|
--host=${host} \
|
||||||
|
--prefix=${FULLD} \
|
||||||
|
--enable-static \
|
||||||
|
--disable-shared \
|
||||||
|
--enable-debug-symbols \
|
||||||
|
"CFLAGS=${CFLAGS}" \
|
||||||
|
"CXXFLAGS=${CXXFLAGS}" \
|
||||||
|
"CPPFLAGS=${CPPFLAGS}" \
|
||||||
|
"LDFLAGS=${LDFLAGS}" \
|
||||||
|
"CC=${USECC}" \
|
||||||
|
"CXX=${USECXX}"
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# try build-xdelta ${FULLD} make ${MAKEFLAGS} all
|
||||||
|
# if [ $? -ne 0 ]; then
|
||||||
|
# return
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# try install-xdelta ${FULLD} make install
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildall {
|
||||||
|
echo ""
|
||||||
|
echo "Host $1$2 afl=$4"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
buildlzma "$1" "$2"
|
||||||
|
buildit "$1" "$2" 32 32 "-DXD3_USE_LARGESIZET=0 -DXD3_USE_LARGEFILE64=0 $3" "$4"
|
||||||
|
buildit "$1" "$2" 32 64 "-DXD3_USE_LARGESIZET=0 -DXD3_USE_LARGEFILE64=1 $3" "$4"
|
||||||
|
buildit "$1" "$2" 64 64 "-DXD3_USE_LARGESIZET=1 -DXD3_USE_LARGEFILE64=1 $3" "$4"
|
||||||
|
}
|
||||||
|
|
||||||
|
setup
|
||||||
|
|
||||||
|
try untar-lzma ${BUILDDIR} tar -xvf "${LZMA_FILE}"
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat > Makefile.test <<EOF
|
||||||
|
# Auto-generated ${DATE} -*- Mode: Makefile -*-
|
||||||
|
TMP = ${XTMP}
|
||||||
|
|
||||||
|
all: linux windows apple
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Native compiles
|
||||||
|
if [ "${MYOS}" == "Linux" ]; then
|
||||||
|
# Linux
|
||||||
|
buildall x86_64-pc-linux-gnu -m32 "${NONWIN_CFLAGS}" "0"
|
||||||
|
buildall x86_64-pc-linux-gnu -m32 "${NONWIN_CFLAGS}" "1"
|
||||||
|
buildall x86_64-pc-linux-gnu -m64 "${NONWIN_CFLAGS}" "0"
|
||||||
|
buildall x86_64-pc-linux-gnu -m64 "${NONWIN_CFLAGS}" "1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${MYOS}" == "Darwin" ]; then
|
||||||
|
# OS X
|
||||||
|
buildall x86_64-apple-darwin -m32 "${NONWIN_CFLAGS}" "0"
|
||||||
|
buildall x86_64-apple-darwin -m64 "${NONWIN_CFLAGS}" "0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Cross compile
|
||||||
|
buildall i686-w64-mingw32 -mconsole "${MINGW_CFLAGS}" "0"
|
||||||
|
buildall x86_64-w64-mingw32 -mconsole "${MINGW_CFLAGS}" "0"
|
||||||
|
|
||||||
|
cat >> Makefile.test <<EOF
|
||||||
|
|
||||||
|
clean: ${CLEAN}
|
||||||
|
|
||||||
|
.PHONY: linux windows apple
|
||||||
|
.PHONY: linux-build windows-build apple-build
|
||||||
|
.PHONY: linux-selftest windows-selftest apple-selftest
|
||||||
|
.PHONY: linux-regtest windows-regtest apple-regtest
|
||||||
|
|
||||||
|
linux: linux-build linux-selftest linux-regtest
|
||||||
|
windows: windows-build windows-selftest windows-regtest
|
||||||
|
apple: apple-build apple-selftest apple-regtest
|
||||||
|
|
||||||
|
linux-build: ${LINUXTGTS}
|
||||||
|
linux-selftest: ${LINUXTEST1}
|
||||||
|
linux-regtest: ${LINUXTEST2}
|
||||||
|
|
||||||
|
windows-build: ${WINTGTS}
|
||||||
|
windows-selftest: ${WINTEST1}
|
||||||
|
windows-regtest: ${WINTEST2}
|
||||||
|
|
||||||
|
apple-build: ${OSXTGTS}
|
||||||
|
apple-selftest: ${OSXTEST1}
|
||||||
|
apple-regtest: ${OSXTEST2}
|
||||||
|
|
||||||
|
EOF
|
8
lib/xdelta3/testing/Makefile
Normal file
8
lib/xdelta3/testing/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
all:
|
||||||
|
(cd .. && make all)
|
||||||
|
|
||||||
|
xdelta3regtest:
|
||||||
|
(cd .. && make xdelta3regtest)
|
||||||
|
|
||||||
|
xdelta3checksum:
|
||||||
|
(cd .. && make xdelta3checksum)
|
770
lib/xdelta3/testing/checksum_test.cc
Normal file
770
lib/xdelta3/testing/checksum_test.cc
Normal file
|
@ -0,0 +1,770 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: C++ -*-
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "../cpp-btree/btree_map.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
uint32_t xd3_large32_cksum_old (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look);
|
||||||
|
uint32_t xd3_large32_cksum_update_old (xd3_hash_cfg *cfg, uint32_t cksum,
|
||||||
|
const uint8_t *base, const usize_t look);
|
||||||
|
|
||||||
|
uint64_t xd3_large64_cksum_old (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look);
|
||||||
|
uint64_t xd3_large64_cksum_update_old (xd3_hash_cfg *cfg, uint64_t cksum,
|
||||||
|
const uint8_t *base, const usize_t look);
|
||||||
|
}
|
||||||
|
|
||||||
|
using btree::btree_map;
|
||||||
|
using std::list;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
// MLCG parameters
|
||||||
|
// a, a*
|
||||||
|
uint32_t good_32bit_values[] = {
|
||||||
|
1597334677U, // ...
|
||||||
|
741103597U, 887987685U,
|
||||||
|
};
|
||||||
|
|
||||||
|
// a, a*
|
||||||
|
uint64_t good_64bit_values[] = {
|
||||||
|
1181783497276652981ULL, 4292484099903637661ULL,
|
||||||
|
7664345821815920749ULL, // ...
|
||||||
|
};
|
||||||
|
|
||||||
|
void print_header() {
|
||||||
|
static int hdr_cnt = 0;
|
||||||
|
if (hdr_cnt++ % 20 == 0) {
|
||||||
|
printf("%-32sConf\t\tCount\tUniq\tFull\tCover\tColls"
|
||||||
|
"\tMB/s\tIters\t#Colls\n", "Name");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct true_type { };
|
||||||
|
struct false_type { };
|
||||||
|
|
||||||
|
template <typename Word>
|
||||||
|
usize_t bitsof();
|
||||||
|
|
||||||
|
template<>
|
||||||
|
usize_t bitsof<unsigned int>() {
|
||||||
|
return sizeof(unsigned int) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
usize_t bitsof<unsigned long>() {
|
||||||
|
return sizeof(unsigned long) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
usize_t bitsof<unsigned long long>() {
|
||||||
|
return sizeof(unsigned long long) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Word>
|
||||||
|
struct hhash { // shift "s" bits leaving the high bits as a hash value for
|
||||||
|
// this checksum, which are the most "distant" in terms of the
|
||||||
|
// spectral test for the rabin_karp MLCG. For short windows,
|
||||||
|
// the high bits aren't enough, XOR "mask" worth of these in.
|
||||||
|
Word operator()(const Word t, const Word s, const Word mask) {
|
||||||
|
return (t >> s) ^ (t & mask);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Word>
|
||||||
|
Word good_word();
|
||||||
|
|
||||||
|
template<>
|
||||||
|
uint32_t good_word<uint32_t>() {
|
||||||
|
return good_32bit_values[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
uint64_t good_word<uint64_t>() {
|
||||||
|
return good_64bit_values[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// CLASSES
|
||||||
|
|
||||||
|
#define SELF Word, CksumSize, CksumSkip, Hash, Compaction
|
||||||
|
#define MEMBER template <typename Word, \
|
||||||
|
int CksumSize, \
|
||||||
|
int CksumSkip, \
|
||||||
|
typename Hash, \
|
||||||
|
int Compaction>
|
||||||
|
|
||||||
|
MEMBER
|
||||||
|
struct cksum_params {
|
||||||
|
typedef Word word_type;
|
||||||
|
typedef Hash hash_type;
|
||||||
|
|
||||||
|
static const int cksum_size = CksumSize;
|
||||||
|
static const int cksum_skip = CksumSkip;
|
||||||
|
static const int compaction = Compaction;
|
||||||
|
};
|
||||||
|
|
||||||
|
MEMBER
|
||||||
|
struct rabin_karp : public cksum_params<SELF> {
|
||||||
|
// (a^cksum_size-1 c_0) + (a^cksum_size-2 c_1) ...
|
||||||
|
rabin_karp()
|
||||||
|
: powers(make_powers()),
|
||||||
|
product(powers[0] * good_word<Word>()),
|
||||||
|
incr_state(0) { }
|
||||||
|
|
||||||
|
static Word* make_powers() {
|
||||||
|
Word *p = new Word[CksumSize];
|
||||||
|
p[CksumSize - 1] = 1;
|
||||||
|
for (int i = CksumSize - 2; i >= 0; i--) {
|
||||||
|
p[i] = p[i + 1] * good_word<Word>();
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
~rabin_karp() {
|
||||||
|
delete [] powers;
|
||||||
|
}
|
||||||
|
|
||||||
|
Word step(const uint8_t *ptr) {
|
||||||
|
Word h = 0;
|
||||||
|
for (int i = 0; i < CksumSize; i++) {
|
||||||
|
h += (ptr[i]) * powers[i];
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
Word state0(const uint8_t *ptr) {
|
||||||
|
incr_state = step(ptr);
|
||||||
|
return incr_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
Word incr(const uint8_t *ptr) {
|
||||||
|
incr_state = good_word<Word>() * incr_state -
|
||||||
|
product * (ptr[-1]) + (ptr[CksumSize - 1]);
|
||||||
|
return incr_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Word *const powers;
|
||||||
|
const Word product;
|
||||||
|
Word incr_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
MEMBER
|
||||||
|
struct with_stream : public cksum_params<SELF> {
|
||||||
|
xd3_stream stream;
|
||||||
|
|
||||||
|
with_stream()
|
||||||
|
{
|
||||||
|
xd3_config cfg;
|
||||||
|
memset (&stream, 0, sizeof (stream));
|
||||||
|
xd3_init_config (&cfg, 0);
|
||||||
|
cfg.smatch_cfg = XD3_SMATCH_SOFT;
|
||||||
|
cfg.smatcher_soft.large_look = CksumSize;
|
||||||
|
cfg.smatcher_soft.large_step = CksumSkip;
|
||||||
|
cfg.smatcher_soft.small_look = 4;
|
||||||
|
cfg.smatcher_soft.small_chain = 4;
|
||||||
|
cfg.smatcher_soft.small_lchain = 4;
|
||||||
|
cfg.smatcher_soft.max_lazy = 4;
|
||||||
|
cfg.smatcher_soft.long_enough = 4;
|
||||||
|
CHECK_EQ(0, xd3_config_stream (&stream, &cfg));
|
||||||
|
|
||||||
|
CHECK_EQ(0, xd3_size_hashtable (&stream,
|
||||||
|
1<<10 /* ignored */,
|
||||||
|
stream.smatcher.large_look,
|
||||||
|
& stream.large_hash));
|
||||||
|
}
|
||||||
|
~with_stream()
|
||||||
|
{
|
||||||
|
xd3_free_stream (&stream);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MEMBER
|
||||||
|
struct large_cksum : public with_stream<SELF> {
|
||||||
|
Word step(const uint8_t *ptr) {
|
||||||
|
return xd3_large_cksum (&this->stream.large_hash, ptr, CksumSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
Word state0(const uint8_t *ptr) {
|
||||||
|
incr_state = step(ptr);
|
||||||
|
return incr_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
Word incr(const uint8_t *ptr) {
|
||||||
|
incr_state = xd3_large_cksum_update (&this->stream.large_hash,
|
||||||
|
incr_state, ptr - 1, CksumSize);
|
||||||
|
return incr_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
Word incr_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if SIZEOF_USIZE_T == 4
|
||||||
|
#define xd3_large_cksum_old xd3_large32_cksum_old
|
||||||
|
#define xd3_large_cksum_update_old xd3_large32_cksum_update_old
|
||||||
|
#elif SIZEOF_USIZE_T == 8
|
||||||
|
#define xd3_large_cksum_old xd3_large64_cksum_old
|
||||||
|
#define xd3_large_cksum_update_old xd3_large64_cksum_update_old
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MEMBER
|
||||||
|
struct large_cksum_old : public with_stream<SELF> {
|
||||||
|
Word step(const uint8_t *ptr) {
|
||||||
|
return xd3_large_cksum_old (&this->stream.large_hash, ptr, CksumSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
Word state0(const uint8_t *ptr) {
|
||||||
|
incr_state = step(ptr);
|
||||||
|
return incr_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
Word incr(const uint8_t *ptr) {
|
||||||
|
incr_state = xd3_large_cksum_update_old (&this->stream.large_hash,
|
||||||
|
incr_state, ptr - 1, CksumSize);
|
||||||
|
return incr_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
Word incr_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TESTS
|
||||||
|
|
||||||
|
template <typename Word>
|
||||||
|
struct file_stats {
|
||||||
|
typedef const uint8_t* ptr_type;
|
||||||
|
typedef Word word_type;
|
||||||
|
typedef btree::btree_multimap<word_type, ptr_type> table_type;
|
||||||
|
typedef typename table_type::iterator table_iterator;
|
||||||
|
|
||||||
|
usize_t cksum_size;
|
||||||
|
usize_t cksum_skip;
|
||||||
|
usize_t unique;
|
||||||
|
usize_t unique_values;
|
||||||
|
usize_t count;
|
||||||
|
table_type table;
|
||||||
|
|
||||||
|
file_stats(usize_t size, usize_t skip)
|
||||||
|
: cksum_size(size),
|
||||||
|
cksum_skip(skip),
|
||||||
|
unique(0),
|
||||||
|
unique_values(0),
|
||||||
|
count(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
unique = 0;
|
||||||
|
unique_values = 0;
|
||||||
|
count = 0;
|
||||||
|
table.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(word_type word, ptr_type ptr) {
|
||||||
|
table_iterator t_i = table.find(word);
|
||||||
|
|
||||||
|
count++;
|
||||||
|
if (t_i != table.end()) {
|
||||||
|
int collisions = 0;
|
||||||
|
for (table_iterator p_i = t_i;
|
||||||
|
p_i != table.end() && p_i->first == word;
|
||||||
|
++p_i) {
|
||||||
|
if (memcmp(p_i->second, ptr, cksum_size) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
collisions++;
|
||||||
|
}
|
||||||
|
if (collisions >= 1000) {
|
||||||
|
fprintf(stderr, "Something is not right, lots of collisions=%d\n",
|
||||||
|
collisions);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unique_values++;
|
||||||
|
}
|
||||||
|
unique++;
|
||||||
|
table.insert(std::make_pair(word, ptr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeze() {
|
||||||
|
table.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_result_base;
|
||||||
|
|
||||||
|
static vector<test_result_base*> all_tests;
|
||||||
|
|
||||||
|
struct test_result_base {
|
||||||
|
virtual ~test_result_base() {
|
||||||
|
}
|
||||||
|
virtual void reset() = 0;
|
||||||
|
virtual void print() = 0;
|
||||||
|
virtual void get(const uint8_t* buf, const size_t buf_size,
|
||||||
|
usize_t iters) = 0;
|
||||||
|
virtual void stat() = 0;
|
||||||
|
virtual usize_t count() = 0;
|
||||||
|
virtual usize_t dups() = 0;
|
||||||
|
virtual double uniqueness() = 0;
|
||||||
|
virtual double fullness() = 0;
|
||||||
|
virtual double collisions() = 0;
|
||||||
|
virtual double coverage() = 0;
|
||||||
|
virtual double compression() = 0;
|
||||||
|
virtual double time() = 0;
|
||||||
|
virtual double total_time() = 0;
|
||||||
|
virtual usize_t total_count() = 0;
|
||||||
|
virtual usize_t total_dups() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Checksum>
|
||||||
|
struct test_result : public test_result_base {
|
||||||
|
Checksum cksum;
|
||||||
|
const char *test_name;
|
||||||
|
file_stats<typename Checksum::word_type> fstats;
|
||||||
|
usize_t test_size;
|
||||||
|
usize_t n_steps;
|
||||||
|
usize_t n_incrs;
|
||||||
|
typename Checksum::word_type s_bits;
|
||||||
|
typename Checksum::word_type s_mask;
|
||||||
|
usize_t t_entries;
|
||||||
|
usize_t h_bits;
|
||||||
|
usize_t h_buckets_full;
|
||||||
|
char *hash_table;
|
||||||
|
long accum_millis;
|
||||||
|
usize_t accum_iters;
|
||||||
|
|
||||||
|
// These are not reset
|
||||||
|
double accum_time;
|
||||||
|
usize_t accum_count;
|
||||||
|
usize_t accum_dups;
|
||||||
|
usize_t accum_colls;
|
||||||
|
size_t accum_size;
|
||||||
|
|
||||||
|
test_result(const char *name)
|
||||||
|
: test_name(name),
|
||||||
|
fstats(Checksum::cksum_size, Checksum::cksum_skip),
|
||||||
|
hash_table(NULL),
|
||||||
|
accum_millis(0),
|
||||||
|
accum_iters(0),
|
||||||
|
accum_time(0.0),
|
||||||
|
accum_count(0),
|
||||||
|
accum_dups(0),
|
||||||
|
accum_colls(0),
|
||||||
|
accum_size(0) {
|
||||||
|
all_tests.push_back(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~test_result() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
// size of file
|
||||||
|
test_size = 0;
|
||||||
|
|
||||||
|
// count
|
||||||
|
n_steps = 0;
|
||||||
|
n_incrs = 0;
|
||||||
|
|
||||||
|
// four values used by new_table()/summarize_table()
|
||||||
|
s_bits = 0;
|
||||||
|
s_mask = 0;
|
||||||
|
t_entries = 0;
|
||||||
|
h_bits = 0;
|
||||||
|
h_buckets_full = 0;
|
||||||
|
|
||||||
|
accum_millis = 0;
|
||||||
|
accum_iters = 0;
|
||||||
|
|
||||||
|
fstats.reset();
|
||||||
|
|
||||||
|
// temporary
|
||||||
|
if (hash_table) {
|
||||||
|
delete(hash_table);
|
||||||
|
hash_table = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usize_t count() {
|
||||||
|
if (Checksum::cksum_skip == 1) {
|
||||||
|
return n_incrs;
|
||||||
|
} else {
|
||||||
|
return n_steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usize_t dups() {
|
||||||
|
return fstats.count - fstats.unique;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fraction of distinct strings of length cksum_size which are not
|
||||||
|
* represented in the hash table. */
|
||||||
|
double collisions() {
|
||||||
|
return (fstats.unique - fstats.unique_values) / (double) fstats.unique;
|
||||||
|
}
|
||||||
|
usize_t colls() {
|
||||||
|
return (fstats.unique - fstats.unique_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
double uniqueness() {
|
||||||
|
return 1.0 - (double) dups() / count();
|
||||||
|
}
|
||||||
|
|
||||||
|
double fullness() {
|
||||||
|
return (double) h_buckets_full / (1 << h_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
double coverage() {
|
||||||
|
return (double) h_buckets_full / uniqueness() / count();
|
||||||
|
}
|
||||||
|
|
||||||
|
double compression() {
|
||||||
|
return 1.0 - coverage();
|
||||||
|
}
|
||||||
|
|
||||||
|
double time() {
|
||||||
|
return (double) accum_millis / accum_iters;
|
||||||
|
}
|
||||||
|
|
||||||
|
double total_time() {
|
||||||
|
return accum_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
usize_t total_count() {
|
||||||
|
return accum_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
usize_t total_dups() {
|
||||||
|
return accum_dups;
|
||||||
|
}
|
||||||
|
|
||||||
|
usize_t total_colls() {
|
||||||
|
return accum_dups;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stat() {
|
||||||
|
accum_time += time();
|
||||||
|
accum_count += count();
|
||||||
|
accum_dups += dups();
|
||||||
|
accum_colls += colls();
|
||||||
|
accum_size += test_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print() {
|
||||||
|
if (fstats.count != count()) {
|
||||||
|
fprintf(stderr, "internal error: %" W "d != %" W "d\n", fstats.count, count());
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
print_header();
|
||||||
|
printf("%-32s%d/%d 2^%" W "u\t%" W "u\t%0.4f\t%.4f\t%.4f\t%.1e\t%.2f\t"
|
||||||
|
"%" W "u\t%" W "u\n",
|
||||||
|
test_name,
|
||||||
|
Checksum::cksum_size,
|
||||||
|
Checksum::cksum_skip,
|
||||||
|
h_bits,
|
||||||
|
count(),
|
||||||
|
uniqueness(),
|
||||||
|
fullness(),
|
||||||
|
coverage(),
|
||||||
|
collisions(),
|
||||||
|
0.001 * accum_iters * test_size / accum_millis,
|
||||||
|
accum_iters,
|
||||||
|
colls());
|
||||||
|
}
|
||||||
|
|
||||||
|
usize_t size_log2 (usize_t slots) {
|
||||||
|
usize_t bits = bitsof<typename Checksum::word_type>() - 1;
|
||||||
|
usize_t i;
|
||||||
|
|
||||||
|
for (i = 3; i <= bits; i += 1) {
|
||||||
|
if (slots <= (1U << i)) {
|
||||||
|
return i - Checksum::compaction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
void new_table(usize_t entries) {
|
||||||
|
t_entries = entries;
|
||||||
|
h_bits = size_log2(entries);
|
||||||
|
|
||||||
|
usize_t n = 1 << h_bits;
|
||||||
|
|
||||||
|
s_bits = bitsof<typename Checksum::word_type>() - h_bits;
|
||||||
|
s_mask = n - 1U;
|
||||||
|
|
||||||
|
hash_table = new char[n / 8];
|
||||||
|
memset(hash_table, 0, n / 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_table_bit(usize_t i) {
|
||||||
|
return hash_table[i/8] & (1 << i%8);
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_table_bit(usize_t i) {
|
||||||
|
return hash_table[i/8] |= (1 << i%8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void summarize_table() {
|
||||||
|
usize_t n = 1 << h_bits;
|
||||||
|
usize_t f = 0;
|
||||||
|
for (usize_t i = 0; i < n; i++) {
|
||||||
|
if (get_table_bit(i)) {
|
||||||
|
f++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h_buckets_full = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void get(const uint8_t* buf, const size_t buf_size, usize_t test_iters) {
|
||||||
|
typename Checksum::hash_type hash;
|
||||||
|
const uint8_t *ptr;
|
||||||
|
const uint8_t *end;
|
||||||
|
usize_t periods;
|
||||||
|
int64_t last_offset;
|
||||||
|
int64_t stop;
|
||||||
|
|
||||||
|
test_size = buf_size;
|
||||||
|
last_offset = buf_size - Checksum::cksum_size;
|
||||||
|
|
||||||
|
if (last_offset < 0) {
|
||||||
|
periods = 0;
|
||||||
|
n_steps = 0;
|
||||||
|
n_incrs = 0;
|
||||||
|
stop = -Checksum::cksum_size;
|
||||||
|
} else {
|
||||||
|
periods = last_offset / Checksum::cksum_skip;
|
||||||
|
n_steps = periods + 1;
|
||||||
|
n_incrs = last_offset + 1;
|
||||||
|
stop = last_offset - (periods + 1) * Checksum::cksum_skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute file stats once.
|
||||||
|
if (fstats.unique_values == 0) {
|
||||||
|
if (Checksum::cksum_skip == 1) {
|
||||||
|
for (size_t i = 0; i <= buf_size - Checksum::cksum_size; i++) {
|
||||||
|
fstats.update(hash(cksum.step(buf + i), s_bits, s_mask), buf + i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ptr = buf + last_offset;
|
||||||
|
end = buf + stop;
|
||||||
|
|
||||||
|
for (; ptr != end; ptr -= Checksum::cksum_skip) {
|
||||||
|
fstats.update(hash(cksum.step(ptr), s_bits, s_mask), ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fstats.freeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
long start_test = get_millisecs_now();
|
||||||
|
|
||||||
|
if (Checksum::cksum_skip != 1) {
|
||||||
|
new_table(n_steps);
|
||||||
|
|
||||||
|
for (usize_t i = 0; i < test_iters; i++) {
|
||||||
|
ptr = buf + last_offset;
|
||||||
|
end = buf + stop;
|
||||||
|
|
||||||
|
for (; ptr != end; ptr -= Checksum::cksum_skip) {
|
||||||
|
set_table_bit(hash(cksum.step(ptr), s_bits, s_mask));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
summarize_table();
|
||||||
|
}
|
||||||
|
|
||||||
|
stop = buf_size - Checksum::cksum_size + 1;
|
||||||
|
if (stop < 0) {
|
||||||
|
stop = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Checksum::cksum_skip == 1) {
|
||||||
|
new_table(n_incrs);
|
||||||
|
|
||||||
|
for (usize_t i = 0; i < test_iters; i++) {
|
||||||
|
ptr = buf;
|
||||||
|
end = buf + stop;
|
||||||
|
|
||||||
|
if (ptr != end) {
|
||||||
|
set_table_bit(hash(cksum.state0(ptr++), s_bits, s_mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; ptr != end; ptr++) {
|
||||||
|
typename Checksum::word_type w = cksum.incr(ptr);
|
||||||
|
CHECK_EQ(w, cksum.step(ptr));
|
||||||
|
set_table_bit(hash(w, s_bits, s_mask));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
summarize_table();
|
||||||
|
}
|
||||||
|
|
||||||
|
accum_iters += test_iters;
|
||||||
|
accum_millis += get_millisecs_now() - start_test;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int read_whole_file(const char *name,
|
||||||
|
uint8_t **buf_ptr,
|
||||||
|
size_t *buf_len) {
|
||||||
|
main_file file;
|
||||||
|
int ret;
|
||||||
|
xoff_t len;
|
||||||
|
size_t nread;
|
||||||
|
main_file_init(&file);
|
||||||
|
file.filename = name;
|
||||||
|
ret = main_file_open(&file, name, XO_READ);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "open failed\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
ret = main_file_stat(&file, &len);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "stat failed\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*buf_len) = (size_t)len;
|
||||||
|
(*buf_ptr) = (uint8_t*) main_malloc(*buf_len);
|
||||||
|
ret = main_file_read(&file, *buf_ptr, *buf_len, &nread,
|
||||||
|
"read failed");
|
||||||
|
if (ret == 0 && *buf_len == nread) {
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "invalid read\n");
|
||||||
|
ret = XD3_INTERNAL;
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
main_file_cleanup(&file);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
int i;
|
||||||
|
uint8_t *buf = NULL;
|
||||||
|
size_t buf_len = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (argc <= 1) {
|
||||||
|
fprintf(stderr, "usage: %s file ...\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: The xdelta3-hash.h code is identical now; add sameness test.
|
||||||
|
// using rabin_karp<> template.
|
||||||
|
#define TEST(T,Z,S,C) \
|
||||||
|
test_result<large_cksum<T,Z,S,hhash<T>,C>> \
|
||||||
|
_xck_ ## T ## _ ## Z ## _ ## S ## _ ## C \
|
||||||
|
("xck_" #T "_" #Z "_" #S "_" #C); \
|
||||||
|
test_result<large_cksum_old<T,Z,S,hhash<T>,C>> \
|
||||||
|
_old_ ## T ## _ ## Z ## _ ## S ## _ ## C \
|
||||||
|
("old_" #T "_" #Z "_" #S "_" #C)
|
||||||
|
|
||||||
|
#define TESTS(SIZE, SKIP) \
|
||||||
|
TEST(usize_t, SIZE, SKIP, 1); \
|
||||||
|
TEST(usize_t, SIZE, SKIP, 2)
|
||||||
|
|
||||||
|
TESTS(5, 1);
|
||||||
|
TESTS(6, 1);
|
||||||
|
TESTS(7, 1);
|
||||||
|
TESTS(8, 1);
|
||||||
|
TESTS(9, 1);
|
||||||
|
TESTS(10, 1);
|
||||||
|
TESTS(11, 1);
|
||||||
|
TESTS(12, 1);
|
||||||
|
TESTS(13, 1);
|
||||||
|
TESTS(14, 1);
|
||||||
|
TESTS(15, 1);
|
||||||
|
TESTS(16, 1);
|
||||||
|
TESTS(17, 1);
|
||||||
|
TESTS(18, 1);
|
||||||
|
TESTS(19, 1);
|
||||||
|
TESTS(20, 1);
|
||||||
|
TESTS(21, 1);
|
||||||
|
TESTS(22, 1);
|
||||||
|
TESTS(23, 1);
|
||||||
|
TESTS(24, 1);
|
||||||
|
TESTS(25, 1);
|
||||||
|
TESTS(26, 1);
|
||||||
|
TESTS(27, 1);
|
||||||
|
TESTS(28, 1);
|
||||||
|
TESTS(29, 1);
|
||||||
|
TESTS(30, 1);
|
||||||
|
TESTS(31, 1);
|
||||||
|
TESTS(32, 1);
|
||||||
|
TESTS(33, 1);
|
||||||
|
TESTS(34, 1);
|
||||||
|
TESTS(35, 1);
|
||||||
|
TESTS(36, 1);
|
||||||
|
TESTS(37, 1);
|
||||||
|
TESTS(38, 1);
|
||||||
|
TESTS(39, 1);
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
if ((ret = read_whole_file(argv[i],
|
||||||
|
& buf,
|
||||||
|
& buf_len))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "file %s is %zu bytes\n",
|
||||||
|
argv[i], buf_len);
|
||||||
|
|
||||||
|
double min_time = -1.0;
|
||||||
|
double min_compression = 0.0;
|
||||||
|
|
||||||
|
for (vector<test_result_base*>::iterator iter = all_tests.begin();
|
||||||
|
iter != all_tests.end(); ++iter) {
|
||||||
|
test_result_base *test = *iter;
|
||||||
|
test->reset();
|
||||||
|
|
||||||
|
usize_t iters = 1;
|
||||||
|
long start_test = get_millisecs_now();
|
||||||
|
|
||||||
|
do {
|
||||||
|
test->get(buf, buf_len, iters);
|
||||||
|
iters *= 3;
|
||||||
|
iters /= 2;
|
||||||
|
} while (get_millisecs_now() - start_test < 2000);
|
||||||
|
|
||||||
|
test->stat();
|
||||||
|
|
||||||
|
if (min_time < 0.0) {
|
||||||
|
min_compression = test->compression();
|
||||||
|
min_time = test->time();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min_time > test->time()) {
|
||||||
|
min_time = test->time();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min_compression > test->compression()) {
|
||||||
|
min_compression = test->compression();
|
||||||
|
}
|
||||||
|
|
||||||
|
test->print();
|
||||||
|
}
|
||||||
|
|
||||||
|
main_free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
189
lib/xdelta3/testing/checksum_test_c.c
Normal file
189
lib/xdelta3/testing/checksum_test_c.c
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: C++ -*-
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#include "../xdelta3.c"
|
||||||
|
|
||||||
|
// OLD CHECKSUM CODE
|
||||||
|
|
||||||
|
#define PERMUTE32(x) (__single_hash32[x])
|
||||||
|
#define PERMUTE64(x) (__single_hash64[x])
|
||||||
|
|
||||||
|
const uint16_t __single_hash32[256] =
|
||||||
|
{
|
||||||
|
/* This hashes the input alphabet (Scheme SLIB pseudo-random). */
|
||||||
|
0xbcd1, 0xbb65, 0x42c2, 0xdffe, 0x9666, 0x431b, 0x8504, 0xeb46,
|
||||||
|
0x6379, 0xd460, 0xcf14, 0x53cf, 0xdb51, 0xdb08, 0x12c8, 0xf602,
|
||||||
|
0xe766, 0x2394, 0x250d, 0xdcbb, 0xa678, 0x02af, 0xa5c6, 0x7ea6,
|
||||||
|
0xb645, 0xcb4d, 0xc44b, 0xe5dc, 0x9fe6, 0x5b5c, 0x35f5, 0x701a,
|
||||||
|
0x220f, 0x6c38, 0x1a56, 0x4ca3, 0xffc6, 0xb152, 0x8d61, 0x7a58,
|
||||||
|
0x9025, 0x8b3d, 0xbf0f, 0x95a3, 0xe5f4, 0xc127, 0x3bed, 0x320b,
|
||||||
|
0xb7f3, 0x6054, 0x333c, 0xd383, 0x8154, 0x5242, 0x4e0d, 0x0a94,
|
||||||
|
0x7028, 0x8689, 0x3a22, 0x0980, 0x1847, 0xb0f1, 0x9b5c, 0x4176,
|
||||||
|
0xb858, 0xd542, 0x1f6c, 0x2497, 0x6a5a, 0x9fa9, 0x8c5a, 0x7743,
|
||||||
|
0xa8a9, 0x9a02, 0x4918, 0x438c, 0xc388, 0x9e2b, 0x4cad, 0x01b6,
|
||||||
|
0xab19, 0xf777, 0x365f, 0x1eb2, 0x091e, 0x7bf8, 0x7a8e, 0x5227,
|
||||||
|
0xeab1, 0x2074, 0x4523, 0xe781, 0x01a3, 0x163d, 0x3b2e, 0x287d,
|
||||||
|
0x5e7f, 0xa063, 0xb134, 0x8fae, 0x5e8e, 0xb7b7, 0x4548, 0x1f5a,
|
||||||
|
0xfa56, 0x7a24, 0x900f, 0x42dc, 0xcc69, 0x02a0, 0x0b22, 0xdb31,
|
||||||
|
0x71fe, 0x0c7d, 0x1732, 0x1159, 0xcb09, 0xe1d2, 0x1351, 0x52e9,
|
||||||
|
0xf536, 0x5a4f, 0xc316, 0x6bf9, 0x8994, 0xb774, 0x5f3e, 0xf6d6,
|
||||||
|
0x3a61, 0xf82c, 0xcc22, 0x9d06, 0x299c, 0x09e5, 0x1eec, 0x514f,
|
||||||
|
0x8d53, 0xa650, 0x5c6e, 0xc577, 0x7958, 0x71ac, 0x8916, 0x9b4f,
|
||||||
|
0x2c09, 0x5211, 0xf6d8, 0xcaaa, 0xf7ef, 0x287f, 0x7a94, 0xab49,
|
||||||
|
0xfa2c, 0x7222, 0xe457, 0xd71a, 0x00c3, 0x1a76, 0xe98c, 0xc037,
|
||||||
|
0x8208, 0x5c2d, 0xdfda, 0xe5f5, 0x0b45, 0x15ce, 0x8a7e, 0xfcad,
|
||||||
|
0xaa2d, 0x4b5c, 0xd42e, 0xb251, 0x907e, 0x9a47, 0xc9a6, 0xd93f,
|
||||||
|
0x085e, 0x35ce, 0xa153, 0x7e7b, 0x9f0b, 0x25aa, 0x5d9f, 0xc04d,
|
||||||
|
0x8a0e, 0x2875, 0x4a1c, 0x295f, 0x1393, 0xf760, 0x9178, 0x0f5b,
|
||||||
|
0xfa7d, 0x83b4, 0x2082, 0x721d, 0x6462, 0x0368, 0x67e2, 0x8624,
|
||||||
|
0x194d, 0x22f6, 0x78fb, 0x6791, 0xb238, 0xb332, 0x7276, 0xf272,
|
||||||
|
0x47ec, 0x4504, 0xa961, 0x9fc8, 0x3fdc, 0xb413, 0x007a, 0x0806,
|
||||||
|
0x7458, 0x95c6, 0xccaa, 0x18d6, 0xe2ae, 0x1b06, 0xf3f6, 0x5050,
|
||||||
|
0xc8e8, 0xf4ac, 0xc04c, 0xf41c, 0x992f, 0xae44, 0x5f1b, 0x1113,
|
||||||
|
0x1738, 0xd9a8, 0x19ea, 0x2d33, 0x9698, 0x2fe9, 0x323f, 0xcde2,
|
||||||
|
0x6d71, 0xe37d, 0xb697, 0x2c4f, 0x4373, 0x9102, 0x075d, 0x8e25,
|
||||||
|
0x1672, 0xec28, 0x6acb, 0x86cc, 0x186e, 0x9414, 0xd674, 0xd1a5
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32_t __single_hash64[256] =
|
||||||
|
{
|
||||||
|
/* http://random.org 2014.10.24 */
|
||||||
|
0xd25e9f0a, 0xb1af9d5e, 0xb753dfa2, 0x157050f7, /* 0 */
|
||||||
|
0xc84b072c, 0xdd14fe7c, 0xf92208c3, 0xdf08a0c0,
|
||||||
|
0x63a5c118, 0x76f5d90f, 0xa2f8b93e, 0xb6c12d22,
|
||||||
|
0xaf074957, 0x966fb7d9, 0x62f7b785, 0xb40e8a09,
|
||||||
|
0x0a811d5d, 0x323a6daa, 0xb62f7c5b, 0xfdcb9a53,
|
||||||
|
0xf25a9067, 0x4506bc7a, 0xff58a74b, 0x5ae62817,
|
||||||
|
0x74097675, 0x722c0fd9, 0x116a2a66, 0x65f76728,
|
||||||
|
0x72c79651, 0xe043cf9d, 0x64b867c7, 0x6604834f,
|
||||||
|
0xcdca58a6, 0x0f164e2d, 0x24515f05, 0x632cdbf8,
|
||||||
|
0x18091d4a, 0x3eff4128, 0x673d1c33, 0xd8e10c71,
|
||||||
|
0x1a3edf11, 0xba52892f, 0xa56949e0, 0xf3e1dd77, /* 10 */
|
||||||
|
0x86fcbe3e, 0x138d66d0, 0x4fc98359, 0xc22e5dd6,
|
||||||
|
0xc59f2267, 0x6c6dd739, 0xe03da190, 0x07e8469c,
|
||||||
|
0xadcfb02c, 0x00d3b0d9, 0xa1f44918, 0x8bd84d87,
|
||||||
|
0x08ec9ec1, 0xbbcd156f, 0xb57718e3, 0x3177e752,
|
||||||
|
0xf52a4d70, 0xde7aaad9, 0x075f1da0, 0x21ba00c6,
|
||||||
|
0xb9469a5c, 0xcf08d5ba, 0x91ac9edc, 0xc6167b63,
|
||||||
|
0xc1974919, 0xc8c8d195, 0x4b1996dd, 0xeff8991c,
|
||||||
|
0xf7f66c6b, 0x25b012e2, 0x59d12a98, 0xea40d3cc,
|
||||||
|
0x41f9970b, 0xec48101a, 0xa3bdcf90, 0x99f16905,
|
||||||
|
0x27af6c97, 0xc849af37, 0x49cad89b, 0xf48c2278, /* 20 */
|
||||||
|
0x5529c3d8, 0x9e7d6dce, 0x16feb52d, 0xf1b0aca1,
|
||||||
|
0xaf28fccb, 0x48e4ce3c, 0xc4436617, 0x64524e3e,
|
||||||
|
0x61806681, 0x6384f2d7, 0x1172880f, 0x34a5ef5f,
|
||||||
|
0xcc8cc0a8, 0x66e8f100, 0x2866085f, 0xba9b1b2d,
|
||||||
|
0x51285949, 0x2be4b574, 0x889b1ef5, 0x3dbe920d,
|
||||||
|
0x9277a62f, 0x0584a9f6, 0x085d8fc4, 0x4b5d403d,
|
||||||
|
0x4e46ca78, 0x3294c2f9, 0x29313e70, 0xe4f09b24,
|
||||||
|
0xe73b331c, 0x072f5552, 0x2e390b78, 0xea0021ca,
|
||||||
|
0xd8f40320, 0xed0e16fd, 0x7de9cf7a, 0xf17e3d6c,
|
||||||
|
0x8df1bd85, 0x052cae67, 0x3486e512, 0x3a1c09b8, /* 30 */
|
||||||
|
0x6c2a7b4e, 0x83455753, 0xbc0353ac, 0x0ffe20b6,
|
||||||
|
0x5fdcef85, 0x010f506c, 0x595ce972, 0xe28680d0,
|
||||||
|
0xa7e216b2, 0xa392ee0f, 0x25b73faa, 0x2b1f4983,
|
||||||
|
0xeeaefe98, 0x1d3d9cbc, 0x6aebe97b, 0x8b7b3584,
|
||||||
|
0x9e6a9a07, 0xd37f1e99, 0x4ac2a441, 0x8ae9a213,
|
||||||
|
0x7d0e27d7, 0x5de54b9a, 0x8621de1f, 0xf0f2f866,
|
||||||
|
0xcb08d275, 0x49c3f87e, 0xd5ee68c1, 0x9802fc77,
|
||||||
|
0x68be6c5e, 0x65aa8c27, 0xf423d5f7, 0x10ec5502,
|
||||||
|
0x9909bce1, 0x509cdf1b, 0x338fea72, 0x2733e9bf,
|
||||||
|
0xf92f4fd7, 0x87738ea2, 0x931a8bbc, 0x0a5c9155, /* 40 */
|
||||||
|
0xbe5edd9b, 0xadbf5838, 0x0338f8d2, 0x290da210,
|
||||||
|
0x390c37d8, 0xe7cffae8, 0x20617ebe, 0x464322dd,
|
||||||
|
0x7b3c4e78, 0xac142dcb, 0x2d5cef76, 0xd8fe49fc,
|
||||||
|
0x60f4e9a9, 0x7473816f, 0x0dc35f39, 0x5eed80c1,
|
||||||
|
0x0cb55ab6, 0x1d3ac541, 0x13c7f529, 0x7bffdf4a,
|
||||||
|
0xe334785b, 0x85263ec1, 0xd132ae56, 0x7c868b9e,
|
||||||
|
0x47f60638, 0x1012b979, 0x81c31dd3, 0x1af868c8,
|
||||||
|
0x0c5d0742, 0xd1b3e1a2, 0x5873200a, 0xf848465c,
|
||||||
|
0x0fc4d596, 0x609c18af, 0xc9f5a480, 0xd1a94a84,
|
||||||
|
0xa1431a3f, 0x7de8bb1a, 0x25f1256b, 0x1dcc732c, /* 50 */
|
||||||
|
0x6aa1549a, 0xa2367281, 0x32f2a77e, 0x82e62a0f,
|
||||||
|
0x045cbb56, 0x74b2027c, 0xd71a32d9, 0x022e7cb5,
|
||||||
|
0xe99be177, 0x60222fdf, 0xd69681ca, 0x9008ee2c,
|
||||||
|
0x32923db4, 0xcf82bf97, 0x38960a5b, 0xb3503d5b,
|
||||||
|
0x9bd4c7f2, 0x33c029c8, 0x1ef504a3, 0xdb249d3b,
|
||||||
|
0x91e89676, 0x4ca43b36, 0x9191433c, 0x465d5dc4,
|
||||||
|
0xf4dcb118, 0x9d11dd00, 0xb592f058, 0xdbe5ce30,
|
||||||
|
0x74790d92, 0x779850a8, 0x7180d25b, 0xfa951d99,
|
||||||
|
0x5990935a, 0x921cb022, 0x3b7c39bc, 0x6a38a7c7,
|
||||||
|
0xdc22703b, 0x142bab3b, 0x4e3d9479, 0x44bb8482, /* 60 */
|
||||||
|
0x8043abce, 0xfebe832a, 0x8e6a2f98, 0x4d43c4fe,
|
||||||
|
0xd192a70a, 0x802f3c3a, 0x5d11bbab, 0x2665d241,
|
||||||
|
0xb3f3a680, 0x3a8d223f, 0xcf82cdb4, 0x4ed28743,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
xd3_large64_cksum_old (xd3_hash_cfg *ignore, const uint8_t *base, const usize_t look)
|
||||||
|
{
|
||||||
|
static const uint64_t kBits = 32;
|
||||||
|
static const uint64_t kMask = 0xffffffff;
|
||||||
|
usize_t i = 0;
|
||||||
|
uint64_t low = 0;
|
||||||
|
uint64_t high = 0;
|
||||||
|
|
||||||
|
for (; i < look; i += 1)
|
||||||
|
{
|
||||||
|
low += PERMUTE64(*base++);
|
||||||
|
high += low;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((high & kMask) << kBits) | (low & kMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
xd3_large64_cksum_update_old (xd3_hash_cfg *ignore, const uint64_t cksum,
|
||||||
|
const uint8_t *base, const usize_t look)
|
||||||
|
{
|
||||||
|
static const uint64_t kBits = 32;
|
||||||
|
static const uint64_t kMask = 0xffffffff;
|
||||||
|
uint64_t old_c = PERMUTE64(base[0]);
|
||||||
|
uint64_t new_c = PERMUTE64(base[look]);
|
||||||
|
uint64_t low = ((cksum & kMask) - old_c + new_c) & kMask;
|
||||||
|
uint64_t high = ((cksum >> kBits) - (old_c * look) + low) & kMask;
|
||||||
|
return (high << kBits) | low;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
xd3_large32_cksum_old (xd3_hash_cfg *ignore, const uint8_t *base, const usize_t look)
|
||||||
|
{
|
||||||
|
static const uint32_t kBits = 16;
|
||||||
|
static const uint32_t kMask = 0xffff;
|
||||||
|
usize_t i = 0;
|
||||||
|
uint32_t low = 0;
|
||||||
|
uint32_t high = 0;
|
||||||
|
|
||||||
|
for (; i < look; i += 1)
|
||||||
|
{
|
||||||
|
low += PERMUTE32(*base++);
|
||||||
|
high += low;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((high & kMask) << kBits) | (low & kMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
xd3_large32_cksum_update_old (xd3_hash_cfg *ignore, const uint32_t cksum,
|
||||||
|
const uint8_t *base, const usize_t look)
|
||||||
|
{
|
||||||
|
static const uint32_t kBits = 16;
|
||||||
|
static const uint32_t kMask = 0xffff;
|
||||||
|
uint32_t old_c = PERMUTE32(base[0]);
|
||||||
|
uint32_t new_c = PERMUTE32(base[look]);
|
||||||
|
uint32_t low = ((cksum & kMask) - old_c + new_c) & kMask;
|
||||||
|
uint32_t high = ((cksum >> kBits) - (old_c * look) + low) & kMask;
|
||||||
|
return (high << kBits) | low;
|
||||||
|
}
|
67
lib/xdelta3/testing/cmp.h
Normal file
67
lib/xdelta3/testing/cmp.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: C++ -*-
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
static size_t CmpDifferentBlockBytes(const Block &a, const Block &b) {
|
||||||
|
size_t total = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
size_t m = min(a.Size(), b.Size());
|
||||||
|
|
||||||
|
for (; i < m; i++) {
|
||||||
|
if (a[i] != b[i]) {
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total += a.Size() - i;
|
||||||
|
total += b.Size() - i;
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xoff_t CmpDifferentBytes(const FileSpec &a, const FileSpec &b) {
|
||||||
|
Block block_a, block_b;
|
||||||
|
xoff_t total = 0;
|
||||||
|
typename FileSpec::iterator a_i(a), b_i(b);
|
||||||
|
|
||||||
|
for (; !a_i.Done() && !b_i.Done(); a_i.Next(), b_i.Next()) {
|
||||||
|
|
||||||
|
a_i.Get(&block_a);
|
||||||
|
b_i.Get(&block_b);
|
||||||
|
|
||||||
|
total += CmpDifferentBlockBytes(block_a, block_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; !a_i.Done(); a_i.Next()) {
|
||||||
|
total += a_i.BytesOnBlock();
|
||||||
|
}
|
||||||
|
for (; !b_i.Done(); b_i.Next()) {
|
||||||
|
total += b_i.BytesOnBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t CmpDifferentBlockBytesAtOffset(const Block &a,
|
||||||
|
const FileSpec &b_spec,
|
||||||
|
xoff_t offset) {
|
||||||
|
Block b;
|
||||||
|
size_t size = a.Size();
|
||||||
|
CHECK_LE(offset, b_spec.Size());
|
||||||
|
if (b_spec.Size() < offset + size) {
|
||||||
|
size = b_spec.Size() - offset;
|
||||||
|
}
|
||||||
|
b_spec.Get(&b, offset, size);
|
||||||
|
return CmpDifferentBlockBytes(a, b);
|
||||||
|
}
|
87
lib/xdelta3/testing/delta.h
Normal file
87
lib/xdelta3/testing/delta.h
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: C++ -*-
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Delta {
|
||||||
|
public:
|
||||||
|
Delta(const Block &block) {
|
||||||
|
int ret;
|
||||||
|
xd3_config config;
|
||||||
|
memset(&stream_, 0, sizeof (stream_));
|
||||||
|
memset(&config, 0, sizeof (config));
|
||||||
|
|
||||||
|
xd3_init_config(&config, XD3_SKIP_EMIT | XD3_ADLER32_NOVER);
|
||||||
|
|
||||||
|
CHECK_EQ(0, xd3_config_stream (&stream_, &config));
|
||||||
|
|
||||||
|
xd3_avail_input (&stream_, block.Data(), block.Size());
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
while (!done) {
|
||||||
|
ret = xd3_decode_input(&stream_);
|
||||||
|
|
||||||
|
switch (ret) {
|
||||||
|
case XD3_INPUT:
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
case XD3_OUTPUT:
|
||||||
|
CHECK_EQ(0, xd3_whole_append_window (&stream_));
|
||||||
|
break;
|
||||||
|
case XD3_GOTHEADER:
|
||||||
|
case XD3_WINSTART:
|
||||||
|
case XD3_WINFINISH:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cerr << "decode: " << done;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~Delta() {
|
||||||
|
xd3_free_stream(&stream_);
|
||||||
|
}
|
||||||
|
|
||||||
|
xoff_t AddedBytes() const {
|
||||||
|
return stream_.whole_target.addslen;
|
||||||
|
}
|
||||||
|
|
||||||
|
xoff_t Windows() const {
|
||||||
|
return stream_.whole_target.wininfolen;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: This does not benefit from -Wformat= checking, due to the
|
||||||
|
// enclosing template. Further, it was not used.
|
||||||
|
// void Print() const {
|
||||||
|
// for (size_t i = 0; i < stream_.whole_target.instlen; i++) {
|
||||||
|
// xd3_winst &winst = stream_.whole_target.inst[i];
|
||||||
|
// switch (winst.type) {
|
||||||
|
// case XD3_RUN:
|
||||||
|
// DP(RINT, "%" Q "u run %" W "u\n", winst.position, winst.size);
|
||||||
|
// break;
|
||||||
|
// case XD3_ADD:
|
||||||
|
// DP(RINT "%" Q "u add %" W "u\n", winst.position, winst.size);
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// DP(RINT "%" Q "u copy %" W "u @ %" Q "u (mode %u)\n",
|
||||||
|
// winst.position, winst.size, winst.addr, winst.mode);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
private:
|
||||||
|
xd3_stream stream_;
|
||||||
|
};
|
399
lib/xdelta3/testing/file.h
Normal file
399
lib/xdelta3/testing/file.h
Normal file
|
@ -0,0 +1,399 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: C++ -*-
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
class Block;
|
||||||
|
class BlockIterator;
|
||||||
|
class TmpFile;
|
||||||
|
|
||||||
|
class Block {
|
||||||
|
public:
|
||||||
|
Block()
|
||||||
|
: data_(NULL),
|
||||||
|
data_size_(0),
|
||||||
|
size_(0) { }
|
||||||
|
|
||||||
|
~Block() {
|
||||||
|
if (data_) {
|
||||||
|
delete [] data_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Size() const {
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t operator[](size_t i) const {
|
||||||
|
CHECK_LT(i, size_);
|
||||||
|
return data_[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* Data() const {
|
||||||
|
if (data_ == NULL) {
|
||||||
|
CHECK_EQ(0, size_);
|
||||||
|
data_size_ = 1;
|
||||||
|
data_ = new uint8_t[1];
|
||||||
|
}
|
||||||
|
return data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For writing to blocks
|
||||||
|
void Append(const uint8_t *data, size_t size) {
|
||||||
|
if (data_ == NULL) {
|
||||||
|
CHECK_EQ(0, size_);
|
||||||
|
CHECK_EQ(0, data_size_);
|
||||||
|
data_ = new uint8_t[Constants::BLOCK_SIZE];
|
||||||
|
data_size_ = Constants::BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size_ + size > data_size_) {
|
||||||
|
uint8_t *tmp = data_;
|
||||||
|
while (size_ + size > data_size_) {
|
||||||
|
data_size_ *= 2;
|
||||||
|
}
|
||||||
|
data_ = new uint8_t[data_size_];
|
||||||
|
memcpy(data_, tmp, size_);
|
||||||
|
delete [] tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(data_ + size_, data, size);
|
||||||
|
size_ += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For cleaing a block
|
||||||
|
void Reset() {
|
||||||
|
size_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: This does not benefit from -Wformat= checking, due to the
|
||||||
|
// enclosing template. Further, it was not used.
|
||||||
|
// void Print() const {
|
||||||
|
// xoff_t pos = 0;
|
||||||
|
// for (size_t i = 0; i < Size(); i++) {
|
||||||
|
// if (pos % 16 == 0) {
|
||||||
|
// DP(RINT "%5" Q "x: ", pos);
|
||||||
|
// }
|
||||||
|
// DP(RINT "%02x ", (*this)[i]);
|
||||||
|
// if (pos % 16 == 15) {
|
||||||
|
// DP(RINT "\n");
|
||||||
|
// }
|
||||||
|
// pos++;
|
||||||
|
// }
|
||||||
|
// DP(RINT "\n");
|
||||||
|
// }
|
||||||
|
|
||||||
|
void WriteTmpFile(TmpFile *f) const {
|
||||||
|
f->Append(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSize(size_t size) {
|
||||||
|
uint8_t *t = NULL;
|
||||||
|
if (data_size_ < size) {
|
||||||
|
if (data_) {
|
||||||
|
t = data_;
|
||||||
|
}
|
||||||
|
data_ = new uint8_t[size];
|
||||||
|
data_size_ = size;
|
||||||
|
}
|
||||||
|
if (t && size < size_) {
|
||||||
|
memcpy(data_, t, size);
|
||||||
|
}
|
||||||
|
delete [] t;
|
||||||
|
size_ = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class BlockIterator;
|
||||||
|
|
||||||
|
mutable uint8_t *data_;
|
||||||
|
mutable size_t data_size_;
|
||||||
|
size_t size_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileSpec {
|
||||||
|
public:
|
||||||
|
FileSpec(MTRandom *rand)
|
||||||
|
: rand_(rand) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates a file with a known size
|
||||||
|
void GenerateFixedSize(xoff_t size) {
|
||||||
|
Reset();
|
||||||
|
|
||||||
|
for (xoff_t p = 0; p < size; ) {
|
||||||
|
xoff_t t = min(Constants::BLOCK_SIZE, size - p);
|
||||||
|
table_.insert(make_pair(p, Segment(t, rand_)));
|
||||||
|
p += t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates a file with exponential-random distributed size
|
||||||
|
void GenerateRandomSize(xoff_t mean) {
|
||||||
|
GenerateFixedSize(rand_->ExpRand(mean));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the size of the file
|
||||||
|
xoff_t Size() const {
|
||||||
|
if (table_.empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ConstSegmentMapIterator i = --table_.end();
|
||||||
|
return i->first + i->second.Size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of blocks
|
||||||
|
xoff_t Blocks(size_t blksize = Constants::BLOCK_SIZE) const {
|
||||||
|
if (table_.empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ((Size() - 1) / blksize) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of segments
|
||||||
|
xoff_t Segments() const {
|
||||||
|
return table_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a mutation according to "what".
|
||||||
|
void ModifyTo(const Mutator &mutator,
|
||||||
|
FileSpec *modify) const {
|
||||||
|
modify->Reset();
|
||||||
|
mutator.Mutate(&modify->table_, &table_, rand_);
|
||||||
|
modify->CheckSegments();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckSegments() const {
|
||||||
|
for (ConstSegmentMapIterator iter(table_.begin());
|
||||||
|
iter != table_.end(); ) {
|
||||||
|
ConstSegmentMapIterator iter0(iter++);
|
||||||
|
if (iter == table_.end()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CHECK_EQ(iter0->first + iter0->second.Size(), iter->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() {
|
||||||
|
table_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Print() const {
|
||||||
|
for (ConstSegmentMapIterator iter(table_.begin());
|
||||||
|
iter != table_.end();
|
||||||
|
++iter) {
|
||||||
|
const Segment &seg = iter->second;
|
||||||
|
cerr << "Segment at " << iter->first
|
||||||
|
<< " (" << seg.ToString() << ")" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintData() const {
|
||||||
|
Block block;
|
||||||
|
for (BlockIterator iter(*this); !iter.Done(); iter.Next()) {
|
||||||
|
iter.Get(&block);
|
||||||
|
block.Print();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteTmpFile(TmpFile *f) const {
|
||||||
|
Block block;
|
||||||
|
for (BlockIterator iter(*this); !iter.Done(); iter.Next()) {
|
||||||
|
iter.Get(&block);
|
||||||
|
f->Append(&block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Get(Block *block, xoff_t offset, size_t size) const {
|
||||||
|
size_t got = 0;
|
||||||
|
block->SetSize(size);
|
||||||
|
|
||||||
|
ConstSegmentMapIterator pos = table_.upper_bound(offset);
|
||||||
|
if (pos == table_.begin()) {
|
||||||
|
CHECK_EQ(0, Size());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
--pos;
|
||||||
|
|
||||||
|
while (got < size) {
|
||||||
|
CHECK(pos != table_.end());
|
||||||
|
CHECK_GE(offset, pos->first);
|
||||||
|
|
||||||
|
const Segment &seg = pos->second;
|
||||||
|
|
||||||
|
// The position of this segment may start before this block starts,
|
||||||
|
// and then the position of the data may be offset from the seeding
|
||||||
|
// position.
|
||||||
|
size_t seg_offset = offset - pos->first;
|
||||||
|
size_t advance = min(seg.Size() - seg_offset,
|
||||||
|
size - got);
|
||||||
|
|
||||||
|
seg.Fill(seg_offset, advance, block->Data() + got);
|
||||||
|
|
||||||
|
got += advance;
|
||||||
|
offset += advance;
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef BlockIterator iterator;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class BlockIterator;
|
||||||
|
|
||||||
|
MTRandom *rand_;
|
||||||
|
SegmentMap table_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BlockIterator {
|
||||||
|
public:
|
||||||
|
explicit BlockIterator(const FileSpec& spec)
|
||||||
|
: spec_(spec),
|
||||||
|
blkno_(0),
|
||||||
|
blksize_(Constants::BLOCK_SIZE) { }
|
||||||
|
|
||||||
|
BlockIterator(const FileSpec& spec,
|
||||||
|
size_t blksize)
|
||||||
|
: spec_(spec),
|
||||||
|
blkno_(0),
|
||||||
|
blksize_(blksize) { }
|
||||||
|
|
||||||
|
bool Done() const {
|
||||||
|
return blkno_ >= spec_.Blocks(blksize_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Next() {
|
||||||
|
blkno_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
xoff_t Blkno() const {
|
||||||
|
return blkno_;
|
||||||
|
}
|
||||||
|
|
||||||
|
xoff_t Blocks() const {
|
||||||
|
return spec_.Blocks(blksize_);
|
||||||
|
}
|
||||||
|
|
||||||
|
xoff_t Offset() const {
|
||||||
|
return blkno_ * blksize_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBlock(xoff_t blkno) {
|
||||||
|
CHECK_LE(blkno, Blocks());
|
||||||
|
blkno_ = blkno;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Get(Block *block) const {
|
||||||
|
spec_.Get(block, blkno_ * blksize_, BytesOnBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t BytesOnBlock() const {
|
||||||
|
xoff_t blocks = spec_.Blocks(blksize_);
|
||||||
|
xoff_t size = spec_.Size();
|
||||||
|
|
||||||
|
DCHECK((blkno_ < blocks) ||
|
||||||
|
(blkno_ == blocks && size % blksize_ == 0));
|
||||||
|
|
||||||
|
if (blkno_ == blocks) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (blkno_ + 1 == blocks) {
|
||||||
|
return ((size - 1) % blksize_) + 1;
|
||||||
|
}
|
||||||
|
return blksize_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t BlockSize() const {
|
||||||
|
return blksize_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const FileSpec& spec_;
|
||||||
|
xoff_t blkno_;
|
||||||
|
size_t blksize_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExtFile {
|
||||||
|
public:
|
||||||
|
ExtFile() {
|
||||||
|
static int static_counter = 0;
|
||||||
|
pid_t pid = getpid();
|
||||||
|
char buf[64];
|
||||||
|
xoff_t xpid = pid;
|
||||||
|
snprintf(buf, 64, "/tmp/regtest.%" Q "u.%d", xpid, static_counter++);
|
||||||
|
filename_.append(buf);
|
||||||
|
unlink(filename_.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
~ExtFile() {
|
||||||
|
unlink(filename_.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* Name() const {
|
||||||
|
return filename_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether a real file matches a file spec.
|
||||||
|
bool EqualsSpec(const FileSpec &spec) const {
|
||||||
|
main_file t;
|
||||||
|
main_file_init(&t);
|
||||||
|
CHECK_EQ(0, main_file_open(&t, Name(), XO_READ));
|
||||||
|
|
||||||
|
Block tblock;
|
||||||
|
Block sblock;
|
||||||
|
for (BlockIterator iter(spec); !iter.Done(); iter.Next()) {
|
||||||
|
iter.Get(&sblock);
|
||||||
|
tblock.SetSize(sblock.Size());
|
||||||
|
size_t tread;
|
||||||
|
CHECK_EQ(0, main_file_read(&t,
|
||||||
|
tblock.Data(),
|
||||||
|
tblock.Size(), &tread, "read failed"));
|
||||||
|
CHECK_EQ(0, CmpDifferentBlockBytes(tblock, sblock));
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_EQ(0, main_file_close(&t));
|
||||||
|
main_file_cleanup(&t);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
string filename_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TmpFile : public ExtFile {
|
||||||
|
public:
|
||||||
|
TmpFile() {
|
||||||
|
main_file_init(&file_);
|
||||||
|
CHECK_EQ(0, main_file_open(&file_, Name(), XO_WRITE));
|
||||||
|
}
|
||||||
|
|
||||||
|
~TmpFile() {
|
||||||
|
main_file_cleanup(&file_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Append(const Block *block) {
|
||||||
|
CHECK_EQ(0, main_file_write(&file_,
|
||||||
|
block->Data(), block->Size(),
|
||||||
|
"tmpfile write failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* Name() const {
|
||||||
|
if (main_file_isopen(&file_)) {
|
||||||
|
CHECK_EQ(0, main_file_close(&file_));
|
||||||
|
}
|
||||||
|
return ExtFile::Name();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable main_file file_;
|
||||||
|
};
|
400
lib/xdelta3/testing/modify.h
Normal file
400
lib/xdelta3/testing/modify.h
Normal file
|
@ -0,0 +1,400 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: C++ -*-
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Mutator {
|
||||||
|
public:
|
||||||
|
virtual ~Mutator() { }
|
||||||
|
virtual void Mutate(SegmentMap *table,
|
||||||
|
const SegmentMap *source_table,
|
||||||
|
MTRandom *rand) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Change {
|
||||||
|
public:
|
||||||
|
enum Kind {
|
||||||
|
MODIFY = 1, // Mutate a certain range w/ random or supplied data
|
||||||
|
ADD = 2, // Insert random or supplied data
|
||||||
|
DELRANGE = 3, // Delete a specified range of data
|
||||||
|
COPY = 4, // Copy from one region, inserting elsewhere
|
||||||
|
MOVE = 5, // Copy then delete copied-from range
|
||||||
|
COPYOVER = 6 // Copy then delete copied-to range
|
||||||
|
|
||||||
|
// ADD, DELRANGE, and COPY change the file size
|
||||||
|
// MODIFY, MOVE, COPYOVER preserve the file size
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constructor for modify, add, delete.
|
||||||
|
Change(Kind kind0, xoff_t size0, xoff_t addr1_0)
|
||||||
|
: kind(kind0),
|
||||||
|
size(size0),
|
||||||
|
addr1(addr1_0),
|
||||||
|
addr2(0),
|
||||||
|
insert(NULL) {
|
||||||
|
CHECK(kind != MOVE && kind != COPY && kind != COPYOVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor for modify, add w/ provided data.
|
||||||
|
Change(Kind kind0, xoff_t size0, xoff_t addr1_0, Segment *insert0)
|
||||||
|
: kind(kind0),
|
||||||
|
size(size0),
|
||||||
|
addr1(addr1_0),
|
||||||
|
addr2(0),
|
||||||
|
insert(insert0) {
|
||||||
|
CHECK(kind != MOVE && kind != COPY && kind != COPYOVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor for move, copy, overwrite
|
||||||
|
Change(Kind kind0, xoff_t size0, xoff_t addr1_0, xoff_t addr2_0)
|
||||||
|
: kind(kind0),
|
||||||
|
size(size0),
|
||||||
|
addr1(addr1_0),
|
||||||
|
addr2(addr2_0),
|
||||||
|
insert(NULL) {
|
||||||
|
CHECK(kind == MOVE || kind == COPY || kind == COPYOVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
Kind kind;
|
||||||
|
xoff_t size;
|
||||||
|
xoff_t addr1;
|
||||||
|
xoff_t addr2;
|
||||||
|
Segment *insert; // For modify and/or add
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef list<Change> ChangeList;
|
||||||
|
typedef typename ChangeList::const_iterator ConstChangeListIterator;
|
||||||
|
typedef typename ChangeList::iterator ChangeListIterator;
|
||||||
|
|
||||||
|
class ChangeListMutator : public Mutator {
|
||||||
|
public:
|
||||||
|
ChangeListMutator(const ChangeList &cl)
|
||||||
|
: cl_(cl) { }
|
||||||
|
|
||||||
|
ChangeListMutator() { }
|
||||||
|
|
||||||
|
void Mutate(SegmentMap *table,
|
||||||
|
const SegmentMap *source_table,
|
||||||
|
MTRandom *rand) const {
|
||||||
|
// The speed of processing gigabytes of data is so slow compared with
|
||||||
|
// these table-copy operations, no attempt to make this fast.
|
||||||
|
SegmentMap tmp;
|
||||||
|
|
||||||
|
for (ConstChangeListIterator iter(cl_.begin());
|
||||||
|
iter != cl_.end(); ++iter) {
|
||||||
|
const Change &ch = *iter;
|
||||||
|
tmp.clear();
|
||||||
|
Mutate(ch, &tmp, source_table, rand);
|
||||||
|
tmp.swap(*table);
|
||||||
|
source_table = table;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Mutate(const Change &ch,
|
||||||
|
SegmentMap *table,
|
||||||
|
const SegmentMap *source_table,
|
||||||
|
MTRandom *rand) {
|
||||||
|
switch (ch.kind) {
|
||||||
|
case Change::ADD:
|
||||||
|
AddChange(ch, table, source_table, rand);
|
||||||
|
break;
|
||||||
|
case Change::MODIFY:
|
||||||
|
ModifyChange(ch, table, source_table, rand);
|
||||||
|
break;
|
||||||
|
case Change::DELRANGE:
|
||||||
|
DeleteChange(ch, table, source_table, rand);
|
||||||
|
break;
|
||||||
|
case Change::COPY:
|
||||||
|
CopyChange(ch, table, source_table, rand);
|
||||||
|
break;
|
||||||
|
case Change::MOVE:
|
||||||
|
MoveChange(ch, table, source_table, rand);
|
||||||
|
break;
|
||||||
|
case Change::COPYOVER:
|
||||||
|
OverwriteChange(ch, table, source_table, rand);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ModifyChange(const Change &ch,
|
||||||
|
SegmentMap *table,
|
||||||
|
const SegmentMap *source_table,
|
||||||
|
MTRandom *rand) {
|
||||||
|
xoff_t m_start = ch.addr1;
|
||||||
|
xoff_t m_end = m_start + ch.size;
|
||||||
|
xoff_t i_start = 0;
|
||||||
|
xoff_t i_end = 0;
|
||||||
|
|
||||||
|
for (ConstSegmentMapIterator iter(source_table->begin());
|
||||||
|
iter != source_table->end();
|
||||||
|
++iter) {
|
||||||
|
const Segment &seg = iter->second;
|
||||||
|
i_start = iter->first;
|
||||||
|
i_end = i_start + seg.Size();
|
||||||
|
|
||||||
|
if (i_end <= m_start || i_start >= m_end) {
|
||||||
|
table->insert(table->end(), make_pair(i_start, seg));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i_start < m_start) {
|
||||||
|
table->insert(table->end(),
|
||||||
|
make_pair(i_start,
|
||||||
|
seg.Subseg(0, m_start - i_start)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the entire segment, even though it may extend into later
|
||||||
|
// segments. This condition avoids inserting it during later
|
||||||
|
// segments.
|
||||||
|
if (m_start >= i_start) {
|
||||||
|
if (ch.insert != NULL) {
|
||||||
|
table->insert(table->end(), make_pair(m_start, *ch.insert));
|
||||||
|
} else {
|
||||||
|
Segment part(m_end - m_start, rand);
|
||||||
|
table->insert(table->end(), make_pair(m_start, part));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i_end > m_end) {
|
||||||
|
table->insert(table->end(),
|
||||||
|
make_pair(m_end,
|
||||||
|
seg.Subseg(m_end - i_start, i_end - m_end)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This check verifies that the modify does not extend past the
|
||||||
|
// source_table EOF.
|
||||||
|
CHECK_LE(m_end, i_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void AddChange(const Change &ch,
|
||||||
|
SegmentMap *table,
|
||||||
|
const SegmentMap *source_table,
|
||||||
|
MTRandom *rand) {
|
||||||
|
xoff_t m_start = ch.addr1;
|
||||||
|
xoff_t i_start = 0;
|
||||||
|
xoff_t i_end = 0;
|
||||||
|
|
||||||
|
for (ConstSegmentMapIterator iter(source_table->begin());
|
||||||
|
iter != source_table->end();
|
||||||
|
++iter) {
|
||||||
|
const Segment &seg = iter->second;
|
||||||
|
i_start = iter->first;
|
||||||
|
i_end = i_start + seg.Size();
|
||||||
|
|
||||||
|
if (i_end <= m_start) {
|
||||||
|
table->insert(table->end(), make_pair(i_start, seg));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i_start > m_start) {
|
||||||
|
table->insert(table->end(), make_pair(i_start + ch.size, seg));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i_start < m_start) {
|
||||||
|
table->insert(table->end(),
|
||||||
|
make_pair(i_start,
|
||||||
|
seg.Subseg(0, m_start - i_start)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch.insert != NULL) {
|
||||||
|
table->insert(table->end(), make_pair(m_start, *ch.insert));
|
||||||
|
} else {
|
||||||
|
Segment addseg(ch.size, rand);
|
||||||
|
table->insert(table->end(), make_pair(m_start, addseg));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_start < i_end) {
|
||||||
|
table->insert(table->end(),
|
||||||
|
make_pair(m_start + ch.size,
|
||||||
|
seg.Subseg(m_start - i_start,
|
||||||
|
i_end - m_start)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_LE(m_start, i_end);
|
||||||
|
|
||||||
|
// Special case for add at end-of-input.
|
||||||
|
if (m_start == i_end) {
|
||||||
|
Segment addseg(ch.size, rand);
|
||||||
|
table->insert(table->end(), make_pair(m_start, addseg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DeleteChange(const Change &ch,
|
||||||
|
SegmentMap *table,
|
||||||
|
const SegmentMap *source_table,
|
||||||
|
MTRandom *rand) {
|
||||||
|
xoff_t m_start = ch.addr1;
|
||||||
|
xoff_t m_end = m_start + ch.size;
|
||||||
|
xoff_t i_start = 0;
|
||||||
|
xoff_t i_end = 0;
|
||||||
|
|
||||||
|
for (ConstSegmentMapIterator iter(source_table->begin());
|
||||||
|
iter != source_table->end();
|
||||||
|
++iter) {
|
||||||
|
const Segment &seg = iter->second;
|
||||||
|
i_start = iter->first;
|
||||||
|
i_end = i_start + seg.Size();
|
||||||
|
|
||||||
|
if (i_end <= m_start) {
|
||||||
|
table->insert(table->end(), make_pair(i_start, seg));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i_start >= m_end) {
|
||||||
|
table->insert(table->end(), make_pair(i_start - ch.size, seg));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i_start < m_start) {
|
||||||
|
table->insert(table->end(),
|
||||||
|
make_pair(i_start,
|
||||||
|
seg.Subseg(0, m_start - i_start)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i_end > m_end) {
|
||||||
|
table->insert(table->end(),
|
||||||
|
make_pair(m_end - ch.size,
|
||||||
|
seg.Subseg(m_end - i_start, i_end - m_end)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_LT(m_start, i_end);
|
||||||
|
CHECK_LE(m_end, i_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A move is a copy followed by delete of the copied-from range.
|
||||||
|
static void MoveChange(const Change &ch,
|
||||||
|
SegmentMap *table,
|
||||||
|
const SegmentMap *source_table,
|
||||||
|
MTRandom *rand) {
|
||||||
|
SegmentMap tmp;
|
||||||
|
CHECK_NE(ch.addr1, ch.addr2);
|
||||||
|
CopyChange(ch, &tmp, source_table, rand);
|
||||||
|
Change d(Change::DELRANGE, ch.size,
|
||||||
|
ch.addr1 < ch.addr2 ? ch.addr1 : ch.addr1 + ch.size);
|
||||||
|
DeleteChange(d, table, &tmp, rand);
|
||||||
|
}
|
||||||
|
|
||||||
|
// An overwrite is a copy followed by a delete of the copied-to range.
|
||||||
|
static void OverwriteChange(const Change &ch,
|
||||||
|
SegmentMap *table,
|
||||||
|
const SegmentMap *source_table,
|
||||||
|
MTRandom *rand) {
|
||||||
|
SegmentMap tmp;
|
||||||
|
CHECK_NE(ch.addr1, ch.addr2);
|
||||||
|
CopyChange(ch, &tmp, source_table, rand);
|
||||||
|
Change d(Change::DELRANGE, ch.size, ch.addr2 + ch.size);
|
||||||
|
DeleteChange(d, table, &tmp, rand);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CopyChange(const Change &ch,
|
||||||
|
SegmentMap *table,
|
||||||
|
const SegmentMap *source_table,
|
||||||
|
MTRandom *ignore) {
|
||||||
|
xoff_t m_start = ch.addr2;
|
||||||
|
xoff_t c_start = ch.addr1;
|
||||||
|
xoff_t i_start = 0;
|
||||||
|
xoff_t i_end = 0;
|
||||||
|
|
||||||
|
// Like AddChange() with AppendCopy instead of a random segment.
|
||||||
|
for (ConstSegmentMapIterator iter(source_table->begin());
|
||||||
|
iter != source_table->end();
|
||||||
|
++iter) {
|
||||||
|
const Segment &seg = iter->second;
|
||||||
|
i_start = iter->first;
|
||||||
|
i_end = i_start + seg.Size();
|
||||||
|
|
||||||
|
if (i_end <= m_start) {
|
||||||
|
table->insert(table->end(), make_pair(i_start, seg));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i_start > m_start) {
|
||||||
|
table->insert(table->end(), make_pair(i_start + ch.size, seg));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i_start < m_start) {
|
||||||
|
table->insert(table->end(),
|
||||||
|
make_pair(i_start,
|
||||||
|
seg.Subseg(0, m_start - i_start)));
|
||||||
|
}
|
||||||
|
|
||||||
|
AppendCopy(table, source_table, c_start, m_start, ch.size);
|
||||||
|
|
||||||
|
if (m_start < i_end) {
|
||||||
|
table->insert(table->end(),
|
||||||
|
make_pair(m_start + ch.size,
|
||||||
|
seg.Subseg(m_start - i_start, i_end - m_start)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_LE(m_start, i_end);
|
||||||
|
|
||||||
|
// Special case for copy to end-of-input.
|
||||||
|
if (m_start == i_end) {
|
||||||
|
AppendCopy(table, source_table, c_start, m_start, ch.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void AppendCopy(SegmentMap *table,
|
||||||
|
const SegmentMap *source_table,
|
||||||
|
xoff_t copy_offset,
|
||||||
|
xoff_t append_offset,
|
||||||
|
xoff_t length) {
|
||||||
|
ConstSegmentMapIterator pos(source_table->upper_bound(copy_offset));
|
||||||
|
--pos;
|
||||||
|
xoff_t got = 0;
|
||||||
|
|
||||||
|
while (got < length) {
|
||||||
|
size_t seg_offset = copy_offset - pos->first;
|
||||||
|
size_t advance = min(pos->second.Size() - seg_offset,
|
||||||
|
(size_t)(length - got));
|
||||||
|
|
||||||
|
table->insert(table->end(),
|
||||||
|
make_pair(append_offset,
|
||||||
|
pos->second.Subseg(seg_offset,
|
||||||
|
advance)));
|
||||||
|
|
||||||
|
got += advance;
|
||||||
|
copy_offset += advance;
|
||||||
|
append_offset += advance;
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChangeList* Changes() {
|
||||||
|
return &cl_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChangeList* Changes() const {
|
||||||
|
return &cl_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ChangeList cl_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Modify1stByte : public Mutator {
|
||||||
|
public:
|
||||||
|
void Mutate(SegmentMap *table,
|
||||||
|
const SegmentMap *source_table,
|
||||||
|
MTRandom *rand) const {
|
||||||
|
ChangeListMutator::Mutate(Change(Change::MODIFY, 1, 0),
|
||||||
|
table, source_table, rand);
|
||||||
|
}
|
||||||
|
};
|
157
lib/xdelta3/testing/random.h
Normal file
157
lib/xdelta3/testing/random.h
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: C++ -*-
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef MT_LEN
|
||||||
|
#undef MT_IA
|
||||||
|
class MTRandom {
|
||||||
|
public:
|
||||||
|
enum Constants {
|
||||||
|
MT_LEN = 624,
|
||||||
|
MT_IA = 397
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t TEST_SEED1;
|
||||||
|
static const uint32_t UPPER_MASK;
|
||||||
|
static const uint32_t LOWER_MASK;
|
||||||
|
static const uint32_t MATRIX_A;
|
||||||
|
|
||||||
|
MTRandom() {
|
||||||
|
Init(TEST_SEED1);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit MTRandom(uint32_t seed) {
|
||||||
|
Init(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This Mersenne Twister code is attributed to Michael Brundage. Thanks!
|
||||||
|
* http://www.qbrundage.com/michaelb/pubs/essays/random_number_generation.html
|
||||||
|
*/
|
||||||
|
uint32_t Rand32 () {
|
||||||
|
uint32_t y;
|
||||||
|
static unsigned long mag01[2] = {
|
||||||
|
0 , MATRIX_A
|
||||||
|
};
|
||||||
|
|
||||||
|
if (mt_index_ >= MT_LEN) {
|
||||||
|
int kk;
|
||||||
|
|
||||||
|
for (kk = 0; kk < MT_LEN - MT_IA; kk++) {
|
||||||
|
y = (mt_buffer_[kk] & UPPER_MASK) | (mt_buffer_[kk + 1] & LOWER_MASK);
|
||||||
|
mt_buffer_[kk] = mt_buffer_[kk + MT_IA] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||||
|
}
|
||||||
|
for (;kk < MT_LEN - 1; kk++) {
|
||||||
|
y = (mt_buffer_[kk] & UPPER_MASK) | (mt_buffer_[kk + 1] & LOWER_MASK);
|
||||||
|
mt_buffer_[kk] = mt_buffer_[kk + (MT_IA - MT_LEN)] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||||
|
}
|
||||||
|
y = (mt_buffer_[MT_LEN - 1] & UPPER_MASK) | (mt_buffer_[0] & LOWER_MASK);
|
||||||
|
mt_buffer_[MT_LEN - 1] = mt_buffer_[MT_IA - 1] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||||
|
|
||||||
|
mt_index_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
y = mt_buffer_[mt_index_++];
|
||||||
|
|
||||||
|
y ^= (y >> 11);
|
||||||
|
y ^= (y << 7) & 0x9d2c5680UL;
|
||||||
|
y ^= (y << 15) & 0xefc60000UL;
|
||||||
|
y ^= (y >> 18);
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ExpRand32(uint32_t mean) {
|
||||||
|
double mean_d = mean;
|
||||||
|
double erand = log (1.0 / (Rand32() / (double)UINT32_MAX));
|
||||||
|
uint32_t x = (uint32_t) (mean_d * erand + 0.5);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t Rand64() {
|
||||||
|
return ((uint64_t)Rand32() << 32) | Rand32();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t ExpRand64(uint64_t mean) {
|
||||||
|
double mean_d = mean;
|
||||||
|
double erand = log (1.0 / (Rand64() / (double)UINT32_MAX));
|
||||||
|
uint64_t x = (uint64_t) (mean_d * erand + 0.5);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T Rand() {
|
||||||
|
switch (sizeof(T)) {
|
||||||
|
case sizeof(uint32_t):
|
||||||
|
return Rand32();
|
||||||
|
case sizeof(uint64_t):
|
||||||
|
return Rand64();
|
||||||
|
default:
|
||||||
|
cerr << "Invalid sizeof T" << endl;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T ExpRand(T mean) {
|
||||||
|
switch (sizeof(T)) {
|
||||||
|
case sizeof(uint32_t):
|
||||||
|
return ExpRand32(mean);
|
||||||
|
case sizeof(uint64_t):
|
||||||
|
return ExpRand64(mean);
|
||||||
|
default:
|
||||||
|
cerr << "Invalid sizeof T" << endl;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Init(uint32_t seed) {
|
||||||
|
mt_buffer_[0] = seed;
|
||||||
|
mt_index_ = MT_LEN;
|
||||||
|
for (int i = 1; i < MT_LEN; i++) {
|
||||||
|
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
||||||
|
/* In the previous versions, MSBs of the seed affect */
|
||||||
|
/* only MSBs of the array mt[]. */
|
||||||
|
/* 2002/01/09 modified by Makoto Matsumoto */
|
||||||
|
mt_buffer_[i] =
|
||||||
|
(1812433253UL * (mt_buffer_[i-1] ^ (mt_buffer_[i-1] >> 30)) + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int mt_index_;
|
||||||
|
uint32_t mt_buffer_[MT_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32_t MTRandom::TEST_SEED1 = 5489UL;
|
||||||
|
const uint32_t MTRandom::UPPER_MASK = 0x80000000;
|
||||||
|
const uint32_t MTRandom::LOWER_MASK = 0x7FFFFFFF;
|
||||||
|
const uint32_t MTRandom::MATRIX_A = 0x9908B0DF;
|
||||||
|
|
||||||
|
class MTRandom8 {
|
||||||
|
public:
|
||||||
|
MTRandom8(MTRandom *rand)
|
||||||
|
: rand_(rand) {
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Rand8() {
|
||||||
|
uint32_t r = rand_->Rand32();
|
||||||
|
|
||||||
|
// TODO: make this use a single byte at a time?
|
||||||
|
return (r & 0xff) ^ (r >> 7) ^ (r >> 15) ^ (r >> 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MTRandom *rand_;
|
||||||
|
};
|
1321
lib/xdelta3/testing/regtest.cc
Normal file
1321
lib/xdelta3/testing/regtest.cc
Normal file
File diff suppressed because it is too large
Load diff
17
lib/xdelta3/testing/regtest_c.c
Normal file
17
lib/xdelta3/testing/regtest_c.c
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
/* xdelta3 - delta compression tools and library
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../xdelta3.c"
|
2
lib/xdelta3/testing/run_release.sh
Normal file
2
lib/xdelta3/testing/run_release.sh
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/sh
|
||||||
|
(cd .. && ./run_release.sh)
|
112
lib/xdelta3/testing/segment.h
Normal file
112
lib/xdelta3/testing/segment.h
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: C++ -*-
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Segment {
|
||||||
|
public:
|
||||||
|
Segment(size_t size, MTRandom *rand)
|
||||||
|
: size_(size),
|
||||||
|
seed_(rand->Rand32()),
|
||||||
|
seed_offset_(0),
|
||||||
|
data_(NULL) {
|
||||||
|
CHECK_GT(size_, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Segment(size_t size, uint32_t seed)
|
||||||
|
: size_(size),
|
||||||
|
seed_(seed),
|
||||||
|
seed_offset_(0),
|
||||||
|
data_(NULL) {
|
||||||
|
CHECK_GT(size_, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Segment(size_t size, uint8_t *data)
|
||||||
|
: size_(size),
|
||||||
|
seed_(0),
|
||||||
|
seed_offset_(0),
|
||||||
|
data_(data) {
|
||||||
|
CHECK_GT(size_, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Size() const {
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Segment Subseg(size_t start, size_t size) const {
|
||||||
|
CHECK_LE(start + size, size_);
|
||||||
|
if (data_) {
|
||||||
|
return Segment(size, data_ + start);
|
||||||
|
} else {
|
||||||
|
return Segment(size, seed_, seed_offset_ + start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fill(size_t seg_offset, size_t size, uint8_t *data) const {
|
||||||
|
CHECK_LE(seg_offset + size, size_);
|
||||||
|
if (data_) {
|
||||||
|
memcpy(data, data_ + seg_offset, size);
|
||||||
|
} else {
|
||||||
|
size_t skip = seg_offset + seed_offset_;
|
||||||
|
MTRandom gen(seed_);
|
||||||
|
MTRandom8 gen8(&gen);
|
||||||
|
while (skip--) {
|
||||||
|
gen8.Rand8();
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
data[i] = gen8.Rand8();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string ToString() const {
|
||||||
|
string r;
|
||||||
|
if (data_) {
|
||||||
|
for (size_t i = 0; i < size_; i++) {
|
||||||
|
char buf[10];
|
||||||
|
sprintf(buf, "%02x ", data_[i]);
|
||||||
|
r.append(buf);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
char buf[256];
|
||||||
|
sprintf(buf, "size=%ld,seed=%ud,skip=%ld", size_, seed_, seed_offset_);
|
||||||
|
r.append(buf);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Used by Subseg()
|
||||||
|
Segment(size_t size, uint32_t seed, size_t seed_offset)
|
||||||
|
: size_(size),
|
||||||
|
seed_(seed),
|
||||||
|
seed_offset_(seed_offset),
|
||||||
|
data_(NULL) {
|
||||||
|
CHECK_GT(size_, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size_; // Size of this segment
|
||||||
|
|
||||||
|
// For random segments
|
||||||
|
uint32_t seed_; // Seed used for generating byte sequence
|
||||||
|
size_t seed_offset_; // Seed positions the sequence this many bytes
|
||||||
|
// before its beginning.
|
||||||
|
|
||||||
|
// For literal segments (data is not owned)
|
||||||
|
uint8_t *data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef map<xoff_t, Segment> SegmentMap;
|
||||||
|
typedef typename SegmentMap::const_iterator ConstSegmentMapIterator;
|
||||||
|
typedef typename SegmentMap::iterator SegmentMapIterator;
|
126
lib/xdelta3/testing/sizes.h
Normal file
126
lib/xdelta3/testing/sizes.h
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: C++ -*-
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
class SizeIterator {
|
||||||
|
public:
|
||||||
|
SizeIterator(MTRandom *rand, size_t howmany)
|
||||||
|
: rand_(rand),
|
||||||
|
count_(0),
|
||||||
|
fixed_(U::sizes),
|
||||||
|
fixed_size_(SIZEOF_ARRAY(U::sizes)),
|
||||||
|
howmany_(howmany) { }
|
||||||
|
|
||||||
|
T Get() {
|
||||||
|
if (count_ < fixed_size_) {
|
||||||
|
return fixed_[count_];
|
||||||
|
}
|
||||||
|
return rand_->Rand<T>() % U::max_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Done() {
|
||||||
|
return count_ >= fixed_size_ && count_ >= howmany_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Next() {
|
||||||
|
count_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MTRandom *rand_;
|
||||||
|
size_t count_;
|
||||||
|
T* fixed_;
|
||||||
|
size_t fixed_size_;
|
||||||
|
size_t howmany_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Small sizes
|
||||||
|
class SmallSizes {
|
||||||
|
public:
|
||||||
|
static size_t sizes[];
|
||||||
|
static size_t max_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t SmallSizes::sizes[] = {
|
||||||
|
0, 1, 128 / 4, 3333,
|
||||||
|
128 - (128 / 3),
|
||||||
|
128,
|
||||||
|
128 + (128 / 3),
|
||||||
|
2 * 128 - (128 / 3),
|
||||||
|
2 * 128,
|
||||||
|
2 * 128 + (128 / 3),
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t SmallSizes::max_value = 128 * 3;
|
||||||
|
|
||||||
|
// Large sizes
|
||||||
|
class LargeSizes {
|
||||||
|
public:
|
||||||
|
static size_t sizes[];
|
||||||
|
static size_t max_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t LargeSizes::sizes[] = {
|
||||||
|
1 << 20,
|
||||||
|
1 << 18,
|
||||||
|
1 << 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t LargeSizes::max_value = 1<<20;
|
||||||
|
|
||||||
|
// Base constants
|
||||||
|
struct BaseConstants {
|
||||||
|
static const size_t TEST_ROUNDS;
|
||||||
|
};
|
||||||
|
|
||||||
|
const size_t BaseConstants::TEST_ROUNDS = 10;
|
||||||
|
|
||||||
|
// Regtest<> arguments
|
||||||
|
struct SmallBlock : public BaseConstants {
|
||||||
|
static const xoff_t BLOCK_SIZE;
|
||||||
|
static const size_t WINDOW_SIZE;
|
||||||
|
typedef SmallSizes Sizes;
|
||||||
|
};
|
||||||
|
|
||||||
|
const xoff_t SmallBlock::BLOCK_SIZE = 1<<7;
|
||||||
|
const size_t SmallBlock::WINDOW_SIZE = 1<<7;
|
||||||
|
|
||||||
|
struct LargeBlock : public BaseConstants {
|
||||||
|
static const xoff_t BLOCK_SIZE;
|
||||||
|
static const size_t WINDOW_SIZE;
|
||||||
|
typedef LargeSizes Sizes;
|
||||||
|
};
|
||||||
|
|
||||||
|
const xoff_t LargeBlock::BLOCK_SIZE = (1 << 13);
|
||||||
|
const size_t LargeBlock::WINDOW_SIZE = (1 << 13);
|
||||||
|
|
||||||
|
struct MixedBlock : public BaseConstants {
|
||||||
|
static const xoff_t BLOCK_SIZE;
|
||||||
|
static const size_t WINDOW_SIZE;
|
||||||
|
typedef SmallSizes Sizes;
|
||||||
|
};
|
||||||
|
|
||||||
|
const xoff_t MixedBlock::BLOCK_SIZE = 1<<7;
|
||||||
|
const size_t MixedBlock::WINDOW_SIZE = 1<<8;
|
||||||
|
|
||||||
|
struct OversizeBlock : public BaseConstants {
|
||||||
|
static const xoff_t BLOCK_SIZE;
|
||||||
|
static const size_t WINDOW_SIZE;
|
||||||
|
typedef SmallSizes Sizes;
|
||||||
|
};
|
||||||
|
|
||||||
|
const xoff_t OversizeBlock::BLOCK_SIZE = 1<<8;
|
||||||
|
const size_t OversizeBlock::WINDOW_SIZE = 1<<7;
|
84
lib/xdelta3/testing/test.h
Normal file
84
lib/xdelta3/testing/test.h
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
/* xdelta3 - delta compression tools and library -*- Mode: C++ -*-
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "../xdelta3.h"
|
||||||
|
#include "../xdelta3-internal.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define CHECK_EQ(x,y) CHECK_OP(x,y,==)
|
||||||
|
#define CHECK_NE(x,y) CHECK_OP(x,y,!=)
|
||||||
|
#define CHECK_LT(x,y) CHECK_OP(x,y,<)
|
||||||
|
#define CHECK_GT(x,y) CHECK_OP(x,y,>)
|
||||||
|
#define CHECK_LE(x,y) CHECK_OP(x,y,<=)
|
||||||
|
#define CHECK_GE(x,y) CHECK_OP(x,y,>=)
|
||||||
|
|
||||||
|
#define CHECK_OP(x,y,OP) \
|
||||||
|
do { \
|
||||||
|
__typeof__(x) _x(x); \
|
||||||
|
__typeof__(x) _y(y); \
|
||||||
|
if (!(_x OP _y)) { \
|
||||||
|
cerr << __FILE__ << ":" << __LINE__ << " Check failed: " << #x " " #OP " " #y << endl; \
|
||||||
|
cerr << __FILE__ << ":" << __LINE__ << " {0} " << _x << endl; \
|
||||||
|
cerr << __FILE__ << ":" << __LINE__ << " {1} " << _y << endl; \
|
||||||
|
abort(); \
|
||||||
|
} } while (false)
|
||||||
|
#undef CHECK
|
||||||
|
#define CHECK(x) \
|
||||||
|
do {if (!(x)) { \
|
||||||
|
cerr << __FILE__ << ":" << __LINE__ << " Check failed: " << #x << endl; \
|
||||||
|
abort(); \
|
||||||
|
} } while (false)
|
||||||
|
|
||||||
|
#define DCHECK(x)
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
inline string CommandToString(const vector<const char*> &v) {
|
||||||
|
string s(v[0]);
|
||||||
|
for (size_t i = 1; i < v.size() && v[i] != NULL; i++) {
|
||||||
|
s.append(" ");
|
||||||
|
s.append(v[i]);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
using std::cerr;
|
||||||
|
using std::endl;
|
||||||
|
using std::ostream;
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
using std::map;
|
||||||
|
using std::pair;
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
using std::list;
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
pair<T, U> make_pair(const T& t, const U& u) {
|
||||||
|
return pair<T, U>(t, u);
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::min;
|
||||||
|
using std::max;
|
1264
lib/xdelta3/testing/xdelta3-regtest.py
Normal file
1264
lib/xdelta3/testing/xdelta3-regtest.py
Normal file
File diff suppressed because it is too large
Load diff
153
lib/xdelta3/testing/xdelta3-test.py
Normal file
153
lib/xdelta3/testing/xdelta3-test.py
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
#!/usr/bin/python2.7
|
||||||
|
# xdelta3 - delta compression tools and library -*- Mode: C++ -*-
|
||||||
|
# Copyright 2016 Joshua MacDonald
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import xdelta3
|
||||||
|
|
||||||
|
# the test data section is expected to be len('target')
|
||||||
|
source = 'source source input0 source source'
|
||||||
|
target = 'source source target source source'
|
||||||
|
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
print 'encode: basic ...'
|
||||||
|
result, patch = xdelta3.xd3_encode_memory(target, source, 50)
|
||||||
|
|
||||||
|
assert result == 0
|
||||||
|
assert len(patch) < len(source)
|
||||||
|
|
||||||
|
print 'encode: adler32 ...'
|
||||||
|
result, patch_adler32 = xdelta3.xd3_encode_memory(target, source, 50,
|
||||||
|
xdelta3.XD3_ADLER32)
|
||||||
|
|
||||||
|
assert result == 0
|
||||||
|
assert len(patch_adler32) < len(source)
|
||||||
|
assert len(patch_adler32) > len(patch)
|
||||||
|
|
||||||
|
print 'encode: secondary ...'
|
||||||
|
result, patch_djw = xdelta3.xd3_encode_memory(target, source, 50,
|
||||||
|
xdelta3.XD3_SEC_DJW)
|
||||||
|
|
||||||
|
assert result == 0
|
||||||
|
# secondary compression doesn't help
|
||||||
|
assert len(patch_djw) > len(patch)
|
||||||
|
|
||||||
|
print 'encode: exact ...'
|
||||||
|
result, ignore = xdelta3.xd3_encode_memory(target, source, len(patch))
|
||||||
|
|
||||||
|
assert result == 0
|
||||||
|
assert len(ignore) < len(source)
|
||||||
|
|
||||||
|
print 'encode: out of space ...'
|
||||||
|
result, ignore = xdelta3.xd3_encode_memory(target, source, len(patch) - 1)
|
||||||
|
|
||||||
|
assert result == 28
|
||||||
|
assert ignore == None
|
||||||
|
|
||||||
|
print 'encode: zero space ...'
|
||||||
|
result, ignore = xdelta3.xd3_encode_memory(target, source, 0)
|
||||||
|
|
||||||
|
assert result == 28
|
||||||
|
assert ignore == None
|
||||||
|
|
||||||
|
print 'encode: no source ...'
|
||||||
|
result, zdata = xdelta3.xd3_encode_memory(target, None, 50)
|
||||||
|
|
||||||
|
assert result == 0
|
||||||
|
assert len(zdata) > len(patch)
|
||||||
|
|
||||||
|
print 'encode: no input ...'
|
||||||
|
result, ignore = xdelta3.xd3_encode_memory(None, None, 50)
|
||||||
|
|
||||||
|
assert result != 0
|
||||||
|
|
||||||
|
print 'decode: basic ...'
|
||||||
|
result, target1 = xdelta3.xd3_decode_memory(patch, source, len(target))
|
||||||
|
|
||||||
|
assert result == 0
|
||||||
|
assert len(target1) == len(target)
|
||||||
|
assert target1 == target
|
||||||
|
|
||||||
|
print 'decode: out of space ...'
|
||||||
|
result, ignore = xdelta3.xd3_decode_memory(patch, source, len(target) - 1)
|
||||||
|
|
||||||
|
assert result == 28
|
||||||
|
assert ignore == None
|
||||||
|
|
||||||
|
print 'decode: zero space ...'
|
||||||
|
result, ignore = xdelta3.xd3_decode_memory(patch, source, 0)
|
||||||
|
|
||||||
|
assert result == 28
|
||||||
|
assert ignore == None
|
||||||
|
|
||||||
|
print 'decode: single byte error ...'
|
||||||
|
# a few expected single-byte errors, e.g., unused address cache bits, see
|
||||||
|
# xdelta3-test.h's single-bit error tests
|
||||||
|
extra_count = 4
|
||||||
|
noverify_count = 0
|
||||||
|
for corrupt_pos in range(len(patch_adler32)):
|
||||||
|
input = ''.join([j == corrupt_pos and '\xff' or patch_adler32[j]
|
||||||
|
for j in range(len(patch_adler32))])
|
||||||
|
|
||||||
|
result, ignore = xdelta3.xd3_decode_memory(input, source, len(target), 0)
|
||||||
|
assert result == -17712
|
||||||
|
assert ignore == None
|
||||||
|
|
||||||
|
# without adler32 verification, the error may be in the data section which
|
||||||
|
# in this case is 6 bytes 'target'
|
||||||
|
result, corrupt = xdelta3.xd3_decode_memory(input, source, len(target),
|
||||||
|
xdelta3.XD3_ADLER32_NOVER)
|
||||||
|
if result == 0:
|
||||||
|
noverify_count = noverify_count + 1
|
||||||
|
#print "got %s" % corrupt
|
||||||
|
#end
|
||||||
|
#end
|
||||||
|
assert noverify_count == len('target') + extra_count
|
||||||
|
|
||||||
|
print 'decode: no source ...'
|
||||||
|
result, target2 = xdelta3.xd3_decode_memory(zdata, None, len(target))
|
||||||
|
|
||||||
|
assert result == 0
|
||||||
|
assert target == target2
|
||||||
|
|
||||||
|
# Test compression level setting via flags. assumes a 9 byte checksum
|
||||||
|
# and that level 9 steps 2, level 1 steps 15:
|
||||||
|
# 01234567890123456789012345678901
|
||||||
|
# level 1 only indexes 2 checksums "abcdefghi" and "ABCDEFGHI"
|
||||||
|
# outputs 43 vs. 23 bytes
|
||||||
|
print 'encode: compression level ...'
|
||||||
|
|
||||||
|
source = '_la_la_abcdefghi_la_la_ABCDEFGHI'
|
||||||
|
target = 'la_la_ABCDEFGH__la_la_abcdefgh__'
|
||||||
|
|
||||||
|
result1, level1 = xdelta3.xd3_encode_memory(target, source, 50, xdelta3.XD3_COMPLEVEL_1)
|
||||||
|
result9, level9 = xdelta3.xd3_encode_memory(target, source, 50, xdelta3.XD3_COMPLEVEL_9)
|
||||||
|
|
||||||
|
assert result1 == 0 and result9 == 0
|
||||||
|
assert len(level1) > len(level9)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Issue 65
|
||||||
|
print 'encode: 65 ...'
|
||||||
|
source = 'Hello World'
|
||||||
|
target = 'Hello everyone'
|
||||||
|
result, patch = xdelta3.xd3_encode_memory(target, source, len(target))
|
||||||
|
assert result != 0
|
||||||
|
|
||||||
|
result, patch = xdelta3.xd3_encode_memory(target, source, 2 * len(target))
|
||||||
|
assert result == 0
|
||||||
|
|
||||||
|
print 'PASS'
|
557
lib/xdelta3/xdelta3-blkcache.h
Normal file
557
lib/xdelta3/xdelta3-blkcache.h
Normal file
|
@ -0,0 +1,557 @@
|
||||||
|
/* xdelta3 - delta compression tools and library
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xdelta3-internal.h"
|
||||||
|
|
||||||
|
typedef struct _main_blklru main_blklru;
|
||||||
|
typedef struct _main_blklru_list main_blklru_list;
|
||||||
|
|
||||||
|
|
||||||
|
#define XD3_INVALID_OFFSET XOFF_T_MAX
|
||||||
|
|
||||||
|
struct _main_blklru_list
|
||||||
|
{
|
||||||
|
main_blklru_list *next;
|
||||||
|
main_blklru_list *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _main_blklru
|
||||||
|
{
|
||||||
|
uint8_t *blk;
|
||||||
|
xoff_t blkno;
|
||||||
|
usize_t size;
|
||||||
|
main_blklru_list link;
|
||||||
|
};
|
||||||
|
|
||||||
|
XD3_MAKELIST(main_blklru_list,main_blklru,link);
|
||||||
|
|
||||||
|
static usize_t lru_size = 0;
|
||||||
|
static main_blklru *lru = NULL; /* array of lru_size elts */
|
||||||
|
static main_blklru_list lru_list;
|
||||||
|
static int do_src_fifo = 0; /* set to avoid lru */
|
||||||
|
|
||||||
|
static int lru_hits = 0;
|
||||||
|
static int lru_misses = 0;
|
||||||
|
static int lru_filled = 0;
|
||||||
|
|
||||||
|
static void main_lru_reset (void)
|
||||||
|
{
|
||||||
|
lru_size = 0;
|
||||||
|
lru = NULL;
|
||||||
|
do_src_fifo = 0;
|
||||||
|
lru_hits = 0;
|
||||||
|
lru_misses = 0;
|
||||||
|
lru_filled = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void main_lru_cleanup (void)
|
||||||
|
{
|
||||||
|
if (lru != NULL)
|
||||||
|
{
|
||||||
|
main_buffree (lru[0].blk);
|
||||||
|
}
|
||||||
|
|
||||||
|
main_free (lru);
|
||||||
|
lru = NULL;
|
||||||
|
|
||||||
|
lru_hits = 0;
|
||||||
|
lru_misses = 0;
|
||||||
|
lru_filled = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is called at different times for encoding and decoding. The
|
||||||
|
* encoder calls it immediately, the decoder delays until the
|
||||||
|
* application header is received. */
|
||||||
|
static int
|
||||||
|
main_set_source (xd3_stream *stream, xd3_cmd cmd,
|
||||||
|
main_file *sfile, xd3_source *source)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
usize_t i;
|
||||||
|
xoff_t source_size = 0;
|
||||||
|
usize_t blksize;
|
||||||
|
|
||||||
|
XD3_ASSERT (lru == NULL);
|
||||||
|
XD3_ASSERT (stream->src == NULL);
|
||||||
|
XD3_ASSERT (option_srcwinsz >= XD3_MINSRCWINSZ);
|
||||||
|
|
||||||
|
/* TODO: this code needs refactoring into FIFO, LRU, FAKE. Yuck!
|
||||||
|
* This is simplified from 3.0z which had issues with sizing the
|
||||||
|
* source buffer memory allocation and the source blocksize. */
|
||||||
|
|
||||||
|
/* LRU-specific */
|
||||||
|
main_blklru_list_init (& lru_list);
|
||||||
|
|
||||||
|
if (allow_fake_source)
|
||||||
|
{
|
||||||
|
/* TODO: refactor
|
||||||
|
* TOOLS/recode-specific: Check "allow_fake_source" mode looks
|
||||||
|
* broken now. */
|
||||||
|
sfile->mode = XO_READ;
|
||||||
|
sfile->realname = sfile->filename;
|
||||||
|
sfile->nread = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Either a regular file (possibly compressed) or a FIFO
|
||||||
|
* (possibly compressed). */
|
||||||
|
if ((ret = main_file_open (sfile, sfile->filename, XO_READ)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the file is regular we know it's size. If the file turns
|
||||||
|
* out to be externally compressed, size_known may change. */
|
||||||
|
sfile->size_known = (main_file_stat (sfile, &source_size) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: The API requires a power-of-two blocksize and srcwinsz
|
||||||
|
* (-B). The logic here will use a single block if the entire file
|
||||||
|
* is known to fit into srcwinsz. */
|
||||||
|
option_srcwinsz = xd3_xoff_roundup (option_srcwinsz);
|
||||||
|
|
||||||
|
/* Though called "lru", it is not LRU-specific. We always allocate
|
||||||
|
* a maximum number of source block buffers. If the entire file
|
||||||
|
* fits into srcwinsz, this buffer will stay as the only
|
||||||
|
* (lru_size==1) source block. Otherwise, we know that at least
|
||||||
|
* option_srcwinsz bytes are available. Split the source window
|
||||||
|
* into buffers. */
|
||||||
|
if ((lru = (main_blklru*) main_malloc (MAX_LRU_SIZE *
|
||||||
|
sizeof (main_blklru))) == NULL)
|
||||||
|
{
|
||||||
|
ret = ENOMEM;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (lru, 0, sizeof(lru[0]) * MAX_LRU_SIZE);
|
||||||
|
|
||||||
|
/* Allocate the entire buffer. */
|
||||||
|
if ((lru[0].blk = (uint8_t*) main_bufalloc (option_srcwinsz)) == NULL)
|
||||||
|
{
|
||||||
|
ret = ENOMEM;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main calls main_getblk_func() once before xd3_set_source(). This
|
||||||
|
* is the point at which external decompression may begin. Set the
|
||||||
|
* system for a single block. */
|
||||||
|
lru_size = 1;
|
||||||
|
lru[0].blkno = XD3_INVALID_OFFSET;
|
||||||
|
blksize = option_srcwinsz;
|
||||||
|
main_blklru_list_push_back (& lru_list, & lru[0]);
|
||||||
|
XD3_ASSERT (blksize != 0);
|
||||||
|
|
||||||
|
/* Initialize xd3_source. */
|
||||||
|
source->blksize = blksize;
|
||||||
|
source->name = sfile->filename;
|
||||||
|
source->ioh = sfile;
|
||||||
|
source->curblkno = XD3_INVALID_OFFSET;
|
||||||
|
source->curblk = NULL;
|
||||||
|
source->max_winsize = option_srcwinsz;
|
||||||
|
|
||||||
|
if ((ret = main_getblk_func (stream, source, 0)) != 0)
|
||||||
|
{
|
||||||
|
XPR(NT "error reading source: %s: %s\n",
|
||||||
|
sfile->filename,
|
||||||
|
xd3_mainerror (ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
source->onblk = lru[0].size; /* xd3 sets onblk */
|
||||||
|
|
||||||
|
/* If the file is smaller than a block, size is known. */
|
||||||
|
if (!sfile->size_known && source->onblk < blksize)
|
||||||
|
{
|
||||||
|
source_size = source->onblk;
|
||||||
|
source->onlastblk = source_size;
|
||||||
|
sfile->size_known = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the size is not known or is greater than the buffer size, we
|
||||||
|
* split the buffer across MAX_LRU_SIZE blocks (already allocated in
|
||||||
|
* "lru"). */
|
||||||
|
if (!sfile->size_known || source_size > option_srcwinsz)
|
||||||
|
{
|
||||||
|
/* Modify block 0, change blocksize. */
|
||||||
|
blksize = option_srcwinsz / MAX_LRU_SIZE;
|
||||||
|
source->blksize = blksize;
|
||||||
|
source->onblk = blksize;
|
||||||
|
source->onlastblk = blksize;
|
||||||
|
source->max_blkno = MAX_LRU_SIZE - 1;
|
||||||
|
|
||||||
|
lru[0].size = blksize;
|
||||||
|
lru_size = MAX_LRU_SIZE;
|
||||||
|
|
||||||
|
/* Setup rest of blocks. */
|
||||||
|
for (i = 1; i < lru_size; i += 1)
|
||||||
|
{
|
||||||
|
lru[i].blk = lru[0].blk + (blksize * i);
|
||||||
|
lru[i].blkno = i;
|
||||||
|
lru[i].size = blksize;
|
||||||
|
main_blklru_list_push_back (& lru_list, & lru[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! sfile->size_known)
|
||||||
|
{
|
||||||
|
/* If the size is not know, we must use FIFO discipline. */
|
||||||
|
do_src_fifo = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call the appropriate set_source method, handle errors, print
|
||||||
|
* verbose message, etc. */
|
||||||
|
if (sfile->size_known)
|
||||||
|
{
|
||||||
|
ret = xd3_set_source_and_size (stream, source, source_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = xd3_set_source (stream, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
XPR(NT XD3_LIB_ERRMSG (stream, ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
XD3_ASSERT (stream->src == source);
|
||||||
|
XD3_ASSERT (source->blksize == blksize);
|
||||||
|
|
||||||
|
if (option_verbose)
|
||||||
|
{
|
||||||
|
static shortbuf srcszbuf;
|
||||||
|
static shortbuf srccntbuf;
|
||||||
|
static shortbuf winszbuf;
|
||||||
|
static shortbuf blkszbuf;
|
||||||
|
static shortbuf nbufs;
|
||||||
|
|
||||||
|
if (sfile->size_known)
|
||||||
|
{
|
||||||
|
short_sprintf (srcszbuf, "source size %s [%"Q"u]",
|
||||||
|
main_format_bcnt (source_size, &srccntbuf),
|
||||||
|
source_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
short_sprintf (srcszbuf, "%s", "source size unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
nbufs.buf[0] = 0;
|
||||||
|
|
||||||
|
if (option_verbose > 1)
|
||||||
|
{
|
||||||
|
short_sprintf (nbufs, " #bufs %"W"u", lru_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
XPR(NT "source %s %s blksize %s window %s%s%s\n",
|
||||||
|
sfile->filename,
|
||||||
|
srcszbuf.buf,
|
||||||
|
main_format_bcnt (blksize, &blkszbuf),
|
||||||
|
main_format_bcnt (option_srcwinsz, &winszbuf),
|
||||||
|
nbufs.buf,
|
||||||
|
do_src_fifo ? " (FIFO)" : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
main_getblk_lru (xd3_source *source, xoff_t blkno,
|
||||||
|
main_blklru** blrup, int *is_new)
|
||||||
|
{
|
||||||
|
main_blklru *blru = NULL;
|
||||||
|
usize_t i;
|
||||||
|
|
||||||
|
(*is_new) = 0;
|
||||||
|
|
||||||
|
if (do_src_fifo)
|
||||||
|
{
|
||||||
|
/* Direct lookup assumes sequential scan w/o skipping blocks. */
|
||||||
|
int idx = blkno % lru_size;
|
||||||
|
blru = & lru[idx];
|
||||||
|
if (blru->blkno == blkno)
|
||||||
|
{
|
||||||
|
(*blrup) = blru;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* No going backwards in a sequential scan. */
|
||||||
|
if (blru->blkno != XD3_INVALID_OFFSET && blru->blkno > blkno)
|
||||||
|
{
|
||||||
|
return XD3_TOOFARBACK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Sequential search through LRU. */
|
||||||
|
for (i = 0; i < lru_size; i += 1)
|
||||||
|
{
|
||||||
|
blru = & lru[i];
|
||||||
|
if (blru->blkno == blkno)
|
||||||
|
{
|
||||||
|
main_blklru_list_remove (blru);
|
||||||
|
main_blklru_list_push_back (& lru_list, blru);
|
||||||
|
(*blrup) = blru;
|
||||||
|
IF_DEBUG1 (DP(RINT "[getblk_lru] HIT blkno = %"Q"u lru_size=%"W"u\n",
|
||||||
|
blkno, lru_size));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IF_DEBUG1 (DP(RINT "[getblk_lru] MISS blkno = %"Q"u lru_size=%"W"u\n",
|
||||||
|
blkno, lru_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_src_fifo)
|
||||||
|
{
|
||||||
|
int idx = blkno % lru_size;
|
||||||
|
blru = & lru[idx];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XD3_ASSERT (! main_blklru_list_empty (& lru_list));
|
||||||
|
blru = main_blklru_list_pop_front (& lru_list);
|
||||||
|
main_blklru_list_push_back (& lru_list, blru);
|
||||||
|
}
|
||||||
|
|
||||||
|
lru_filled += 1;
|
||||||
|
(*is_new) = 1;
|
||||||
|
(*blrup) = blru;
|
||||||
|
blru->blkno = XD3_INVALID_OFFSET;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
main_read_seek_source (xd3_stream *stream,
|
||||||
|
xd3_source *source,
|
||||||
|
xoff_t blkno) {
|
||||||
|
xoff_t pos = blkno * source->blksize;
|
||||||
|
main_file *sfile = (main_file*) source->ioh;
|
||||||
|
main_blklru *blru;
|
||||||
|
int is_new;
|
||||||
|
size_t nread = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!sfile->seek_failed)
|
||||||
|
{
|
||||||
|
ret = main_file_seek (sfile, pos);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
sfile->source_position = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sfile->seek_failed || ret != 0)
|
||||||
|
{
|
||||||
|
/* For an unseekable file (or other seek error, does it
|
||||||
|
* matter?) */
|
||||||
|
if (sfile->source_position > pos)
|
||||||
|
{
|
||||||
|
/* Could assert !IS_ENCODE(), this shouldn't happen
|
||||||
|
* because of do_src_fifo during encode. */
|
||||||
|
if (!option_quiet)
|
||||||
|
{
|
||||||
|
XPR(NT "source can't seek backwards; requested block offset "
|
||||||
|
"%"Q"u source position is %"Q"u\n",
|
||||||
|
pos, sfile->source_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
sfile->seek_failed = 1;
|
||||||
|
stream->msg = "non-seekable source: "
|
||||||
|
"copy is too far back (try raising -B)";
|
||||||
|
return XD3_TOOFARBACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There's a chance here, that an genuine lseek error will cause
|
||||||
|
* xdelta3 to shift into non-seekable mode, entering a degraded
|
||||||
|
* condition. */
|
||||||
|
if (!sfile->seek_failed && option_verbose)
|
||||||
|
{
|
||||||
|
XPR(NT "source can't seek, will use FIFO for %s\n",
|
||||||
|
sfile->filename);
|
||||||
|
|
||||||
|
if (option_verbose > 1)
|
||||||
|
{
|
||||||
|
XPR(NT "seek error at offset %"Q"u: %s\n",
|
||||||
|
pos, xd3_mainerror (ret));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sfile->seek_failed = 1;
|
||||||
|
|
||||||
|
if (option_verbose > 1 && pos != sfile->source_position)
|
||||||
|
{
|
||||||
|
XPR(NT "non-seekable source skipping %"Q"u bytes @ %"Q"u\n",
|
||||||
|
pos - sfile->source_position,
|
||||||
|
sfile->source_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (sfile->source_position < pos)
|
||||||
|
{
|
||||||
|
xoff_t skip_blkno;
|
||||||
|
usize_t skip_offset;
|
||||||
|
|
||||||
|
xd3_blksize_div (sfile->source_position, source,
|
||||||
|
&skip_blkno, &skip_offset);
|
||||||
|
|
||||||
|
/* Read past unused data */
|
||||||
|
XD3_ASSERT (pos - sfile->source_position >= source->blksize);
|
||||||
|
XD3_ASSERT (skip_offset == 0);
|
||||||
|
|
||||||
|
if ((ret = main_getblk_lru (source, skip_blkno,
|
||||||
|
& blru, & is_new)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
XD3_ASSERT (is_new);
|
||||||
|
blru->blkno = skip_blkno;
|
||||||
|
|
||||||
|
if ((ret = main_read_primary_input (sfile,
|
||||||
|
(uint8_t*) blru->blk,
|
||||||
|
source->blksize,
|
||||||
|
& nread)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nread != source->blksize)
|
||||||
|
{
|
||||||
|
IF_DEBUG1 (DP(RINT "[getblk] short skip block nread = %"Z"u\n",
|
||||||
|
nread));
|
||||||
|
stream->msg = "non-seekable input is short";
|
||||||
|
return XD3_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
sfile->source_position += nread;
|
||||||
|
blru->size = nread;
|
||||||
|
|
||||||
|
IF_DEBUG1 (DP(RINT "[getblk] skip blkno %"Q"u size %"W"u\n",
|
||||||
|
skip_blkno, blru->size));
|
||||||
|
|
||||||
|
XD3_ASSERT (sfile->source_position <= pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is the callback for reading a block of source. This function
|
||||||
|
* is blocking and it implements a small LRU.
|
||||||
|
*
|
||||||
|
* Note that it is possible for main_input() to handle getblk requests
|
||||||
|
* in a non-blocking manner. If the callback is NULL then the caller
|
||||||
|
* of xd3_*_input() must handle the XD3_GETSRCBLK return value and
|
||||||
|
* fill the source in the same way. See xd3_getblk for details. To
|
||||||
|
* see an example of non-blocking getblk, see xdelta-test.h. */
|
||||||
|
static int
|
||||||
|
main_getblk_func (xd3_stream *stream,
|
||||||
|
xd3_source *source,
|
||||||
|
xoff_t blkno)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
xoff_t pos = blkno * source->blksize;
|
||||||
|
main_file *sfile = (main_file*) source->ioh;
|
||||||
|
main_blklru *blru;
|
||||||
|
int is_new;
|
||||||
|
size_t nread = 0;
|
||||||
|
|
||||||
|
if (allow_fake_source)
|
||||||
|
{
|
||||||
|
source->curblkno = blkno;
|
||||||
|
source->onblk = 0;
|
||||||
|
source->curblk = lru[0].blk;
|
||||||
|
lru[0].size = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = main_getblk_lru (source, blkno, & blru, & is_new)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_new)
|
||||||
|
{
|
||||||
|
source->curblkno = blkno;
|
||||||
|
source->onblk = blru->size;
|
||||||
|
source->curblk = blru->blk;
|
||||||
|
lru_hits++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lru_misses += 1;
|
||||||
|
|
||||||
|
if (pos != sfile->source_position)
|
||||||
|
{
|
||||||
|
/* Only try to seek when the position is wrong. This means the
|
||||||
|
* decoder will fail when the source buffer is too small, but
|
||||||
|
* only when the input is non-seekable. */
|
||||||
|
if ((ret = main_read_seek_source (stream, source, blkno)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XD3_ASSERT (sfile->source_position == pos);
|
||||||
|
|
||||||
|
if ((ret = main_read_primary_input (sfile,
|
||||||
|
(uint8_t*) blru->blk,
|
||||||
|
source->blksize,
|
||||||
|
& nread)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the last block read, used to handle non-seekable files. */
|
||||||
|
sfile->source_position = pos + nread;
|
||||||
|
|
||||||
|
if (option_verbose > 3)
|
||||||
|
{
|
||||||
|
if (blru->blkno != XD3_INVALID_OFFSET)
|
||||||
|
{
|
||||||
|
if (blru->blkno != blkno)
|
||||||
|
{
|
||||||
|
XPR(NT "source block %"Q"u read %"Z"u ejects %"Q"u (lru_hits=%u, "
|
||||||
|
"lru_misses=%u, lru_filled=%u)\n",
|
||||||
|
blkno, nread, blru->blkno, lru_hits, lru_misses, lru_filled);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XPR(NT "source block %"Q"u read %"Z"u (lru_hits=%u, "
|
||||||
|
"lru_misses=%u, lru_filled=%u)\n",
|
||||||
|
blkno, nread, lru_hits, lru_misses, lru_filled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XPR(NT "source block %"Q"u read %"Z"u (lru_hits=%u, lru_misses=%u, "
|
||||||
|
"lru_filled=%u)\n", blkno, nread,
|
||||||
|
lru_hits, lru_misses, lru_filled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
source->curblk = blru->blk;
|
||||||
|
source->curblkno = blkno;
|
||||||
|
source->onblk = nread;
|
||||||
|
blru->size = nread;
|
||||||
|
blru->blkno = blkno;
|
||||||
|
|
||||||
|
IF_DEBUG1 (DP(RINT "[main_getblk] blkno %"Q"u onblk %"Z"u pos %"Q"u "
|
||||||
|
"srcpos %"Q"u\n",
|
||||||
|
blkno, nread, pos, sfile->source_position));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
171
lib/xdelta3/xdelta3-cfgs.h
Normal file
171
lib/xdelta3/xdelta3-cfgs.h
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
/* xdelta3 - delta compression tools and library
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
SOFT string matcher
|
||||||
|
******************************************************************/
|
||||||
|
|
||||||
|
#if XD3_BUILD_SOFT
|
||||||
|
|
||||||
|
#define TEMPLATE soft
|
||||||
|
#define LLOOK stream->smatcher.large_look
|
||||||
|
#define LSTEP stream->smatcher.large_step
|
||||||
|
#define SLOOK stream->smatcher.small_look
|
||||||
|
#define SCHAIN stream->smatcher.small_chain
|
||||||
|
#define SLCHAIN stream->smatcher.small_lchain
|
||||||
|
#define MAXLAZY stream->smatcher.max_lazy
|
||||||
|
#define LONGENOUGH stream->smatcher.long_enough
|
||||||
|
|
||||||
|
#define SOFTCFG 1
|
||||||
|
#include "xdelta3.c"
|
||||||
|
#undef SOFTCFG
|
||||||
|
|
||||||
|
#undef TEMPLATE
|
||||||
|
#undef LLOOK
|
||||||
|
#undef SLOOK
|
||||||
|
#undef LSTEP
|
||||||
|
#undef SCHAIN
|
||||||
|
#undef SLCHAIN
|
||||||
|
#undef MAXLAZY
|
||||||
|
#undef LONGENOUGH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SOFTCFG 0
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
FASTEST string matcher
|
||||||
|
**********************************************************/
|
||||||
|
#if XD3_BUILD_FASTEST
|
||||||
|
#define TEMPLATE fastest
|
||||||
|
#define LLOOK 9
|
||||||
|
#define LSTEP 26
|
||||||
|
#define SLOOK 4U
|
||||||
|
#define SCHAIN 1
|
||||||
|
#define SLCHAIN 1
|
||||||
|
#define MAXLAZY 6
|
||||||
|
#define LONGENOUGH 6
|
||||||
|
|
||||||
|
#include "xdelta3.c"
|
||||||
|
|
||||||
|
#undef TEMPLATE
|
||||||
|
#undef LLOOK
|
||||||
|
#undef SLOOK
|
||||||
|
#undef LSTEP
|
||||||
|
#undef SCHAIN
|
||||||
|
#undef SLCHAIN
|
||||||
|
#undef MAXLAZY
|
||||||
|
#undef LONGENOUGH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
FASTER string matcher
|
||||||
|
**********************************************************/
|
||||||
|
#if XD3_BUILD_FASTER
|
||||||
|
#define TEMPLATE faster
|
||||||
|
#define LLOOK 9
|
||||||
|
#define LSTEP 15
|
||||||
|
#define SLOOK 4U
|
||||||
|
#define SCHAIN 1
|
||||||
|
#define SLCHAIN 1
|
||||||
|
#define MAXLAZY 18
|
||||||
|
#define LONGENOUGH 18
|
||||||
|
|
||||||
|
#include "xdelta3.c"
|
||||||
|
|
||||||
|
#undef TEMPLATE
|
||||||
|
#undef LLOOK
|
||||||
|
#undef SLOOK
|
||||||
|
#undef LSTEP
|
||||||
|
#undef SCHAIN
|
||||||
|
#undef SLCHAIN
|
||||||
|
#undef MAXLAZY
|
||||||
|
#undef LONGENOUGH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************************************
|
||||||
|
FAST string matcher
|
||||||
|
********************************************************/
|
||||||
|
#if XD3_BUILD_FAST
|
||||||
|
#define TEMPLATE fast
|
||||||
|
#define LLOOK 9
|
||||||
|
#define LSTEP 8
|
||||||
|
#define SLOOK 4U
|
||||||
|
#define SCHAIN 4
|
||||||
|
#define SLCHAIN 1
|
||||||
|
#define MAXLAZY 18
|
||||||
|
#define LONGENOUGH 35
|
||||||
|
|
||||||
|
#include "xdelta3.c"
|
||||||
|
|
||||||
|
#undef TEMPLATE
|
||||||
|
#undef LLOOK
|
||||||
|
#undef SLOOK
|
||||||
|
#undef LSTEP
|
||||||
|
#undef SCHAIN
|
||||||
|
#undef SLCHAIN
|
||||||
|
#undef MAXLAZY
|
||||||
|
#undef LONGENOUGH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**************************************************
|
||||||
|
SLOW string matcher
|
||||||
|
**************************************************************/
|
||||||
|
#if XD3_BUILD_SLOW
|
||||||
|
#define TEMPLATE slow
|
||||||
|
#define LLOOK 9
|
||||||
|
#define LSTEP 2
|
||||||
|
#define SLOOK 4U
|
||||||
|
#define SCHAIN 44
|
||||||
|
#define SLCHAIN 13
|
||||||
|
#define MAXLAZY 90
|
||||||
|
#define LONGENOUGH 70
|
||||||
|
|
||||||
|
#include "xdelta3.c"
|
||||||
|
|
||||||
|
#undef TEMPLATE
|
||||||
|
#undef LLOOK
|
||||||
|
#undef SLOOK
|
||||||
|
#undef LSTEP
|
||||||
|
#undef SCHAIN
|
||||||
|
#undef SLCHAIN
|
||||||
|
#undef MAXLAZY
|
||||||
|
#undef LONGENOUGH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
DEFAULT string matcher
|
||||||
|
************************************************************/
|
||||||
|
#if XD3_BUILD_DEFAULT
|
||||||
|
#define TEMPLATE default
|
||||||
|
#define LLOOK 9
|
||||||
|
#define LSTEP 3
|
||||||
|
#define SLOOK 4U
|
||||||
|
#define SCHAIN 8
|
||||||
|
#define SLCHAIN 2
|
||||||
|
#define MAXLAZY 36
|
||||||
|
#define LONGENOUGH 70
|
||||||
|
|
||||||
|
#include "xdelta3.c"
|
||||||
|
|
||||||
|
#undef TEMPLATE
|
||||||
|
#undef LLOOK
|
||||||
|
#undef SLOOK
|
||||||
|
#undef LSTEP
|
||||||
|
#undef SCHAIN
|
||||||
|
#undef SLCHAIN
|
||||||
|
#undef MAXLAZY
|
||||||
|
#undef LONGENOUGH
|
||||||
|
#endif
|
1219
lib/xdelta3/xdelta3-decode.h
Normal file
1219
lib/xdelta3/xdelta3-decode.h
Normal file
File diff suppressed because it is too large
Load diff
1835
lib/xdelta3/xdelta3-djw.h
Normal file
1835
lib/xdelta3/xdelta3-djw.h
Normal file
File diff suppressed because it is too large
Load diff
857
lib/xdelta3/xdelta3-fgk.h
Normal file
857
lib/xdelta3/xdelta3-fgk.h
Normal file
|
@ -0,0 +1,857 @@
|
||||||
|
/* xdelta3 - delta compression tools and library
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
For demonstration purposes only.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _XDELTA3_FGK_h_
|
||||||
|
#define _XDELTA3_FGK_h_
|
||||||
|
|
||||||
|
/* An implementation of the FGK algorithm described by D.E. Knuth in
|
||||||
|
* "Dynamic Huffman Coding" in Journal of Algorithms 6. */
|
||||||
|
|
||||||
|
/* A 32bit counter (fgk_weight) is used as the frequency counter for
|
||||||
|
* nodes in the huffman tree. TODO: Need oto test for overflow and/or
|
||||||
|
* reset stats. */
|
||||||
|
|
||||||
|
typedef struct _fgk_stream fgk_stream;
|
||||||
|
typedef struct _fgk_node fgk_node;
|
||||||
|
typedef struct _fgk_block fgk_block;
|
||||||
|
typedef unsigned int fgk_bit;
|
||||||
|
typedef uint32_t fgk_weight;
|
||||||
|
|
||||||
|
struct _fgk_block {
|
||||||
|
union {
|
||||||
|
fgk_node *un_leader;
|
||||||
|
fgk_block *un_freeptr;
|
||||||
|
} un;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define block_leader un.un_leader
|
||||||
|
#define block_freeptr un.un_freeptr
|
||||||
|
|
||||||
|
/* The code can also support fixed huffman encoding/decoding. */
|
||||||
|
#define IS_ADAPTIVE 1
|
||||||
|
|
||||||
|
/* weight is a count of the number of times this element has been seen
|
||||||
|
* in the current encoding/decoding. parent, right_child, and
|
||||||
|
* left_child are pointers defining the tree structure. right and
|
||||||
|
* left point to neighbors in an ordered sequence of weights. The
|
||||||
|
* left child of a node is always guaranteed to have weight not
|
||||||
|
* greater than its sibling. fgk_blockLeader points to the element
|
||||||
|
* with the same weight as itself which is closest to the next
|
||||||
|
* increasing weight block. */
|
||||||
|
struct _fgk_node
|
||||||
|
{
|
||||||
|
fgk_weight weight;
|
||||||
|
fgk_node *parent;
|
||||||
|
fgk_node *left_child;
|
||||||
|
fgk_node *right_child;
|
||||||
|
fgk_node *left;
|
||||||
|
fgk_node *right;
|
||||||
|
fgk_block *my_block;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* alphabet_size is the a count of the number of possible leaves in
|
||||||
|
* the huffman tree. The number of total nodes counting internal
|
||||||
|
* nodes is ((2 * alphabet_size) - 1). zero_freq_count is the number
|
||||||
|
* of elements remaining which have zero frequency. zero_freq_exp and
|
||||||
|
* zero_freq_rem satisfy the equation zero_freq_count =
|
||||||
|
* 2^zero_freq_exp + zero_freq_rem. root_node is the root of the
|
||||||
|
* tree, which is initialized to a node with zero frequency and
|
||||||
|
* contains the 0th such element. free_node contains a pointer to the
|
||||||
|
* next available fgk_node space. alphabet contains all the elements
|
||||||
|
* and is indexed by N. remaining_zeros points to the head of the
|
||||||
|
* list of zeros. */
|
||||||
|
struct _fgk_stream
|
||||||
|
{
|
||||||
|
usize_t alphabet_size;
|
||||||
|
usize_t zero_freq_count;
|
||||||
|
usize_t zero_freq_exp;
|
||||||
|
usize_t zero_freq_rem;
|
||||||
|
usize_t coded_depth;
|
||||||
|
|
||||||
|
usize_t total_nodes;
|
||||||
|
usize_t total_blocks;
|
||||||
|
|
||||||
|
fgk_bit *coded_bits;
|
||||||
|
|
||||||
|
fgk_block *block_array;
|
||||||
|
fgk_block *free_block;
|
||||||
|
|
||||||
|
fgk_node *decode_ptr;
|
||||||
|
fgk_node *remaining_zeros;
|
||||||
|
fgk_node *alphabet;
|
||||||
|
fgk_node *root_node;
|
||||||
|
fgk_node *free_node;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
/* Encoder */
|
||||||
|
/*********************************************************************/
|
||||||
|
|
||||||
|
static fgk_stream* fgk_alloc (xd3_stream *stream /*, usize_t alphabet_size */);
|
||||||
|
static int fgk_init (xd3_stream *stream,
|
||||||
|
fgk_stream *h,
|
||||||
|
int is_encode);
|
||||||
|
static usize_t fgk_encode_data (fgk_stream *h,
|
||||||
|
usize_t n);
|
||||||
|
static inline fgk_bit fgk_get_encoded_bit (fgk_stream *h);
|
||||||
|
|
||||||
|
static int xd3_encode_fgk (xd3_stream *stream,
|
||||||
|
fgk_stream *sec_stream,
|
||||||
|
xd3_output *input,
|
||||||
|
xd3_output *output,
|
||||||
|
xd3_sec_cfg *cfg);
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
/* Decoder */
|
||||||
|
/*********************************************************************/
|
||||||
|
|
||||||
|
static inline int fgk_decode_bit (fgk_stream *h,
|
||||||
|
fgk_bit b);
|
||||||
|
static usize_t fgk_decode_data (fgk_stream *h);
|
||||||
|
static void fgk_destroy (xd3_stream *stream,
|
||||||
|
fgk_stream *h);
|
||||||
|
|
||||||
|
static int xd3_decode_fgk (xd3_stream *stream,
|
||||||
|
fgk_stream *sec_stream,
|
||||||
|
const uint8_t **input,
|
||||||
|
const uint8_t *const input_end,
|
||||||
|
uint8_t **output,
|
||||||
|
const uint8_t *const output_end);
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
/* Private */
|
||||||
|
/*********************************************************************/
|
||||||
|
|
||||||
|
static unsigned int fgk_find_nth_zero (fgk_stream *h, usize_t n);
|
||||||
|
static usize_t fgk_nth_zero (fgk_stream *h, usize_t n);
|
||||||
|
static void fgk_update_tree (fgk_stream *h, usize_t n);
|
||||||
|
static fgk_node* fgk_increase_zero_weight (fgk_stream *h, usize_t n);
|
||||||
|
static void fgk_eliminate_zero (fgk_stream* h, fgk_node *node);
|
||||||
|
static void fgk_move_right (fgk_stream *h, fgk_node *node);
|
||||||
|
static void fgk_promote (fgk_stream *h, fgk_node *node);
|
||||||
|
static void fgk_init_node (fgk_node *node, usize_t i, usize_t size);
|
||||||
|
static fgk_block* fgk_make_block (fgk_stream *h, fgk_node *l);
|
||||||
|
static void fgk_free_block (fgk_stream *h, fgk_block *b);
|
||||||
|
static void fgk_factor_remaining (fgk_stream *h);
|
||||||
|
static inline void fgk_swap_ptrs (fgk_node **one, fgk_node **two);
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
/* Basic Routines */
|
||||||
|
/*********************************************************************/
|
||||||
|
|
||||||
|
/* returns an initialized huffman encoder for an alphabet with the
|
||||||
|
* given size. returns NULL if enough memory cannot be allocated */
|
||||||
|
static fgk_stream* fgk_alloc (xd3_stream *stream /*, int alphabet_size0 */)
|
||||||
|
{
|
||||||
|
usize_t alphabet_size0 = ALPHABET_SIZE;
|
||||||
|
fgk_stream *h;
|
||||||
|
|
||||||
|
if ((h = (fgk_stream*) xd3_alloc (stream, 1, sizeof (fgk_stream))) == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
h->total_nodes = (2 * alphabet_size0) - 1;
|
||||||
|
h->total_blocks = (2 * h->total_nodes);
|
||||||
|
h->alphabet = (fgk_node*) xd3_alloc (stream, h->total_nodes, sizeof (fgk_node));
|
||||||
|
h->block_array = (fgk_block*) xd3_alloc (stream, h->total_blocks, sizeof (fgk_block));
|
||||||
|
h->coded_bits = (fgk_bit*) xd3_alloc (stream, alphabet_size0, sizeof (fgk_bit));
|
||||||
|
|
||||||
|
if (h->coded_bits == NULL ||
|
||||||
|
h->alphabet == NULL ||
|
||||||
|
h->block_array == NULL)
|
||||||
|
{
|
||||||
|
fgk_destroy (stream, h);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
h->alphabet_size = alphabet_size0;
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fgk_init (xd3_stream *stream, fgk_stream *h, int is_encode)
|
||||||
|
{
|
||||||
|
usize_t ui;
|
||||||
|
ssize_t si;
|
||||||
|
|
||||||
|
h->root_node = h->alphabet;
|
||||||
|
h->decode_ptr = h->root_node;
|
||||||
|
h->free_node = h->alphabet + h->alphabet_size;
|
||||||
|
h->remaining_zeros = h->alphabet;
|
||||||
|
h->coded_depth = 0;
|
||||||
|
h->zero_freq_count = h->alphabet_size + 2;
|
||||||
|
|
||||||
|
/* after two calls to factor_remaining, zero_freq_count == alphabet_size */
|
||||||
|
fgk_factor_remaining(h); /* set ZFE and ZFR */
|
||||||
|
fgk_factor_remaining(h); /* set ZFDB according to prev state */
|
||||||
|
|
||||||
|
IF_DEBUG (memset (h->alphabet, 0, sizeof (h->alphabet[0]) * h->total_nodes));
|
||||||
|
|
||||||
|
for (ui = 0; ui < h->total_blocks-1; ui += 1)
|
||||||
|
{
|
||||||
|
h->block_array[ui].block_freeptr = &h->block_array[ui + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
h->block_array[h->total_blocks - 1].block_freeptr = NULL;
|
||||||
|
h->free_block = h->block_array;
|
||||||
|
|
||||||
|
/* Zero frequency nodes are inserted in the first alphabet_size
|
||||||
|
* positions, with Value, weight, and a pointer to the next zero
|
||||||
|
* frequency node. */
|
||||||
|
for (si = h->alphabet_size - 1; si >= 0; si -= 1)
|
||||||
|
{
|
||||||
|
fgk_init_node (h->alphabet + si, (usize_t) si, h->alphabet_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fgk_swap_ptrs(fgk_node **one, fgk_node **two)
|
||||||
|
{
|
||||||
|
fgk_node *tmp = *one;
|
||||||
|
*one = *two;
|
||||||
|
*two = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Takes huffman transmitter h and n, the nth elt in the alphabet, and
|
||||||
|
* returns the number of required to encode n. */
|
||||||
|
static usize_t fgk_encode_data (fgk_stream* h, usize_t n)
|
||||||
|
{
|
||||||
|
fgk_node *target_ptr = h->alphabet + n;
|
||||||
|
|
||||||
|
XD3_ASSERT (n < h->alphabet_size);
|
||||||
|
|
||||||
|
h->coded_depth = 0;
|
||||||
|
|
||||||
|
/* First encode the binary representation of the nth remaining
|
||||||
|
* zero frequency element in reverse such that bit, which will be
|
||||||
|
* encoded from h->coded_depth down to 0 will arrive in increasing
|
||||||
|
* order following the tree path. If there is only one left, it
|
||||||
|
* is not neccesary to encode these bits. */
|
||||||
|
if (IS_ADAPTIVE && target_ptr->weight == 0)
|
||||||
|
{
|
||||||
|
usize_t where, shift;
|
||||||
|
usize_t bits;
|
||||||
|
|
||||||
|
where = fgk_find_nth_zero(h, n);
|
||||||
|
shift = 1;
|
||||||
|
|
||||||
|
if (h->zero_freq_rem == 0)
|
||||||
|
{
|
||||||
|
bits = h->zero_freq_exp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bits = h->zero_freq_exp + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (bits > 0)
|
||||||
|
{
|
||||||
|
h->coded_bits[h->coded_depth++] = (shift & where) && 1;
|
||||||
|
|
||||||
|
bits -= 1;
|
||||||
|
shift <<= 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
target_ptr = h->remaining_zeros;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The path from root to node is filled into coded_bits in reverse so
|
||||||
|
* that it is encoded in the right order */
|
||||||
|
while (target_ptr != h->root_node)
|
||||||
|
{
|
||||||
|
h->coded_bits[h->coded_depth++] = (target_ptr->parent->right_child == target_ptr);
|
||||||
|
|
||||||
|
target_ptr = target_ptr->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_ADAPTIVE)
|
||||||
|
{
|
||||||
|
fgk_update_tree(h, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return h->coded_depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Should be called as many times as fgk_encode_data returns.
|
||||||
|
*/
|
||||||
|
static inline fgk_bit fgk_get_encoded_bit (fgk_stream *h)
|
||||||
|
{
|
||||||
|
XD3_ASSERT (h->coded_depth > 0);
|
||||||
|
|
||||||
|
return h->coded_bits[--h->coded_depth];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This procedure updates the tree after alphabet[n] has been encoded
|
||||||
|
* or decoded.
|
||||||
|
*/
|
||||||
|
static void fgk_update_tree (fgk_stream *h, usize_t n)
|
||||||
|
{
|
||||||
|
fgk_node *incr_node;
|
||||||
|
|
||||||
|
if (h->alphabet[n].weight == 0)
|
||||||
|
{
|
||||||
|
incr_node = fgk_increase_zero_weight (h, n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
incr_node = h->alphabet + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (incr_node != h->root_node)
|
||||||
|
{
|
||||||
|
fgk_move_right (h, incr_node);
|
||||||
|
fgk_promote (h, incr_node);
|
||||||
|
incr_node->weight += 1; /* incr the parent */
|
||||||
|
incr_node = incr_node->parent; /* repeat */
|
||||||
|
}
|
||||||
|
|
||||||
|
h->root_node->weight += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fgk_move_right (fgk_stream *h, fgk_node *move_fwd)
|
||||||
|
{
|
||||||
|
fgk_node **fwd_par_ptr, **back_par_ptr;
|
||||||
|
fgk_node *move_back, *tmp;
|
||||||
|
|
||||||
|
move_back = move_fwd->my_block->block_leader;
|
||||||
|
|
||||||
|
if (move_fwd == move_back ||
|
||||||
|
move_fwd->parent == move_back ||
|
||||||
|
move_fwd->weight == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
move_back->right->left = move_fwd;
|
||||||
|
|
||||||
|
if (move_fwd->left)
|
||||||
|
{
|
||||||
|
move_fwd->left->right = move_back;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = move_fwd->right;
|
||||||
|
move_fwd->right = move_back->right;
|
||||||
|
|
||||||
|
if (tmp == move_back)
|
||||||
|
{
|
||||||
|
move_back->right = move_fwd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tmp->left = move_back;
|
||||||
|
move_back->right = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = move_back->left;
|
||||||
|
move_back->left = move_fwd->left;
|
||||||
|
|
||||||
|
if (tmp == move_fwd)
|
||||||
|
{
|
||||||
|
move_fwd->left = move_back;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tmp->right = move_fwd;
|
||||||
|
move_fwd->left = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (move_fwd->parent->right_child == move_fwd)
|
||||||
|
{
|
||||||
|
fwd_par_ptr = &move_fwd->parent->right_child;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fwd_par_ptr = &move_fwd->parent->left_child;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (move_back->parent->right_child == move_back)
|
||||||
|
{
|
||||||
|
back_par_ptr = &move_back->parent->right_child;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
back_par_ptr = &move_back->parent->left_child;
|
||||||
|
}
|
||||||
|
|
||||||
|
fgk_swap_ptrs (&move_fwd->parent, &move_back->parent);
|
||||||
|
fgk_swap_ptrs (fwd_par_ptr, back_par_ptr);
|
||||||
|
|
||||||
|
move_fwd->my_block->block_leader = move_fwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shifts node, the leader of its block, into the next block. */
|
||||||
|
static void fgk_promote (fgk_stream *h, fgk_node *node)
|
||||||
|
{
|
||||||
|
fgk_node *my_left, *my_right;
|
||||||
|
fgk_block *cur_block;
|
||||||
|
|
||||||
|
my_right = node->right;
|
||||||
|
my_left = node->left;
|
||||||
|
cur_block = node->my_block;
|
||||||
|
|
||||||
|
if (node->weight == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if left is right child, parent of remaining zeros case (?), means parent
|
||||||
|
* has same weight as right child. */
|
||||||
|
if (my_left == node->right_child &&
|
||||||
|
node->left_child &&
|
||||||
|
node->left_child->weight == 0)
|
||||||
|
{
|
||||||
|
XD3_ASSERT (node->left_child == h->remaining_zeros);
|
||||||
|
XD3_ASSERT (node->right_child->weight == (node->weight+1)); /* child weight was already incremented */
|
||||||
|
|
||||||
|
if (node->weight == (my_right->weight - 1) && my_right != h->root_node)
|
||||||
|
{
|
||||||
|
fgk_free_block (h, cur_block);
|
||||||
|
node->my_block = my_right->my_block;
|
||||||
|
my_left->my_block = my_right->my_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_left == h->remaining_zeros)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* true if not the leftmost node */
|
||||||
|
if (my_left->my_block == cur_block)
|
||||||
|
{
|
||||||
|
my_left->my_block->block_leader = my_left;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fgk_free_block (h, cur_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* node->parent != my_right */
|
||||||
|
if ((node->weight == (my_right->weight - 1)) && (my_right != h->root_node))
|
||||||
|
{
|
||||||
|
node->my_block = my_right->my_block;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node->my_block = fgk_make_block (h, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When an element is seen the first time this is called to remove it from the list of
|
||||||
|
* zero weight elements and introduce a new internal node to the tree. */
|
||||||
|
static fgk_node* fgk_increase_zero_weight (fgk_stream *h, usize_t n)
|
||||||
|
{
|
||||||
|
fgk_node *this_zero, *new_internal, *zero_ptr;
|
||||||
|
|
||||||
|
this_zero = h->alphabet + n;
|
||||||
|
|
||||||
|
if (h->zero_freq_count == 1)
|
||||||
|
{
|
||||||
|
/* this is the last one */
|
||||||
|
this_zero->right_child = NULL;
|
||||||
|
|
||||||
|
if (this_zero->right->weight == 1)
|
||||||
|
{
|
||||||
|
this_zero->my_block = this_zero->right->my_block;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this_zero->my_block = fgk_make_block (h, this_zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
h->remaining_zeros = NULL;
|
||||||
|
|
||||||
|
return this_zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
zero_ptr = h->remaining_zeros;
|
||||||
|
|
||||||
|
new_internal = h->free_node++;
|
||||||
|
|
||||||
|
new_internal->parent = zero_ptr->parent;
|
||||||
|
new_internal->right = zero_ptr->right;
|
||||||
|
new_internal->weight = 0;
|
||||||
|
new_internal->right_child = this_zero;
|
||||||
|
new_internal->left = this_zero;
|
||||||
|
|
||||||
|
if (h->remaining_zeros == h->root_node)
|
||||||
|
{
|
||||||
|
/* This is the first element to be coded */
|
||||||
|
h->root_node = new_internal;
|
||||||
|
this_zero->my_block = fgk_make_block (h, this_zero);
|
||||||
|
new_internal->my_block = fgk_make_block (h, new_internal);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_internal->right->left = new_internal;
|
||||||
|
|
||||||
|
if (zero_ptr->parent->right_child == zero_ptr)
|
||||||
|
{
|
||||||
|
zero_ptr->parent->right_child = new_internal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
zero_ptr->parent->left_child = new_internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_internal->right->weight == 1)
|
||||||
|
{
|
||||||
|
new_internal->my_block = new_internal->right->my_block;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_internal->my_block = fgk_make_block (h, new_internal);
|
||||||
|
}
|
||||||
|
|
||||||
|
this_zero->my_block = new_internal->my_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
fgk_eliminate_zero (h, this_zero);
|
||||||
|
|
||||||
|
new_internal->left_child = h->remaining_zeros;
|
||||||
|
|
||||||
|
this_zero->right = new_internal;
|
||||||
|
this_zero->left = h->remaining_zeros;
|
||||||
|
this_zero->parent = new_internal;
|
||||||
|
this_zero->left_child = NULL;
|
||||||
|
this_zero->right_child = NULL;
|
||||||
|
|
||||||
|
h->remaining_zeros->parent = new_internal;
|
||||||
|
h->remaining_zeros->right = this_zero;
|
||||||
|
|
||||||
|
return this_zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When a zero frequency element is encoded, it is followed by the
|
||||||
|
* binary representation of the index into the remaining elements.
|
||||||
|
* Sets a cache to the element before it so that it can be removed
|
||||||
|
* without calling this procedure again. */
|
||||||
|
static unsigned int fgk_find_nth_zero (fgk_stream* h, usize_t n)
|
||||||
|
{
|
||||||
|
fgk_node *target_ptr = h->alphabet + n;
|
||||||
|
fgk_node *head_ptr = h->remaining_zeros;
|
||||||
|
unsigned int idx = 0;
|
||||||
|
|
||||||
|
while (target_ptr != head_ptr)
|
||||||
|
{
|
||||||
|
head_ptr = head_ptr->right_child;
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Splices node out of the list of zeros. */
|
||||||
|
static void fgk_eliminate_zero (fgk_stream* h, fgk_node *node)
|
||||||
|
{
|
||||||
|
if (h->zero_freq_count == 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fgk_factor_remaining(h);
|
||||||
|
|
||||||
|
if (node->left_child == NULL)
|
||||||
|
{
|
||||||
|
h->remaining_zeros = h->remaining_zeros->right_child;
|
||||||
|
h->remaining_zeros->left_child = NULL;
|
||||||
|
}
|
||||||
|
else if (node->right_child == NULL)
|
||||||
|
{
|
||||||
|
node->left_child->right_child = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node->right_child->left_child = node->left_child;
|
||||||
|
node->left_child->right_child = node->right_child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fgk_init_node (fgk_node *node, usize_t i, usize_t size)
|
||||||
|
{
|
||||||
|
if (i < size - 1)
|
||||||
|
{
|
||||||
|
node->right_child = node + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node->right_child = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= 1)
|
||||||
|
{
|
||||||
|
node->left_child = node - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node->left_child = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->weight = 0;
|
||||||
|
node->parent = NULL;
|
||||||
|
node->right = NULL;
|
||||||
|
node->left = NULL;
|
||||||
|
node->my_block = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The data structure used is an array of blocks, which are unions of
|
||||||
|
* free pointers and huffnode pointers. free blocks are a linked list
|
||||||
|
* of free blocks, the front of which is h->free_block. The used
|
||||||
|
* blocks are pointers to the head of each block. */
|
||||||
|
static fgk_block* fgk_make_block (fgk_stream *h, fgk_node* lead)
|
||||||
|
{
|
||||||
|
fgk_block *ret = h->free_block;
|
||||||
|
|
||||||
|
XD3_ASSERT (h->free_block != NULL);
|
||||||
|
|
||||||
|
h->free_block = h->free_block->block_freeptr;
|
||||||
|
|
||||||
|
ret->block_leader = lead;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restores the block to the front of the free list. */
|
||||||
|
static void fgk_free_block (fgk_stream *h, fgk_block *b)
|
||||||
|
{
|
||||||
|
b->block_freeptr = h->free_block;
|
||||||
|
h->free_block = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sets zero_freq_count, zero_freq_rem, and zero_freq_exp to satsity
|
||||||
|
* the equation given above. */
|
||||||
|
static void fgk_factor_remaining (fgk_stream *h)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
i = (--h->zero_freq_count);
|
||||||
|
h->zero_freq_exp = 0;
|
||||||
|
|
||||||
|
while (i > 1)
|
||||||
|
{
|
||||||
|
h->zero_freq_exp += 1;
|
||||||
|
i >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 1 << h->zero_freq_exp;
|
||||||
|
|
||||||
|
h->zero_freq_rem = h->zero_freq_count - i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* receives a bit at a time and returns true when a complete code has
|
||||||
|
* been received.
|
||||||
|
*/
|
||||||
|
static inline int fgk_decode_bit (fgk_stream* h, fgk_bit b)
|
||||||
|
{
|
||||||
|
XD3_ASSERT (b == 1 || b == 0);
|
||||||
|
|
||||||
|
if (IS_ADAPTIVE && h->decode_ptr->weight == 0)
|
||||||
|
{
|
||||||
|
usize_t bitsreq;
|
||||||
|
|
||||||
|
if (h->zero_freq_rem == 0)
|
||||||
|
{
|
||||||
|
bitsreq = h->zero_freq_exp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bitsreq = h->zero_freq_exp + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
h->coded_bits[h->coded_depth] = b;
|
||||||
|
h->coded_depth += 1;
|
||||||
|
|
||||||
|
return h->coded_depth >= bitsreq;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (b)
|
||||||
|
{
|
||||||
|
h->decode_ptr = h->decode_ptr->right_child;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
h->decode_ptr = h->decode_ptr->left_child;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h->decode_ptr->left_child == NULL)
|
||||||
|
{
|
||||||
|
/* If the weight is non-zero, finished. */
|
||||||
|
if (h->decode_ptr->weight != 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* zero_freq_count is dropping to 0, finished. */
|
||||||
|
return h->zero_freq_count == 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static usize_t fgk_nth_zero (fgk_stream* h, usize_t n)
|
||||||
|
{
|
||||||
|
fgk_node *ret = h->remaining_zeros;
|
||||||
|
|
||||||
|
/* ERROR: if during this loop (ret->right_child == NULL) then the
|
||||||
|
* encoder's zero count is too high. Could return an error code
|
||||||
|
* now, but is probably unnecessary overhead, since the caller
|
||||||
|
* should check integrity anyway. */
|
||||||
|
for (; n != 0 && ret->right_child != NULL; n -= 1)
|
||||||
|
{
|
||||||
|
ret = ret->right_child;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (usize_t)(ret - h->alphabet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* once fgk_decode_bit returns 1, this retrieves an index into the
|
||||||
|
* alphabet otherwise this returns 0, indicating more bits are
|
||||||
|
* required.
|
||||||
|
*/
|
||||||
|
static usize_t fgk_decode_data (fgk_stream* h)
|
||||||
|
{
|
||||||
|
usize_t elt = (usize_t)(h->decode_ptr - h->alphabet);
|
||||||
|
|
||||||
|
if (IS_ADAPTIVE && h->decode_ptr->weight == 0) {
|
||||||
|
usize_t i = 0;
|
||||||
|
usize_t n = 0;
|
||||||
|
|
||||||
|
if (h->coded_depth > 0)
|
||||||
|
{
|
||||||
|
for (; i < h->coded_depth - 1; i += 1)
|
||||||
|
{
|
||||||
|
n |= h->coded_bits[i];
|
||||||
|
n <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n |= h->coded_bits[i];
|
||||||
|
elt = fgk_nth_zero(h, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
h->coded_depth = 0;
|
||||||
|
|
||||||
|
if (IS_ADAPTIVE)
|
||||||
|
{
|
||||||
|
fgk_update_tree(h, elt);
|
||||||
|
}
|
||||||
|
|
||||||
|
h->decode_ptr = h->root_node;
|
||||||
|
|
||||||
|
return elt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fgk_destroy (xd3_stream *stream,
|
||||||
|
fgk_stream *h)
|
||||||
|
{
|
||||||
|
if (h != NULL)
|
||||||
|
{
|
||||||
|
xd3_free (stream, h->alphabet);
|
||||||
|
xd3_free (stream, h->coded_bits);
|
||||||
|
xd3_free (stream, h->block_array);
|
||||||
|
xd3_free (stream, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
/* Xdelta */
|
||||||
|
/*********************************************************************/
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_encode_fgk (xd3_stream *stream, fgk_stream *sec_stream, xd3_output *input, xd3_output *output, xd3_sec_cfg *cfg)
|
||||||
|
{
|
||||||
|
bit_state bstate = BIT_STATE_ENCODE_INIT;
|
||||||
|
xd3_output *cur_page;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* OPT: quit compression early if it looks bad */
|
||||||
|
for (cur_page = input; cur_page; cur_page = cur_page->next_page)
|
||||||
|
{
|
||||||
|
const uint8_t *inp = cur_page->base;
|
||||||
|
const uint8_t *inp_max = inp + cur_page->next;
|
||||||
|
|
||||||
|
while (inp < inp_max)
|
||||||
|
{
|
||||||
|
usize_t bits = fgk_encode_data (sec_stream, *inp++);
|
||||||
|
|
||||||
|
while (bits--)
|
||||||
|
{
|
||||||
|
if ((ret = xd3_encode_bit (stream, & output, & bstate, fgk_get_encoded_bit (sec_stream)))) { return ret; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return xd3_flush_bits (stream, & output, & bstate);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_decode_fgk (xd3_stream *stream,
|
||||||
|
fgk_stream *sec_stream,
|
||||||
|
const uint8_t **input_pos,
|
||||||
|
const uint8_t *const input_max,
|
||||||
|
uint8_t **output_pos,
|
||||||
|
const uint8_t *const output_max)
|
||||||
|
{
|
||||||
|
bit_state bstate;
|
||||||
|
uint8_t *output = *output_pos;
|
||||||
|
const uint8_t *input = *input_pos;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (input == input_max)
|
||||||
|
{
|
||||||
|
stream->msg = "secondary decoder end of input";
|
||||||
|
return XD3_INTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bstate.cur_byte = *input++;
|
||||||
|
|
||||||
|
for (bstate.cur_mask = 1; bstate.cur_mask != 0x100; bstate.cur_mask <<= 1)
|
||||||
|
{
|
||||||
|
int done = fgk_decode_bit (sec_stream, (bstate.cur_byte & bstate.cur_mask) ? 1U : 0U);
|
||||||
|
|
||||||
|
if (! done) { continue; }
|
||||||
|
|
||||||
|
*output++ = fgk_decode_data (sec_stream);
|
||||||
|
|
||||||
|
if (output == output_max)
|
||||||
|
{
|
||||||
|
/* During regression testing: */
|
||||||
|
IF_REGRESSION ({
|
||||||
|
int ret;
|
||||||
|
bstate.cur_mask <<= 1;
|
||||||
|
if ((ret = xd3_test_clean_bits (stream, & bstate))) { return ret; }
|
||||||
|
});
|
||||||
|
|
||||||
|
(*output_pos) = output;
|
||||||
|
(*input_pos) = input;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _XDELTA3_FGK_ */
|
159
lib/xdelta3/xdelta3-hash.h
Normal file
159
lib/xdelta3/xdelta3-hash.h
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
/* xdelta3 - delta compression tools and library
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#ifndef _XDELTA3_HASH_H_
|
||||||
|
#define _XDELTA3_HASH_H_
|
||||||
|
|
||||||
|
#include "xdelta3-internal.h"
|
||||||
|
|
||||||
|
#if XD3_DEBUG
|
||||||
|
#define SMALL_HASH_DEBUG1(s,inp) \
|
||||||
|
uint32_t debug_state; \
|
||||||
|
uint32_t debug_hval = xd3_checksum_hash (& (s)->small_hash, \
|
||||||
|
xd3_scksum (&debug_state, (inp), (s)->smatcher.small_look))
|
||||||
|
#define SMALL_HASH_DEBUG2(s,inp) \
|
||||||
|
XD3_ASSERT (debug_hval == xd3_checksum_hash (& (s)->small_hash, \
|
||||||
|
xd3_scksum (&debug_state, (inp), (s)->smatcher.small_look)))
|
||||||
|
#else
|
||||||
|
#define SMALL_HASH_DEBUG1(s,inp)
|
||||||
|
#define SMALL_HASH_DEBUG2(s,inp)
|
||||||
|
#endif /* XD3_DEBUG */
|
||||||
|
|
||||||
|
#if UNALIGNED_OK
|
||||||
|
#define UNALIGNED_READ32(dest,src) (*(dest)) = (*(uint32_t*)(src))
|
||||||
|
#else
|
||||||
|
#define UNALIGNED_READ32(dest,src) memcpy((dest), (src), 4);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* These are good hash multipliers for 32-bit and 64-bit LCGs: see
|
||||||
|
* "linear congruential generators of different sizes and good lattice
|
||||||
|
* structure" */
|
||||||
|
#define xd3_hash_multiplier32 1597334677U
|
||||||
|
#define xd3_hash_multiplier64 1181783497276652981ULL
|
||||||
|
|
||||||
|
/* TODO: small cksum is hard-coded for 4 bytes (i.e., "look" is unused) */
|
||||||
|
static inline uint32_t
|
||||||
|
xd3_scksum (uint32_t *state,
|
||||||
|
const uint8_t *base,
|
||||||
|
const usize_t look)
|
||||||
|
{
|
||||||
|
UNALIGNED_READ32(state, base);
|
||||||
|
return (*state) * xd3_hash_multiplier32;
|
||||||
|
}
|
||||||
|
static inline uint32_t
|
||||||
|
xd3_small_cksum_update (uint32_t *state,
|
||||||
|
const uint8_t *base,
|
||||||
|
usize_t look)
|
||||||
|
{
|
||||||
|
UNALIGNED_READ32(state, base+1);
|
||||||
|
return (*state) * xd3_hash_multiplier32;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if XD3_ENCODER
|
||||||
|
inline usize_t
|
||||||
|
xd3_checksum_hash (const xd3_hash_cfg *cfg, const usize_t cksum)
|
||||||
|
{
|
||||||
|
return (cksum >> cfg->shift) ^ (cksum & cfg->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SIZEOF_USIZE_T == 4
|
||||||
|
inline uint32_t
|
||||||
|
xd3_large32_cksum (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look)
|
||||||
|
{
|
||||||
|
uint32_t h = 0;
|
||||||
|
for (usize_t i = 0; i < look; i++) {
|
||||||
|
h += base[i] * cfg->powers[i];
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t
|
||||||
|
xd3_large32_cksum_update (xd3_hash_cfg *cfg, const uint32_t cksum,
|
||||||
|
const uint8_t *base, const usize_t look)
|
||||||
|
{
|
||||||
|
return xd3_hash_multiplier32 * cksum - cfg->multiplier * base[0] + base[look];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SIZEOF_USIZE_T == 8
|
||||||
|
inline uint64_t
|
||||||
|
xd3_large64_cksum (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look)
|
||||||
|
{
|
||||||
|
uint64_t h = 0;
|
||||||
|
for (usize_t i = 0; i < look; i++) {
|
||||||
|
h += base[i] * cfg->powers[i];
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t
|
||||||
|
xd3_large64_cksum_update (xd3_hash_cfg *cfg, const uint64_t cksum,
|
||||||
|
const uint8_t *base, const usize_t look)
|
||||||
|
{
|
||||||
|
return xd3_hash_multiplier64 * cksum - cfg->multiplier * base[0] + base[look];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static usize_t
|
||||||
|
xd3_size_hashtable_bits (usize_t slots)
|
||||||
|
{
|
||||||
|
usize_t bits = (SIZEOF_USIZE_T * 8) - 1;
|
||||||
|
usize_t i;
|
||||||
|
|
||||||
|
for (i = 3; i <= bits; i += 1)
|
||||||
|
{
|
||||||
|
if (slots < (1U << i))
|
||||||
|
{
|
||||||
|
/* Note: this is the compaction=1 setting measured in
|
||||||
|
* checksum_test */
|
||||||
|
bits = i - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xd3_size_hashtable (xd3_stream *stream,
|
||||||
|
usize_t slots,
|
||||||
|
usize_t look,
|
||||||
|
xd3_hash_cfg *cfg)
|
||||||
|
{
|
||||||
|
usize_t bits = xd3_size_hashtable_bits (slots);
|
||||||
|
|
||||||
|
cfg->size = (1U << bits);
|
||||||
|
cfg->mask = (cfg->size - 1);
|
||||||
|
cfg->shift = (SIZEOF_USIZE_T * 8) - bits;
|
||||||
|
cfg->look = look;
|
||||||
|
|
||||||
|
if ((cfg->powers =
|
||||||
|
(usize_t*) xd3_alloc0 (stream, look, sizeof (usize_t))) == NULL)
|
||||||
|
{
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg->powers[look-1] = 1;
|
||||||
|
for (int i = look-2; i >= 0; i--)
|
||||||
|
{
|
||||||
|
cfg->powers[i] = cfg->powers[i+1] * xd3_hash_multiplier;
|
||||||
|
}
|
||||||
|
cfg->multiplier = cfg->powers[0] * xd3_hash_multiplier;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* XD3_ENCODER */
|
||||||
|
#endif /* _XDELTA3_HASH_H_ */
|
385
lib/xdelta3/xdelta3-internal.h
Normal file
385
lib/xdelta3/xdelta3-internal.h
Normal file
|
@ -0,0 +1,385 @@
|
||||||
|
/* xdelta3 - delta compression tools and library
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#ifndef XDELTA3_INTERNAL_H__
|
||||||
|
#define XDELTA3_INTERNAL_H__
|
||||||
|
|
||||||
|
#include "xdelta3.h"
|
||||||
|
|
||||||
|
typedef struct _main_file main_file;
|
||||||
|
typedef struct _main_extcomp main_extcomp;
|
||||||
|
|
||||||
|
void main_buffree (void *ptr);
|
||||||
|
void* main_bufalloc (size_t size);
|
||||||
|
void main_file_init (main_file *xfile);
|
||||||
|
int main_file_close (main_file *xfile);
|
||||||
|
void main_file_cleanup (main_file *xfile);
|
||||||
|
int main_file_isopen (main_file *xfile);
|
||||||
|
int main_file_open (main_file *xfile, const char* name, int mode);
|
||||||
|
int main_file_exists (main_file *xfile);
|
||||||
|
int main_file_stat (main_file *xfile, xoff_t *size);
|
||||||
|
int xd3_whole_append_window (xd3_stream *stream);
|
||||||
|
int xd3_main_cmdline (int argc, char **argv);
|
||||||
|
int main_file_read (main_file *ifile,
|
||||||
|
uint8_t *buf,
|
||||||
|
size_t size,
|
||||||
|
size_t *nread,
|
||||||
|
const char *msg);
|
||||||
|
int main_file_write (main_file *ofile, uint8_t *buf,
|
||||||
|
usize_t size, const char *msg);
|
||||||
|
void* main_malloc (size_t size);
|
||||||
|
void main_free (void *ptr);
|
||||||
|
|
||||||
|
int test_compare_files (const char* f0, const char* f1);
|
||||||
|
usize_t xd3_bytes_on_srcblk (xd3_source *src, xoff_t blkno);
|
||||||
|
xoff_t xd3_source_eof(const xd3_source *src);
|
||||||
|
|
||||||
|
uint32_t xd3_large_cksum_update (uint32_t cksum,
|
||||||
|
const uint8_t *base,
|
||||||
|
usize_t look);
|
||||||
|
int xd3_emit_byte (xd3_stream *stream,
|
||||||
|
xd3_output **outputp,
|
||||||
|
uint8_t code);
|
||||||
|
|
||||||
|
int xd3_emit_bytes (xd3_stream *stream,
|
||||||
|
xd3_output **outputp,
|
||||||
|
const uint8_t *base,
|
||||||
|
usize_t size);
|
||||||
|
xd3_output* xd3_alloc_output (xd3_stream *stream,
|
||||||
|
xd3_output *old_output);
|
||||||
|
|
||||||
|
int xd3_encode_init_full (xd3_stream *stream);
|
||||||
|
usize_t xd3_pow2_roundup (usize_t x);
|
||||||
|
long get_millisecs_now (void);
|
||||||
|
int xd3_process_stream (int is_encode,
|
||||||
|
xd3_stream *stream,
|
||||||
|
int (*func) (xd3_stream *),
|
||||||
|
int close_stream,
|
||||||
|
const uint8_t *input,
|
||||||
|
usize_t input_size,
|
||||||
|
uint8_t *output,
|
||||||
|
usize_t *output_size,
|
||||||
|
usize_t output_size_max);
|
||||||
|
|
||||||
|
#if PYTHON_MODULE || SWIG_MODULE || NOT_MAIN
|
||||||
|
int xd3_main_cmdline (int argc, char **argv);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if REGRESSION_TEST
|
||||||
|
int xd3_selftest (void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* main_file->mode values */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
XO_READ = 0,
|
||||||
|
XO_WRITE = 1
|
||||||
|
} main_file_modes;
|
||||||
|
|
||||||
|
#ifndef XD3_POSIX
|
||||||
|
#define XD3_POSIX 0
|
||||||
|
#endif
|
||||||
|
#ifndef XD3_STDIO
|
||||||
|
#define XD3_STDIO 0
|
||||||
|
#endif
|
||||||
|
#ifndef XD3_WIN32
|
||||||
|
#define XD3_WIN32 0
|
||||||
|
#endif
|
||||||
|
#ifndef NOT_MAIN
|
||||||
|
#define NOT_MAIN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If none are set, default to posix. */
|
||||||
|
#if (XD3_POSIX + XD3_STDIO + XD3_WIN32) == 0
|
||||||
|
#undef XD3_POSIX
|
||||||
|
#define XD3_POSIX 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct _main_file
|
||||||
|
{
|
||||||
|
#if XD3_WIN32
|
||||||
|
HANDLE file;
|
||||||
|
#elif XD3_STDIO
|
||||||
|
FILE *file;
|
||||||
|
#elif XD3_POSIX
|
||||||
|
int file;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int mode; /* XO_READ and XO_WRITE */
|
||||||
|
const char *filename; /* File name or /dev/stdin,
|
||||||
|
* /dev/stdout, /dev/stderr. */
|
||||||
|
char *filename_copy; /* File name or /dev/stdin,
|
||||||
|
* /dev/stdout, /dev/stderr. */
|
||||||
|
const char *realname; /* File name or /dev/stdin,
|
||||||
|
* /dev/stdout, /dev/stderr. */
|
||||||
|
const main_extcomp *compressor; /* External compression struct. */
|
||||||
|
int flags; /* RD_FIRST, RD_NONEXTERNAL, ... */
|
||||||
|
xoff_t nread; /* for input position */
|
||||||
|
xoff_t nwrite; /* for output position */
|
||||||
|
uint8_t *snprintf_buf; /* internal snprintf() use */
|
||||||
|
int size_known; /* Set by main_set_souze */
|
||||||
|
xoff_t source_position; /* for avoiding seek in getblk_func */
|
||||||
|
int seek_failed; /* after seek fails once, try FIFO */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef UINT32_MAX
|
||||||
|
#define UINT32_MAX 4294967295U
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef UINT64_MAX
|
||||||
|
#define UINT64_MAX 18446744073709551615ULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define UINT32_OFLOW_MASK 0xfe000000U
|
||||||
|
#define UINT64_OFLOW_MASK 0xfe00000000000000ULL
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
Integer encoder/decoder functions
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
/* Consume N bytes of input, only used by the decoder. */
|
||||||
|
#define DECODE_INPUT(n) \
|
||||||
|
do { \
|
||||||
|
stream->total_in += (xoff_t) (n); \
|
||||||
|
stream->avail_in -= (n); \
|
||||||
|
stream->next_in += (n); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DECODE_INTEGER_TYPE(PART,OFLOW) \
|
||||||
|
while (stream->avail_in != 0) \
|
||||||
|
{ \
|
||||||
|
usize_t next = stream->next_in[0]; \
|
||||||
|
\
|
||||||
|
DECODE_INPUT(1); \
|
||||||
|
\
|
||||||
|
if (PART & OFLOW) \
|
||||||
|
{ \
|
||||||
|
stream->msg = "overflow in decode_integer"; \
|
||||||
|
return XD3_INVALID_INPUT; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
PART = (PART << 7) | (next & 127); \
|
||||||
|
\
|
||||||
|
if ((next & 128) == 0) \
|
||||||
|
{ \
|
||||||
|
(*val) = PART; \
|
||||||
|
PART = 0; \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
stream->msg = "further input required"; \
|
||||||
|
return XD3_INPUT
|
||||||
|
|
||||||
|
#define READ_INTEGER_TYPE(TYPE, OFLOW) \
|
||||||
|
TYPE val = 0; \
|
||||||
|
const uint8_t *inp = (*inpp); \
|
||||||
|
usize_t next; \
|
||||||
|
\
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (inp == maxp) \
|
||||||
|
{ \
|
||||||
|
stream->msg = "end-of-input in read_integer"; \
|
||||||
|
return XD3_INVALID_INPUT; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (val & OFLOW) \
|
||||||
|
{ \
|
||||||
|
stream->msg = "overflow in read_intger"; \
|
||||||
|
return XD3_INVALID_INPUT; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
next = (*inp++); \
|
||||||
|
val = (val << 7) | (next & 127); \
|
||||||
|
} \
|
||||||
|
while (next & 128); \
|
||||||
|
\
|
||||||
|
(*valp) = val; \
|
||||||
|
(*inpp) = inp; \
|
||||||
|
\
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#define EMIT_INTEGER_TYPE() \
|
||||||
|
/* max 64-bit value in base-7 encoding is 9.1 bytes */ \
|
||||||
|
uint8_t buf[10]; \
|
||||||
|
usize_t bufi = 10; \
|
||||||
|
\
|
||||||
|
/* This loop performs division and turns on all MSBs. */ \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
buf[--bufi] = (num & 127) | 128; \
|
||||||
|
num >>= 7U; \
|
||||||
|
} \
|
||||||
|
while (num != 0); \
|
||||||
|
\
|
||||||
|
/* Turn off MSB of the last byte. */ \
|
||||||
|
buf[9] &= 127; \
|
||||||
|
\
|
||||||
|
return xd3_emit_bytes (stream, output, buf + bufi, 10 - bufi)
|
||||||
|
|
||||||
|
#define IF_SIZEOF32(x) if (num < (1U << (7 * (x)))) return (x);
|
||||||
|
#define IF_SIZEOF64(x) if (num < (1ULL << (7 * (x)))) return (x);
|
||||||
|
|
||||||
|
#if USE_UINT32
|
||||||
|
static inline uint32_t
|
||||||
|
xd3_sizeof_uint32_t (uint32_t num)
|
||||||
|
{
|
||||||
|
IF_SIZEOF32(1);
|
||||||
|
IF_SIZEOF32(2);
|
||||||
|
IF_SIZEOF32(3);
|
||||||
|
IF_SIZEOF32(4);
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
xd3_decode_uint32_t (xd3_stream *stream, uint32_t *val)
|
||||||
|
{ DECODE_INTEGER_TYPE (stream->dec_32part, UINT32_OFLOW_MASK); }
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
xd3_read_uint32_t (xd3_stream *stream, const uint8_t **inpp,
|
||||||
|
const uint8_t *maxp, uint32_t *valp)
|
||||||
|
{ READ_INTEGER_TYPE (uint32_t, UINT32_OFLOW_MASK); }
|
||||||
|
|
||||||
|
#if XD3_ENCODER
|
||||||
|
static inline int
|
||||||
|
xd3_emit_uint32_t (xd3_stream *stream, xd3_output **output, uint32_t num)
|
||||||
|
{ EMIT_INTEGER_TYPE (); }
|
||||||
|
#endif /* XD3_ENCODER */
|
||||||
|
#endif /* USE_UINT32 */
|
||||||
|
|
||||||
|
#if USE_UINT64
|
||||||
|
static inline uint32_t
|
||||||
|
xd3_sizeof_uint64_t (uint64_t num)
|
||||||
|
{
|
||||||
|
IF_SIZEOF64(1);
|
||||||
|
IF_SIZEOF64(2);
|
||||||
|
IF_SIZEOF64(3);
|
||||||
|
IF_SIZEOF64(4);
|
||||||
|
IF_SIZEOF64(5);
|
||||||
|
IF_SIZEOF64(6);
|
||||||
|
IF_SIZEOF64(7);
|
||||||
|
IF_SIZEOF64(8);
|
||||||
|
IF_SIZEOF64(9);
|
||||||
|
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
xd3_decode_uint64_t (xd3_stream *stream, uint64_t *val)
|
||||||
|
{ DECODE_INTEGER_TYPE (stream->dec_64part, UINT64_OFLOW_MASK); }
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
xd3_read_uint64_t (xd3_stream *stream, const uint8_t **inpp,
|
||||||
|
const uint8_t *maxp, uint64_t *valp)
|
||||||
|
{ READ_INTEGER_TYPE (uint64_t, UINT64_OFLOW_MASK); }
|
||||||
|
|
||||||
|
#if XD3_ENCODER
|
||||||
|
static inline int
|
||||||
|
xd3_emit_uint64_t (xd3_stream *stream, xd3_output **output, uint64_t num)
|
||||||
|
{ EMIT_INTEGER_TYPE (); }
|
||||||
|
#endif /* XD3_ENCODER */
|
||||||
|
#endif /* USE_UINT64 */
|
||||||
|
|
||||||
|
#if SIZEOF_USIZE_T == 4
|
||||||
|
#define USIZE_T_MAX UINT32_MAX
|
||||||
|
#define USIZE_T_MAXBLKSZ 0x80000000U
|
||||||
|
#define XD3_MAXSRCWINSZ (1ULL << 31)
|
||||||
|
#define xd3_large_cksum xd3_large32_cksum
|
||||||
|
#define xd3_large_cksum_update xd3_large32_cksum_update
|
||||||
|
#define xd3_hash_multiplier xd3_hash_multiplier32
|
||||||
|
|
||||||
|
static inline uint32_t xd3_sizeof_size (usize_t num)
|
||||||
|
{ return xd3_sizeof_uint32_t (num); }
|
||||||
|
static inline int xd3_decode_size (xd3_stream *stream, usize_t *valp)
|
||||||
|
{ return xd3_decode_uint32_t (stream, (uint32_t*) valp); }
|
||||||
|
static inline int xd3_read_size (xd3_stream *stream, const uint8_t **inpp,
|
||||||
|
const uint8_t *maxp, usize_t *valp)
|
||||||
|
{ return xd3_read_uint32_t (stream, inpp, maxp, (uint32_t*) valp); }
|
||||||
|
#if XD3_ENCODER
|
||||||
|
static inline int xd3_emit_size (xd3_stream *stream, xd3_output **output, usize_t num)
|
||||||
|
{ return xd3_emit_uint32_t (stream, output, num); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif SIZEOF_USIZE_T == 8
|
||||||
|
#define USIZE_T_MAX UINT64_MAX
|
||||||
|
#define USIZE_T_MAXBLKSZ 0x8000000000000000ULL
|
||||||
|
#define XD3_MAXSRCWINSZ (1ULL << 61)
|
||||||
|
#define xd3_large_cksum xd3_large64_cksum
|
||||||
|
#define xd3_large_cksum_update xd3_large64_cksum_update
|
||||||
|
#define xd3_hash_multiplier xd3_hash_multiplier64
|
||||||
|
|
||||||
|
static inline uint32_t xd3_sizeof_size (usize_t num)
|
||||||
|
{ return xd3_sizeof_uint64_t (num); }
|
||||||
|
static inline int xd3_decode_size (xd3_stream *stream, usize_t *valp)
|
||||||
|
{ return xd3_decode_uint64_t (stream, (uint64_t*) valp); }
|
||||||
|
static inline int xd3_read_size (xd3_stream *stream, const uint8_t **inpp,
|
||||||
|
const uint8_t *maxp, usize_t *valp)
|
||||||
|
{ return xd3_read_uint64_t (stream, inpp, maxp, (uint64_t*) valp); }
|
||||||
|
#if XD3_ENCODER
|
||||||
|
static inline int xd3_emit_size (xd3_stream *stream, xd3_output **output, usize_t num)
|
||||||
|
{ return xd3_emit_uint64_t (stream, output, num); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SIZEOF_USIZE_T */
|
||||||
|
|
||||||
|
#if SIZEOF_XOFF_T == 4
|
||||||
|
#define XOFF_T_MAX UINT32_MAX
|
||||||
|
|
||||||
|
static inline int xd3_decode_offset (xd3_stream *stream, xoff_t *valp)
|
||||||
|
{ return xd3_decode_uint32_t (stream, (uint32_t*) valp); }
|
||||||
|
#if XD3_ENCODER
|
||||||
|
static inline int xd3_emit_offset (xd3_stream *stream, xd3_output **output, xoff_t num)
|
||||||
|
{ return xd3_emit_uint32_t (stream, output, num); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif SIZEOF_XOFF_T == 8
|
||||||
|
#define XOFF_T_MAX UINT64_MAX
|
||||||
|
|
||||||
|
static inline int xd3_decode_offset (xd3_stream *stream, xoff_t *valp)
|
||||||
|
{ return xd3_decode_uint64_t (stream, (uint64_t*) valp); }
|
||||||
|
#if XD3_ENCODER
|
||||||
|
static inline int xd3_emit_offset (xd3_stream *stream, xd3_output **output, xoff_t num)
|
||||||
|
{ return xd3_emit_uint64_t (stream, output, num); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define USIZE_T_OVERFLOW(a,b) ((USIZE_T_MAX - (usize_t) (a)) < (usize_t) (b))
|
||||||
|
#define XOFF_T_OVERFLOW(a,b) ((XOFF_T_MAX - (xoff_t) (a)) < (xoff_t) (b))
|
||||||
|
|
||||||
|
int xd3_size_hashtable (xd3_stream *stream,
|
||||||
|
usize_t slots,
|
||||||
|
usize_t look,
|
||||||
|
xd3_hash_cfg *cfg);
|
||||||
|
|
||||||
|
usize_t xd3_checksum_hash (const xd3_hash_cfg *cfg, const usize_t cksum);
|
||||||
|
|
||||||
|
#if USE_UINT32
|
||||||
|
uint32_t xd3_large32_cksum (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look);
|
||||||
|
uint32_t xd3_large32_cksum_update (xd3_hash_cfg *cfg, const uint32_t cksum,
|
||||||
|
const uint8_t *base, const usize_t look);
|
||||||
|
#endif /* USE_UINT32 */
|
||||||
|
|
||||||
|
#if USE_UINT64
|
||||||
|
uint64_t xd3_large64_cksum (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look);
|
||||||
|
uint64_t xd3_large64_cksum_update (xd3_hash_cfg *cfg, const uint64_t cksum,
|
||||||
|
const uint8_t *base, const usize_t look);
|
||||||
|
#endif /* USE_UINT64 */
|
||||||
|
|
||||||
|
#define MAX_LRU_SIZE 32U
|
||||||
|
#define XD3_MINSRCWINSZ (XD3_ALLOCSIZE * MAX_LRU_SIZE)
|
||||||
|
|
||||||
|
#endif // XDELTA3_INTERNAL_H__
|
127
lib/xdelta3/xdelta3-list.h
Normal file
127
lib/xdelta3/xdelta3-list.h
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
/* xdelta3 - delta compression tools and library
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#ifndef __XDELTA3_LIST__
|
||||||
|
#define __XDELTA3_LIST__
|
||||||
|
|
||||||
|
#define XD3_MAKELIST(LTYPE,ETYPE,LNAME) \
|
||||||
|
\
|
||||||
|
static inline ETYPE* \
|
||||||
|
LTYPE ## _entry (LTYPE* l) \
|
||||||
|
{ \
|
||||||
|
return (ETYPE*) ((char*) l - (ptrdiff_t) &((ETYPE*) 0)->LNAME); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
LTYPE ## _init (LTYPE *l) \
|
||||||
|
{ \
|
||||||
|
l->next = l; \
|
||||||
|
l->prev = l; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
LTYPE ## _add (LTYPE *prev, LTYPE *next, LTYPE *ins) \
|
||||||
|
{ \
|
||||||
|
next->prev = ins; \
|
||||||
|
prev->next = ins; \
|
||||||
|
ins->next = next; \
|
||||||
|
ins->prev = prev; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
LTYPE ## _push_back (LTYPE *l, ETYPE *i) \
|
||||||
|
{ \
|
||||||
|
LTYPE ## _add (l->prev, l, & i->LNAME); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
LTYPE ## _del (LTYPE *next, \
|
||||||
|
LTYPE *prev) \
|
||||||
|
{ \
|
||||||
|
next->prev = prev; \
|
||||||
|
prev->next = next; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline ETYPE* \
|
||||||
|
LTYPE ## _remove (ETYPE *f) \
|
||||||
|
{ \
|
||||||
|
LTYPE *i = f->LNAME.next; \
|
||||||
|
LTYPE ## _del (f->LNAME.next, f->LNAME.prev); \
|
||||||
|
return LTYPE ## _entry (i); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline ETYPE* \
|
||||||
|
LTYPE ## _pop_back (LTYPE *l) \
|
||||||
|
{ \
|
||||||
|
LTYPE *i = l->prev; \
|
||||||
|
LTYPE ## _del (i->next, i->prev); \
|
||||||
|
return LTYPE ## _entry (i); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline ETYPE* \
|
||||||
|
LTYPE ## _pop_front (LTYPE *l) \
|
||||||
|
{ \
|
||||||
|
LTYPE *i = l->next; \
|
||||||
|
LTYPE ## _del (i->next, i->prev); \
|
||||||
|
return LTYPE ## _entry (i); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline int \
|
||||||
|
LTYPE ## _empty (LTYPE *l) \
|
||||||
|
{ \
|
||||||
|
return l == l->next; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline ETYPE* \
|
||||||
|
LTYPE ## _front (LTYPE *f) \
|
||||||
|
{ \
|
||||||
|
return LTYPE ## _entry (f->next); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline ETYPE* \
|
||||||
|
LTYPE ## _back (LTYPE *f) \
|
||||||
|
{ \
|
||||||
|
return LTYPE ## _entry (f->prev); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline int \
|
||||||
|
LTYPE ## _end (LTYPE *f, ETYPE *i) \
|
||||||
|
{ \
|
||||||
|
return f == & i->LNAME; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline ETYPE* \
|
||||||
|
LTYPE ## _next (ETYPE *f) \
|
||||||
|
{ \
|
||||||
|
return LTYPE ## _entry (f->LNAME.next); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline usize_t \
|
||||||
|
LTYPE ## _length (LTYPE *l) \
|
||||||
|
{ \
|
||||||
|
LTYPE *p; \
|
||||||
|
usize_t c = 0; \
|
||||||
|
\
|
||||||
|
for (p = l->next; p != l; p = p->next) \
|
||||||
|
{ \
|
||||||
|
c += 1; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return c; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
typedef int unused_ ## LTYPE
|
||||||
|
|
||||||
|
#endif
|
195
lib/xdelta3/xdelta3-lzma.h
Normal file
195
lib/xdelta3/xdelta3-lzma.h
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
/* xdelta3 - delta compression tools and library
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Note: The use of the _easy_ decoder means we're not calling the
|
||||||
|
* xd3_stream malloc hooks. TODO(jmacd) Fix if anyone cares. */
|
||||||
|
|
||||||
|
#ifndef _XDELTA3_LZMA_H_
|
||||||
|
#define _XDELTA3_LZMA_H_
|
||||||
|
|
||||||
|
#include <lzma.h>
|
||||||
|
|
||||||
|
typedef struct _xd3_lzma_stream xd3_lzma_stream;
|
||||||
|
|
||||||
|
struct _xd3_lzma_stream {
|
||||||
|
lzma_stream lzma;
|
||||||
|
lzma_options_lzma options;
|
||||||
|
lzma_filter filters[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
static xd3_sec_stream*
|
||||||
|
xd3_lzma_alloc (xd3_stream *stream)
|
||||||
|
{
|
||||||
|
return (xd3_sec_stream*) xd3_alloc (stream, sizeof (xd3_lzma_stream), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xd3_lzma_destroy (xd3_stream *stream, xd3_sec_stream *sec_stream)
|
||||||
|
{
|
||||||
|
xd3_lzma_stream *ls = (xd3_lzma_stream*) sec_stream;
|
||||||
|
lzma_end (&ls->lzma);
|
||||||
|
xd3_free (stream, ls);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_lzma_init (xd3_stream *stream, xd3_lzma_stream *sec, int is_encode)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset (&sec->lzma, 0, sizeof(sec->lzma));
|
||||||
|
|
||||||
|
if (is_encode)
|
||||||
|
{
|
||||||
|
uint32_t preset =
|
||||||
|
(stream->flags & XD3_COMPLEVEL_MASK) >> XD3_COMPLEVEL_SHIFT;
|
||||||
|
|
||||||
|
if (lzma_lzma_preset(&sec->options, preset))
|
||||||
|
{
|
||||||
|
stream->msg = "invalid lzma preset";
|
||||||
|
return XD3_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
sec->filters[0].id = LZMA_FILTER_LZMA2;
|
||||||
|
sec->filters[0].options = &sec->options;
|
||||||
|
sec->filters[1].id = LZMA_VLI_UNKNOWN;
|
||||||
|
|
||||||
|
ret = lzma_stream_encoder (&sec->lzma, &sec->filters[0], LZMA_CHECK_NONE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = lzma_stream_decoder (&sec->lzma, UINT64_MAX, LZMA_TELL_NO_CHECK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != LZMA_OK)
|
||||||
|
{
|
||||||
|
stream->msg = "lzma stream init failed";
|
||||||
|
return XD3_INTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xd3_decode_lzma (xd3_stream *stream, xd3_lzma_stream *sec,
|
||||||
|
const uint8_t **input_pos,
|
||||||
|
const uint8_t *const input_end,
|
||||||
|
uint8_t **output_pos,
|
||||||
|
const uint8_t *const output_end)
|
||||||
|
{
|
||||||
|
uint8_t *output = *output_pos;
|
||||||
|
const uint8_t *input = *input_pos;
|
||||||
|
size_t avail_in = input_end - input;
|
||||||
|
size_t avail_out = output_end - output;
|
||||||
|
|
||||||
|
sec->lzma.avail_in = avail_in;
|
||||||
|
sec->lzma.next_in = input;
|
||||||
|
sec->lzma.avail_out = avail_out;
|
||||||
|
sec->lzma.next_out = output;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int lret = lzma_code (&sec->lzma, LZMA_RUN);
|
||||||
|
|
||||||
|
switch (lret)
|
||||||
|
{
|
||||||
|
case LZMA_NO_CHECK:
|
||||||
|
case LZMA_OK:
|
||||||
|
if (sec->lzma.avail_out == 0)
|
||||||
|
{
|
||||||
|
(*output_pos) = sec->lzma.next_out;
|
||||||
|
(*input_pos) = sec->lzma.next_in;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
stream->msg = "lzma decoding error";
|
||||||
|
return XD3_INTERNAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if XD3_ENCODER
|
||||||
|
|
||||||
|
static int xd3_encode_lzma (xd3_stream *stream,
|
||||||
|
xd3_lzma_stream *sec,
|
||||||
|
xd3_output *input,
|
||||||
|
xd3_output *output,
|
||||||
|
xd3_sec_cfg *cfg)
|
||||||
|
|
||||||
|
{
|
||||||
|
lzma_action action = LZMA_RUN;
|
||||||
|
|
||||||
|
cfg->inefficient = 1; /* Can't skip windows */
|
||||||
|
sec->lzma.next_in = NULL;
|
||||||
|
sec->lzma.avail_in = 0;
|
||||||
|
sec->lzma.next_out = (output->base + output->next);
|
||||||
|
sec->lzma.avail_out = (output->avail - output->next);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int lret;
|
||||||
|
size_t nwrite;
|
||||||
|
if (sec->lzma.avail_in == 0 && input != NULL)
|
||||||
|
{
|
||||||
|
sec->lzma.avail_in = input->next;
|
||||||
|
sec->lzma.next_in = input->base;
|
||||||
|
|
||||||
|
if ((input = input->next_page) == NULL)
|
||||||
|
{
|
||||||
|
action = LZMA_SYNC_FLUSH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lret = lzma_code (&sec->lzma, action);
|
||||||
|
|
||||||
|
nwrite = (output->avail - output->next) - sec->lzma.avail_out;
|
||||||
|
|
||||||
|
if (nwrite != 0)
|
||||||
|
{
|
||||||
|
output->next += nwrite;
|
||||||
|
|
||||||
|
if (output->next == output->avail)
|
||||||
|
{
|
||||||
|
if ((output = xd3_alloc_output (stream, output)) == NULL)
|
||||||
|
{
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
sec->lzma.next_out = output->base;
|
||||||
|
sec->lzma.avail_out = output->avail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (lret)
|
||||||
|
{
|
||||||
|
case LZMA_OK:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LZMA_STREAM_END:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
stream->msg = "lzma encoding error";
|
||||||
|
return XD3_INTERNAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* XD3_ENCODER */
|
||||||
|
|
||||||
|
#endif /* _XDELTA3_LZMA_H_ */
|
4062
lib/xdelta3/xdelta3-main.h
Normal file
4062
lib/xdelta3/xdelta3-main.h
Normal file
File diff suppressed because it is too large
Load diff
583
lib/xdelta3/xdelta3-merge.h
Normal file
583
lib/xdelta3/xdelta3-merge.h
Normal file
|
@ -0,0 +1,583 @@
|
||||||
|
/* xdelta3 - delta compression tools and library
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#ifndef _XDELTA3_MERGE_H_
|
||||||
|
#define _XDELTA3_MERGE_H_
|
||||||
|
|
||||||
|
int xd3_merge_inputs (xd3_stream *stream,
|
||||||
|
xd3_whole_state *source,
|
||||||
|
xd3_whole_state *input);
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_whole_state_init (xd3_stream *stream)
|
||||||
|
{
|
||||||
|
XD3_ASSERT (stream->whole_target.adds == NULL);
|
||||||
|
XD3_ASSERT (stream->whole_target.inst == NULL);
|
||||||
|
XD3_ASSERT (stream->whole_target.wininfo == NULL);
|
||||||
|
XD3_ASSERT (stream->whole_target.length == 0);
|
||||||
|
|
||||||
|
stream->whole_target.adds_alloc = XD3_ALLOCSIZE;
|
||||||
|
stream->whole_target.inst_alloc = XD3_ALLOCSIZE;
|
||||||
|
stream->whole_target.wininfo_alloc = XD3_ALLOCSIZE;
|
||||||
|
|
||||||
|
if ((stream->whole_target.adds = (uint8_t*)
|
||||||
|
xd3_alloc (stream, stream->whole_target.adds_alloc, 1)) == NULL ||
|
||||||
|
(stream->whole_target.inst = (xd3_winst*)
|
||||||
|
xd3_alloc (stream, stream->whole_target.inst_alloc, 1)) == NULL ||
|
||||||
|
(stream->whole_target.wininfo = (xd3_wininfo*)
|
||||||
|
xd3_alloc (stream, stream->whole_target.wininfo_alloc, 1)) == NULL)
|
||||||
|
{
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xd3_swap_whole_state (xd3_whole_state *a,
|
||||||
|
xd3_whole_state *b)
|
||||||
|
{
|
||||||
|
xd3_whole_state tmp;
|
||||||
|
XD3_ASSERT (a->inst != NULL && a->adds != NULL);
|
||||||
|
XD3_ASSERT (b->inst != NULL && b->adds != NULL);
|
||||||
|
XD3_ASSERT (b->wininfo != NULL && b->wininfo != NULL);
|
||||||
|
memcpy (&tmp, a, sizeof (xd3_whole_state));
|
||||||
|
memcpy (a, b, sizeof (xd3_whole_state));
|
||||||
|
memcpy (b, &tmp, sizeof (xd3_whole_state));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_realloc_buffer (xd3_stream *stream,
|
||||||
|
usize_t current_units,
|
||||||
|
usize_t unit_size,
|
||||||
|
usize_t new_units,
|
||||||
|
usize_t *alloc_size,
|
||||||
|
void **alloc_ptr)
|
||||||
|
{
|
||||||
|
usize_t needed;
|
||||||
|
usize_t new_alloc;
|
||||||
|
usize_t cur_size;
|
||||||
|
uint8_t *new_buf;
|
||||||
|
|
||||||
|
needed = (current_units + new_units) * unit_size;
|
||||||
|
|
||||||
|
if (needed <= *alloc_size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_size = current_units * unit_size;
|
||||||
|
new_alloc = xd3_round_blksize (needed * 2, XD3_ALLOCSIZE);
|
||||||
|
|
||||||
|
if ((new_buf = (uint8_t*) xd3_alloc (stream, new_alloc, 1)) == NULL)
|
||||||
|
{
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur_size != 0)
|
||||||
|
{
|
||||||
|
memcpy (new_buf, *alloc_ptr, cur_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*alloc_ptr != NULL)
|
||||||
|
{
|
||||||
|
xd3_free (stream, *alloc_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
*alloc_size = new_alloc;
|
||||||
|
*alloc_ptr = new_buf;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate one new output instruction */
|
||||||
|
static int
|
||||||
|
xd3_whole_alloc_winst (xd3_stream *stream,
|
||||||
|
xd3_winst **winstp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((ret = xd3_realloc_buffer (stream,
|
||||||
|
stream->whole_target.instlen,
|
||||||
|
sizeof (xd3_winst),
|
||||||
|
1,
|
||||||
|
& stream->whole_target.inst_alloc,
|
||||||
|
(void**) & stream->whole_target.inst)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
*winstp = &stream->whole_target.inst[stream->whole_target.instlen++];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_whole_alloc_adds (xd3_stream *stream,
|
||||||
|
usize_t count)
|
||||||
|
{
|
||||||
|
return xd3_realloc_buffer (stream,
|
||||||
|
stream->whole_target.addslen,
|
||||||
|
1,
|
||||||
|
count,
|
||||||
|
& stream->whole_target.adds_alloc,
|
||||||
|
(void**) & stream->whole_target.adds);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_whole_alloc_wininfo (xd3_stream *stream,
|
||||||
|
xd3_wininfo **wininfop)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((ret = xd3_realloc_buffer (stream,
|
||||||
|
stream->whole_target.wininfolen,
|
||||||
|
sizeof (xd3_wininfo),
|
||||||
|
1,
|
||||||
|
& stream->whole_target.wininfo_alloc,
|
||||||
|
(void**) & stream->whole_target.wininfo)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
*wininfop = &stream->whole_target.wininfo[stream->whole_target.wininfolen++];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_whole_append_inst (xd3_stream *stream,
|
||||||
|
xd3_hinst *inst)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
xd3_winst *winst;
|
||||||
|
|
||||||
|
if ((ret = xd3_whole_alloc_winst (stream, &winst)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
winst->type = inst->type;
|
||||||
|
winst->mode = 0;
|
||||||
|
winst->size = inst->size;
|
||||||
|
winst->position = stream->whole_target.length;
|
||||||
|
stream->whole_target.length += inst->size;
|
||||||
|
|
||||||
|
if (((inst->type == XD3_ADD) || (inst->type == XD3_RUN)) &&
|
||||||
|
(ret = xd3_whole_alloc_adds (stream,
|
||||||
|
(inst->type == XD3_RUN ? 1 : inst->size))))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (inst->type)
|
||||||
|
{
|
||||||
|
case XD3_RUN:
|
||||||
|
winst->addr = stream->whole_target.addslen;
|
||||||
|
stream->whole_target.adds[stream->whole_target.addslen++] =
|
||||||
|
*stream->data_sect.buf++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XD3_ADD:
|
||||||
|
winst->addr = stream->whole_target.addslen;
|
||||||
|
memcpy (stream->whole_target.adds + stream->whole_target.addslen,
|
||||||
|
stream->data_sect.buf,
|
||||||
|
inst->size);
|
||||||
|
stream->data_sect.buf += inst->size;
|
||||||
|
stream->whole_target.addslen += inst->size;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (inst->addr < stream->dec_cpylen)
|
||||||
|
{
|
||||||
|
winst->mode = SRCORTGT (stream->dec_win_ind);
|
||||||
|
winst->addr = stream->dec_cpyoff + inst->addr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
winst->addr = (stream->dec_winstart +
|
||||||
|
inst->addr -
|
||||||
|
stream->dec_cpylen);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xd3_whole_append_window (xd3_stream *stream)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
xd3_wininfo *wininfo;
|
||||||
|
|
||||||
|
if ((ret = xd3_whole_alloc_wininfo (stream, &wininfo))) { return ret; }
|
||||||
|
|
||||||
|
wininfo->length = stream->dec_tgtlen;
|
||||||
|
wininfo->offset = stream->dec_winstart;
|
||||||
|
wininfo->adler32 = stream->dec_adler32;
|
||||||
|
|
||||||
|
while (stream->inst_sect.buf < stream->inst_sect.buf_max)
|
||||||
|
{
|
||||||
|
if ((ret = xd3_decode_instruction (stream)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((stream->dec_current1.type != XD3_NOOP) &&
|
||||||
|
(ret = xd3_whole_append_inst (stream,
|
||||||
|
& stream->dec_current1)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((stream->dec_current2.type != XD3_NOOP) &&
|
||||||
|
(ret = xd3_whole_append_inst (stream,
|
||||||
|
& stream->dec_current2)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* xd3_merge_input_output applies *source to *stream, returns the
|
||||||
|
* result in stream. */
|
||||||
|
static int xd3_merge_input_output (xd3_stream *stream,
|
||||||
|
xd3_whole_state *source)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
xd3_stream tmp_stream;
|
||||||
|
memset (& tmp_stream, 0, sizeof (tmp_stream));
|
||||||
|
if ((ret = xd3_config_stream (& tmp_stream, NULL)) ||
|
||||||
|
(ret = xd3_whole_state_init (& tmp_stream)) ||
|
||||||
|
(ret = xd3_merge_inputs (& tmp_stream,
|
||||||
|
source,
|
||||||
|
& stream->whole_target)))
|
||||||
|
{
|
||||||
|
XPR(NT XD3_LIB_ERRMSG (&tmp_stream, ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the output is in tmp_stream.whole_state, swap into input */
|
||||||
|
xd3_swap_whole_state (& stream->whole_target,
|
||||||
|
& tmp_stream.whole_target);
|
||||||
|
/* total allocation counts are preserved */
|
||||||
|
xd3_free_stream (& tmp_stream);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_merge_run (xd3_stream *stream,
|
||||||
|
xd3_whole_state *target,
|
||||||
|
xd3_winst *iinst)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
xd3_winst *oinst;
|
||||||
|
|
||||||
|
if ((ret = xd3_whole_alloc_winst (stream, &oinst)) ||
|
||||||
|
(ret = xd3_whole_alloc_adds (stream, 1)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
oinst->type = iinst->type;
|
||||||
|
oinst->mode = iinst->mode;
|
||||||
|
oinst->size = iinst->size;
|
||||||
|
oinst->addr = stream->whole_target.addslen;
|
||||||
|
|
||||||
|
XD3_ASSERT (stream->whole_target.length == iinst->position);
|
||||||
|
oinst->position = stream->whole_target.length;
|
||||||
|
stream->whole_target.length += iinst->size;
|
||||||
|
|
||||||
|
stream->whole_target.adds[stream->whole_target.addslen++] =
|
||||||
|
target->adds[iinst->addr];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_merge_add (xd3_stream *stream,
|
||||||
|
xd3_whole_state *target,
|
||||||
|
xd3_winst *iinst)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
xd3_winst *oinst;
|
||||||
|
|
||||||
|
if ((ret = xd3_whole_alloc_winst (stream, &oinst)) ||
|
||||||
|
(ret = xd3_whole_alloc_adds (stream, iinst->size)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
oinst->type = iinst->type;
|
||||||
|
oinst->mode = iinst->mode;
|
||||||
|
oinst->size = iinst->size;
|
||||||
|
oinst->addr = stream->whole_target.addslen;
|
||||||
|
|
||||||
|
XD3_ASSERT (stream->whole_target.length == iinst->position);
|
||||||
|
oinst->position = stream->whole_target.length;
|
||||||
|
stream->whole_target.length += iinst->size;
|
||||||
|
|
||||||
|
memcpy(stream->whole_target.adds + stream->whole_target.addslen,
|
||||||
|
target->adds + iinst->addr,
|
||||||
|
iinst->size);
|
||||||
|
|
||||||
|
stream->whole_target.addslen += iinst->size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_merge_target_copy (xd3_stream *stream,
|
||||||
|
xd3_winst *iinst)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
xd3_winst *oinst;
|
||||||
|
|
||||||
|
if ((ret = xd3_whole_alloc_winst (stream, &oinst)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
XD3_ASSERT (stream->whole_target.length == iinst->position);
|
||||||
|
|
||||||
|
memcpy (oinst, iinst, sizeof (*oinst));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_merge_find_position (xd3_stream *stream,
|
||||||
|
xd3_whole_state *source,
|
||||||
|
xoff_t address,
|
||||||
|
usize_t *inst_num)
|
||||||
|
{
|
||||||
|
usize_t low;
|
||||||
|
usize_t high;
|
||||||
|
|
||||||
|
if (address >= source->length)
|
||||||
|
{
|
||||||
|
stream->msg = "Invalid copy offset in merge";
|
||||||
|
return XD3_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
low = 0;
|
||||||
|
high = source->instlen;
|
||||||
|
|
||||||
|
while (low != high)
|
||||||
|
{
|
||||||
|
xoff_t mid_lpos;
|
||||||
|
xoff_t mid_hpos;
|
||||||
|
usize_t mid = low + (high - low) / 2;
|
||||||
|
mid_lpos = source->inst[mid].position;
|
||||||
|
|
||||||
|
if (address < mid_lpos)
|
||||||
|
{
|
||||||
|
high = mid;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
mid_hpos = mid_lpos + source->inst[mid].size;
|
||||||
|
|
||||||
|
if (address >= mid_hpos)
|
||||||
|
{
|
||||||
|
low = mid + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
*inst_num = mid;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->msg = "Internal error in merge";
|
||||||
|
return XD3_INTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_merge_source_copy (xd3_stream *stream,
|
||||||
|
xd3_whole_state *source,
|
||||||
|
const xd3_winst *iinst_orig)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
xd3_winst iinst;
|
||||||
|
usize_t sinst_num;
|
||||||
|
|
||||||
|
memcpy (& iinst, iinst_orig, sizeof (iinst));
|
||||||
|
|
||||||
|
XD3_ASSERT (iinst.mode == VCD_SOURCE);
|
||||||
|
|
||||||
|
if ((ret = xd3_merge_find_position (stream, source,
|
||||||
|
iinst.addr, &sinst_num)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (iinst.size > 0)
|
||||||
|
{
|
||||||
|
xd3_winst *sinst;
|
||||||
|
xd3_winst *minst;
|
||||||
|
usize_t sinst_offset;
|
||||||
|
usize_t sinst_left;
|
||||||
|
usize_t this_take;
|
||||||
|
|
||||||
|
XD3_ASSERT (sinst_num < source->instlen);
|
||||||
|
|
||||||
|
sinst = &source->inst[sinst_num];
|
||||||
|
|
||||||
|
XD3_ASSERT (iinst.addr >= sinst->position);
|
||||||
|
|
||||||
|
sinst_offset = (usize_t)(iinst.addr - sinst->position);
|
||||||
|
|
||||||
|
XD3_ASSERT (sinst->size > sinst_offset);
|
||||||
|
|
||||||
|
sinst_left = sinst->size - sinst_offset;
|
||||||
|
this_take = xd3_min (iinst.size, sinst_left);
|
||||||
|
|
||||||
|
XD3_ASSERT (this_take > 0);
|
||||||
|
|
||||||
|
if ((ret = xd3_whole_alloc_winst (stream, &minst)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
minst->size = this_take;
|
||||||
|
minst->type = sinst->type;
|
||||||
|
minst->position = iinst.position;
|
||||||
|
minst->mode = 0;
|
||||||
|
|
||||||
|
switch (sinst->type)
|
||||||
|
{
|
||||||
|
case XD3_RUN:
|
||||||
|
if ((ret = xd3_whole_alloc_adds (stream, 1)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
minst->addr = stream->whole_target.addslen;
|
||||||
|
stream->whole_target.adds[stream->whole_target.addslen++] =
|
||||||
|
source->adds[sinst->addr];
|
||||||
|
break;
|
||||||
|
case XD3_ADD:
|
||||||
|
if ((ret = xd3_whole_alloc_adds (stream, this_take)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
minst->addr = stream->whole_target.addslen;
|
||||||
|
memcpy(stream->whole_target.adds + stream->whole_target.addslen,
|
||||||
|
source->adds + sinst->addr + sinst_offset,
|
||||||
|
this_take);
|
||||||
|
stream->whole_target.addslen += this_take;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (sinst->mode != 0)
|
||||||
|
{
|
||||||
|
minst->mode = sinst->mode;
|
||||||
|
minst->addr = sinst->addr + sinst_offset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Note: A better implementation will construct the
|
||||||
|
// mapping of output ranges, starting from the input
|
||||||
|
// range, applying deltas in forward order, using an
|
||||||
|
// interval tree. This code uses recursion to construct
|
||||||
|
// each copied range, recursively (using binary search
|
||||||
|
// in xd3_merge_find_position).
|
||||||
|
//
|
||||||
|
// TODO: This code can cause stack overflow. Fix as
|
||||||
|
// described above.
|
||||||
|
xd3_winst tinst;
|
||||||
|
tinst.type = XD3_CPY;
|
||||||
|
tinst.mode = iinst.mode;
|
||||||
|
tinst.addr = sinst->addr + sinst_offset;
|
||||||
|
tinst.size = this_take;
|
||||||
|
tinst.position = iinst.position;
|
||||||
|
|
||||||
|
// The instruction allocated in this frame will not be used.
|
||||||
|
stream->whole_target.instlen -= 1;
|
||||||
|
|
||||||
|
if ((ret = xd3_merge_source_copy (stream, source, &tinst)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
iinst.position += this_take;
|
||||||
|
iinst.addr += this_take;
|
||||||
|
iinst.size -= this_take;
|
||||||
|
sinst_num += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* xd3_merge_inputs() applies *input to *source, returns its result in
|
||||||
|
* stream. */
|
||||||
|
int xd3_merge_inputs (xd3_stream *stream,
|
||||||
|
xd3_whole_state *source,
|
||||||
|
xd3_whole_state *input)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
usize_t i;
|
||||||
|
size_t input_i;
|
||||||
|
|
||||||
|
for (i = 0; i < input->wininfolen; ++i) {
|
||||||
|
xd3_wininfo *copyinfo;
|
||||||
|
|
||||||
|
if ((ret = xd3_whole_alloc_wininfo (stream, ©info))) { return ret; }
|
||||||
|
|
||||||
|
*copyinfo = input->wininfo[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* iterate over each instruction. */
|
||||||
|
for (input_i = 0; ret == 0 && input_i < input->instlen; ++input_i)
|
||||||
|
{
|
||||||
|
xd3_winst *iinst = &input->inst[input_i];
|
||||||
|
|
||||||
|
switch (iinst->type)
|
||||||
|
{
|
||||||
|
case XD3_RUN:
|
||||||
|
ret = xd3_merge_run (stream, input, iinst);
|
||||||
|
break;
|
||||||
|
case XD3_ADD:
|
||||||
|
ret = xd3_merge_add (stream, input, iinst);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (iinst->mode == 0)
|
||||||
|
{
|
||||||
|
ret = xd3_merge_target_copy (stream, iinst);
|
||||||
|
}
|
||||||
|
else if (iinst->mode == VCD_TARGET)
|
||||||
|
{
|
||||||
|
ret = XD3_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = xd3_merge_source_copy (stream, source, iinst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The whole_target.length is not updated in the xd3_merge*copy
|
||||||
|
* routine because of recursion in xd3_merge_source_copy. */
|
||||||
|
stream->whole_target.length += iinst->size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
321
lib/xdelta3/xdelta3-second.h
Normal file
321
lib/xdelta3/xdelta3-second.h
Normal file
|
@ -0,0 +1,321 @@
|
||||||
|
/* xdelta3 - delta compression tools and library
|
||||||
|
Copyright 2016 Joshua MacDonald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#ifndef _XDELTA3_SECOND_H_
|
||||||
|
#define _XDELTA3_SECOND_H_
|
||||||
|
|
||||||
|
static inline void xd3_bit_state_encode_init (bit_state *bits)
|
||||||
|
{
|
||||||
|
bits->cur_byte = 0;
|
||||||
|
bits->cur_mask = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int xd3_decode_bits (xd3_stream *stream,
|
||||||
|
bit_state *bits,
|
||||||
|
const uint8_t **input,
|
||||||
|
const uint8_t *input_max,
|
||||||
|
usize_t nbits,
|
||||||
|
usize_t *valuep)
|
||||||
|
{
|
||||||
|
usize_t value = 0;
|
||||||
|
usize_t vmask = 1 << nbits;
|
||||||
|
|
||||||
|
if (bits->cur_mask == 0x100) { goto next_byte; }
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
vmask >>= 1;
|
||||||
|
|
||||||
|
if (bits->cur_byte & bits->cur_mask)
|
||||||
|
{
|
||||||
|
value |= vmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
bits->cur_mask <<= 1;
|
||||||
|
|
||||||
|
if (vmask == 1) { goto done; }
|
||||||
|
}
|
||||||
|
while (bits->cur_mask != 0x100);
|
||||||
|
|
||||||
|
next_byte:
|
||||||
|
|
||||||
|
if (*input == input_max)
|
||||||
|
{
|
||||||
|
stream->msg = "secondary decoder end of input";
|
||||||
|
return XD3_INTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bits->cur_byte = *(*input)++;
|
||||||
|
bits->cur_mask = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
IF_DEBUG2 (DP(RINT "(d) %"W"u ", value));
|
||||||
|
|
||||||
|
(*valuep) = value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if REGRESSION_TEST
|
||||||
|
/* There may be extra bits at the end of secondary decompression, this macro
|
||||||
|
* checks for non-zero bits. This is overly strict, but helps pass the
|
||||||
|
* single-bit-error regression test. */
|
||||||
|
static int
|
||||||
|
xd3_test_clean_bits (xd3_stream *stream, bit_state *bits)
|
||||||
|
{
|
||||||
|
for (; bits->cur_mask != 0x100; bits->cur_mask <<= 1)
|
||||||
|
{
|
||||||
|
if (bits->cur_byte & bits->cur_mask)
|
||||||
|
{
|
||||||
|
stream->msg = "secondary decoder garbage";
|
||||||
|
return XD3_INTERNAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_get_secondary (xd3_stream *stream, xd3_sec_stream **sec_streamp,
|
||||||
|
int is_encode)
|
||||||
|
{
|
||||||
|
if (*sec_streamp == NULL)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((*sec_streamp = stream->sec_type->alloc (stream)) == NULL)
|
||||||
|
{
|
||||||
|
stream->msg = "error initializing secondary stream";
|
||||||
|
return XD3_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = stream->sec_type->init (stream, *sec_streamp, is_encode)) != 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_decode_secondary (xd3_stream *stream,
|
||||||
|
xd3_desect *sect,
|
||||||
|
xd3_sec_stream **sec_streamp)
|
||||||
|
{
|
||||||
|
usize_t dec_size;
|
||||||
|
uint8_t *out_used;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((ret = xd3_get_secondary (stream, sec_streamp, 0)) != 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode the size, allocate the buffer. */
|
||||||
|
if ((ret = xd3_read_size (stream, & sect->buf,
|
||||||
|
sect->buf_max, & dec_size)) ||
|
||||||
|
(ret = xd3_decode_allocate (stream, dec_size,
|
||||||
|
& sect->copied2, & sect->alloc2)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dec_size == 0)
|
||||||
|
{
|
||||||
|
stream->msg = "secondary decoder invalid output size";
|
||||||
|
return XD3_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_used = sect->copied2;
|
||||||
|
|
||||||
|
if ((ret = stream->sec_type->decode (stream, *sec_streamp,
|
||||||
|
& sect->buf, sect->buf_max,
|
||||||
|
& out_used, out_used + dec_size)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sect->buf != sect->buf_max)
|
||||||
|
{
|
||||||
|
stream->msg = "secondary decoder finished with unused input";
|
||||||
|
return XD3_INTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_used != sect->copied2 + dec_size)
|
||||||
|
{
|
||||||
|
stream->msg = "secondary decoder short output";
|
||||||
|
return XD3_INTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sect->buf = sect->copied2;
|
||||||
|
sect->buf_max = sect->copied2 + dec_size;
|
||||||
|
sect->size = dec_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if XD3_ENCODER
|
||||||
|
static inline int xd3_encode_bit (xd3_stream *stream,
|
||||||
|
xd3_output **output,
|
||||||
|
bit_state *bits,
|
||||||
|
usize_t bit)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (bit)
|
||||||
|
{
|
||||||
|
bits->cur_byte |= bits->cur_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OPT: Might help to buffer more than 8 bits at once. */
|
||||||
|
if (bits->cur_mask == 0x80)
|
||||||
|
{
|
||||||
|
if ((ret = xd3_emit_byte (stream, output, bits->cur_byte)) != 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bits->cur_mask = 1;
|
||||||
|
bits->cur_byte = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bits->cur_mask <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int xd3_flush_bits (xd3_stream *stream,
|
||||||
|
xd3_output **output,
|
||||||
|
bit_state *bits)
|
||||||
|
{
|
||||||
|
return (bits->cur_mask == 1) ? 0 :
|
||||||
|
xd3_emit_byte (stream, output, bits->cur_byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int xd3_encode_bits (xd3_stream *stream,
|
||||||
|
xd3_output **output,
|
||||||
|
bit_state *bits,
|
||||||
|
usize_t nbits,
|
||||||
|
usize_t value)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
usize_t mask = 1 << nbits;
|
||||||
|
|
||||||
|
XD3_ASSERT (nbits > 0);
|
||||||
|
XD3_ASSERT (nbits < sizeof (usize_t) * 8);
|
||||||
|
XD3_ASSERT (value < mask);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
mask >>= 1;
|
||||||
|
|
||||||
|
if ((ret = xd3_encode_bit (stream, output, bits, value & mask)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (mask != 1);
|
||||||
|
|
||||||
|
IF_DEBUG2 (DP(RINT "(e) %"W"u ", value));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xd3_encode_secondary (xd3_stream *stream,
|
||||||
|
xd3_output **head,
|
||||||
|
xd3_output **tail,
|
||||||
|
xd3_sec_stream **sec_streamp,
|
||||||
|
xd3_sec_cfg *cfg,
|
||||||
|
int *did_it)
|
||||||
|
{
|
||||||
|
xd3_output *tmp_head;
|
||||||
|
xd3_output *tmp_tail;
|
||||||
|
|
||||||
|
usize_t comp_size;
|
||||||
|
usize_t orig_size;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
orig_size = xd3_sizeof_output (*head);
|
||||||
|
|
||||||
|
if (orig_size < SECONDARY_MIN_INPUT) { return 0; }
|
||||||
|
|
||||||
|
if ((ret = xd3_get_secondary (stream, sec_streamp, 1)) != 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_head = xd3_alloc_output (stream, NULL);
|
||||||
|
|
||||||
|
/* Encode the size, encode the data. Encoding the size makes it
|
||||||
|
* simpler, but is a little gross. Should not need the entire
|
||||||
|
* section in contiguous memory, but it is much easier this way. */
|
||||||
|
if ((ret = xd3_emit_size (stream, & tmp_head, orig_size)) ||
|
||||||
|
(ret = stream->sec_type->encode (stream, *sec_streamp, *head,
|
||||||
|
tmp_head, cfg)))
|
||||||
|
{
|
||||||
|
goto getout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the secondary compressor determines it's no good, it returns
|
||||||
|
* XD3_NOSECOND. */
|
||||||
|
|
||||||
|
/* Setup tmp_tail, comp_size */
|
||||||
|
tmp_tail = tmp_head;
|
||||||
|
comp_size = tmp_head->next;
|
||||||
|
|
||||||
|
while (tmp_tail->next_page != NULL)
|
||||||
|
{
|
||||||
|
tmp_tail = tmp_tail->next_page;
|
||||||
|
comp_size += tmp_tail->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
XD3_ASSERT (comp_size == xd3_sizeof_output (tmp_head));
|
||||||
|
XD3_ASSERT (tmp_tail != NULL);
|
||||||
|
|
||||||
|
if (comp_size < (orig_size - SECONDARY_MIN_SAVINGS) || cfg->inefficient)
|
||||||
|
{
|
||||||
|
if (comp_size < orig_size)
|
||||||
|
{
|
||||||
|
IF_DEBUG1(DP(RINT "[encode_secondary] saved %"W"u bytes: %"W"u -> %"W"u (%0.2f%%)\n",
|
||||||
|
orig_size - comp_size, orig_size, comp_size,
|
||||||
|
100.0 * (double) comp_size / (double) orig_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
xd3_free_output (stream, *head);
|
||||||
|
|
||||||
|
*head = tmp_head;
|
||||||
|
*tail = tmp_tail;
|
||||||
|
*did_it = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
getout:
|
||||||
|
if (ret == XD3_NOSECOND) { ret = 0; }
|
||||||
|
xd3_free_output (stream, tmp_head);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* XD3_ENCODER */
|
||||||
|
#endif /* _XDELTA3_SECOND_H_ */
|
3022
lib/xdelta3/xdelta3-test.h
Normal file
3022
lib/xdelta3/xdelta3-test.h
Normal file
File diff suppressed because it is too large
Load diff
153
lib/xdelta3/xdelta3.1
Normal file
153
lib/xdelta3/xdelta3.1
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
.TH XDELTA3 "1" "August 2009" "Xdelta3"
|
||||||
|
.SH NAME
|
||||||
|
xdelta3 \- VCDIFF (RFC 3284) binary diff tool
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B xdelta3
|
||||||
|
.RI [ command ]
|
||||||
|
.RI [ options ]
|
||||||
|
.RI [ input
|
||||||
|
.RI [ output ]]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B xdelta3
|
||||||
|
is a binary diff tool that uses the VCDIFF (RFC 3284) format and compression.
|
||||||
|
.SH COMMANDS
|
||||||
|
.TP
|
||||||
|
.BI config
|
||||||
|
prints xdelta3 configuration
|
||||||
|
.TP
|
||||||
|
.BI decode
|
||||||
|
decompress the input, also set by -d
|
||||||
|
.TP
|
||||||
|
.BI encode
|
||||||
|
compress the input, also set by -e (default)
|
||||||
|
.TP
|
||||||
|
.BI test
|
||||||
|
run the builtin tests
|
||||||
|
.TP
|
||||||
|
.BI printdelta
|
||||||
|
print information about the entire delta
|
||||||
|
.TP
|
||||||
|
.BI printhdr
|
||||||
|
print information about the first window
|
||||||
|
.TP
|
||||||
|
.BI printhdrs
|
||||||
|
print information about all windows
|
||||||
|
.TP
|
||||||
|
.BI recode
|
||||||
|
encode with new application/secondary settings
|
||||||
|
|
||||||
|
.SH OPTIONS
|
||||||
|
standard options:
|
||||||
|
.TP
|
||||||
|
.BI "\-0 .. \-9"
|
||||||
|
compression level
|
||||||
|
.TP
|
||||||
|
.BI "\-c"
|
||||||
|
use stdout
|
||||||
|
.TP
|
||||||
|
.BI "\-d"
|
||||||
|
decompress
|
||||||
|
.TP
|
||||||
|
.BI \-e
|
||||||
|
compress
|
||||||
|
.TP
|
||||||
|
.BI \-f
|
||||||
|
force overwrite
|
||||||
|
.TP
|
||||||
|
.BI \-h
|
||||||
|
show help
|
||||||
|
.TP
|
||||||
|
.BI \-q
|
||||||
|
be quiet
|
||||||
|
.TP
|
||||||
|
.BI \-v
|
||||||
|
be verbose (max 2)
|
||||||
|
.TP
|
||||||
|
.BI \-V
|
||||||
|
show version
|
||||||
|
|
||||||
|
.TP
|
||||||
|
memory options:
|
||||||
|
.TP
|
||||||
|
.BI \-B
|
||||||
|
.RI bytes
|
||||||
|
source window size
|
||||||
|
.TP
|
||||||
|
.BI \-W
|
||||||
|
.RI bytes
|
||||||
|
input window size
|
||||||
|
.TP
|
||||||
|
.BI \-P
|
||||||
|
.RI size
|
||||||
|
compression duplicates window
|
||||||
|
.TP
|
||||||
|
.BI \-I
|
||||||
|
.RI size
|
||||||
|
instruction buffer size (0 = unlimited)
|
||||||
|
|
||||||
|
.TP
|
||||||
|
compression options:
|
||||||
|
.TP
|
||||||
|
.BI \-s
|
||||||
|
.RI source
|
||||||
|
source file to copy from (if any)
|
||||||
|
.TP
|
||||||
|
.BI "\-S " [djw|fgk]
|
||||||
|
enable/disable secondary compression
|
||||||
|
.TP
|
||||||
|
.BI \-N
|
||||||
|
disable small string-matching compression
|
||||||
|
.TP
|
||||||
|
.BI \-D
|
||||||
|
disable external decompression (encode/decode)
|
||||||
|
.TP
|
||||||
|
.BI \-R
|
||||||
|
disable external recompression (decode)
|
||||||
|
.TP
|
||||||
|
.BI \-n
|
||||||
|
disable checksum (encode/decode)
|
||||||
|
.TP
|
||||||
|
.BI \-C
|
||||||
|
soft config (encode, undocumented)
|
||||||
|
.TP
|
||||||
|
.BI "\-A " [apphead]
|
||||||
|
disable/provide application header (encode)
|
||||||
|
.TP
|
||||||
|
.BI \-J
|
||||||
|
disable output (check/compute only)
|
||||||
|
.TP
|
||||||
|
.BI \-T
|
||||||
|
use alternate code table (test)
|
||||||
|
|
||||||
|
.SH NOTES
|
||||||
|
The
|
||||||
|
.B XDELTA
|
||||||
|
environment variable may contain extra args:
|
||||||
|
|
||||||
|
.RS
|
||||||
|
XDELTA="-s source-x.y.tar.gz" \\
|
||||||
|
.br
|
||||||
|
tar --use-compress-program=xdelta3 -cf \\
|
||||||
|
.br
|
||||||
|
target-x.z.tar.gz.vcdiff target-x.y/
|
||||||
|
|
||||||
|
.SH EXAMPLES
|
||||||
|
|
||||||
|
Compress the differences between SOURCE and TARGET, yielding OUT,
|
||||||
|
using "djw" secondary compression:
|
||||||
|
|
||||||
|
xdelta3 -S djw -s SOURCE TARGET OUT
|
||||||
|
|
||||||
|
Do the same, using standard input and output:
|
||||||
|
|
||||||
|
xdelta3 -S djw -s SOURCE < TARGET > OUT
|
||||||
|
|
||||||
|
To decompress OUT, using SOURCE, yielding TARGET:
|
||||||
|
|
||||||
|
xdelta3 -d -s SOURCE OUT TARGET
|
||||||
|
|
||||||
|
.SH AUTHOR
|
||||||
|
xdelta3 was written by Josh MacDonald <josh.macdonald@gmail.com>.
|
||||||
|
.PP
|
||||||
|
This manual page was written by Leo 'costela' Antunes <costela@debian.org>
|
||||||
|
for the Debian project (but may be used by others).
|
4819
lib/xdelta3/xdelta3.c
Normal file
4819
lib/xdelta3/xdelta3.c
Normal file
File diff suppressed because it is too large
Load diff
1476
lib/xdelta3/xdelta3.h
Normal file
1476
lib/xdelta3/xdelta3.h
Normal file
File diff suppressed because it is too large
Load diff
85
lib/xdelta3/xdelta3.i
Normal file
85
lib/xdelta3/xdelta3.i
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
%module xdelta3
|
||||||
|
%import cstring.i
|
||||||
|
%import argcargv.i
|
||||||
|
%{
|
||||||
|
#include "xdelta3.h"
|
||||||
|
|
||||||
|
int xd3_main_cmdline (int ARGC, char **ARGV);
|
||||||
|
%}
|
||||||
|
|
||||||
|
%cstring_input_binary(const char *input, unsigned int input_size);
|
||||||
|
%cstring_input_binary(const char *source, unsigned int source_size);
|
||||||
|
|
||||||
|
%define %max_output_withsize(TYPEMAP, SIZE, MAXSIZE)
|
||||||
|
%typemap(in) MAXSIZE (unsigned int alloc_size) {
|
||||||
|
$1 = alloc_size = PyInt_AsLong(obj2);
|
||||||
|
}
|
||||||
|
%typemap(in,numinputs=0) (TYPEMAP, SIZE) {
|
||||||
|
}
|
||||||
|
%typemap(check) (TYPEMAP, SIZE) {
|
||||||
|
// alloc_size input is #7th position in xd3_xxcode_memory()
|
||||||
|
$1 = malloc(alloc_size7);
|
||||||
|
$2 = &alloc_size7;
|
||||||
|
}
|
||||||
|
%typemap(argout,fragment="t_output_helper") (TYPEMAP, SIZE) {
|
||||||
|
if (result == 0) {
|
||||||
|
PyObject *o;
|
||||||
|
// alloc_size7 now carries actual size
|
||||||
|
o = PyString_FromStringAndSize($1,alloc_size7);
|
||||||
|
$result = t_output_helper($result,o);
|
||||||
|
} else {
|
||||||
|
$result = t_output_helper($result,Py_None);
|
||||||
|
}
|
||||||
|
free($1);
|
||||||
|
}
|
||||||
|
%typemap(default) int flags {
|
||||||
|
$1 = 0;
|
||||||
|
}
|
||||||
|
%enddef
|
||||||
|
|
||||||
|
%max_output_withsize(char *output_buf, unsigned int *output_size, unsigned int max_output);
|
||||||
|
|
||||||
|
int xd3_encode_memory (const uint8_t *input,
|
||||||
|
usize_t input_size,
|
||||||
|
const uint8_t *source,
|
||||||
|
usize_t source_size,
|
||||||
|
uint8_t *output_buffer,
|
||||||
|
usize_t *output_size,
|
||||||
|
usize_t avail_output,
|
||||||
|
int flags);
|
||||||
|
|
||||||
|
int xd3_decode_memory (const uint8_t *input,
|
||||||
|
usize_t input_size,
|
||||||
|
const uint8_t *source,
|
||||||
|
usize_t source_size,
|
||||||
|
uint8_t *output_buf,
|
||||||
|
usize_t *output_size,
|
||||||
|
usize_t avail_output,
|
||||||
|
int flags);
|
||||||
|
|
||||||
|
int xd3_main_cmdline (int ARGC, char **ARGV);
|
||||||
|
|
||||||
|
/* Is this the right way? */
|
||||||
|
enum {
|
||||||
|
/*XD3_JUST_HDR,*/
|
||||||
|
/*XD3_SKIP_WINDOW,*/
|
||||||
|
/*XD3_SKIP_EMIT,*/
|
||||||
|
/*XD3_FLUSH,*/
|
||||||
|
XD3_SEC_DJW,
|
||||||
|
XD3_SEC_FGK,
|
||||||
|
/*XD3_SEC_TYPE,*/
|
||||||
|
XD3_SEC_NODATA,
|
||||||
|
XD3_SEC_NOINST,
|
||||||
|
XD3_SEC_NOADDR,
|
||||||
|
/*XD3_SEC_OTHER,*/
|
||||||
|
XD3_ADLER32,
|
||||||
|
XD3_ADLER32_NOVER,
|
||||||
|
XD3_NOCOMPRESS,
|
||||||
|
XD3_BEGREEDY,
|
||||||
|
XD3_COMPLEVEL_SHIFT,
|
||||||
|
XD3_COMPLEVEL_MASK,
|
||||||
|
XD3_COMPLEVEL_1,
|
||||||
|
XD3_COMPLEVEL_3,
|
||||||
|
XD3_COMPLEVEL_6,
|
||||||
|
XD3_COMPLEVEL_9,
|
||||||
|
};
|
344
lib/xdelta3/xdelta3.vcxproj
Normal file
344
lib/xdelta3/xdelta3.vcxproj
Normal file
|
@ -0,0 +1,344 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Itanium">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Itanium</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Itanium">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Itanium</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="xdelta3-64|Itanium">
|
||||||
|
<Configuration>xdelta3-64</Configuration>
|
||||||
|
<Platform>Itanium</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="xdelta3-64|Win32">
|
||||||
|
<Configuration>xdelta3-64</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="xdelta3-64|x64">
|
||||||
|
<Configuration>xdelta3-64</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="xdelta3.c">
|
||||||
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">/DXD3_DEBUG=0 /DXD3_USE_LARGEFILE64=1 /DREGRESSION_TEST=1 /DSECONDARY_DJW=1 /DSECONDARY_FGK=1 /DXD3_MAIN=1 /DXD3_WIN32=1 /DEXTERNAL_COMPRESSION=0 /DXD3_STDIO=0 /DXD3_POSIX=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">/DXD3_DEBUG=0 /DXD3_USE_LARGEFILE64=1 /DREGRESSION_TEST=1 /DSECONDARY_DJW=1 /DSECONDARY_FGK=1 /DXD3_MAIN=1 /DXD3_WIN32=1 /DEXTERNAL_COMPRESSION=0 /DXD3_STDIO=0 /DXD3_POSIX=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">/DXD3_DEBUG=0 /DXD3_USE_LARGEFILE64=1 /DREGRESSION_TEST=1 /DSECONDARY_DJW=1 /DSECONDARY_FGK=1 /DXD3_MAIN=1 /DXD3_WIN32=1 /DEXTERNAL_COMPRESSION=0 /DXD3_STDIO=0 /DXD3_POSIX=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|Win32'">/DXD3_DEBUG=0 /DXD3_USE_LARGEFILE64=1 /DREGRESSION_TEST=1 /DSECONDARY_DJW=1 /DSECONDARY_FGK=1 /DXD3_MAIN=1 /DXD3_WIN32=1 /DEXTERNAL_COMPRESSION=0 /DXD3_STDIO=0 /DXD3_POSIX=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|Itanium'">/DXD3_DEBUG=0 /DXD3_USE_LARGEFILE64=1 /DREGRESSION_TEST=1 /DSECONDARY_DJW=1 /DSECONDARY_FGK=1 /DXD3_MAIN=1 /DXD3_WIN32=1 /DEXTERNAL_COMPRESSION=0 /DXD3_STDIO=0 /DXD3_POSIX=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|x64'">/DXD3_DEBUG=0 /DXD3_USE_LARGEFILE64=1 /DREGRESSION_TEST=1 /DSECONDARY_DJW=1 /DSECONDARY_FGK=1 /DXD3_MAIN=1 /DXD3_WIN32=1 /DEXTERNAL_COMPRESSION=0 /DXD3_STDIO=0 /DXD3_POSIX=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="xdelta3-blkcache.h" />
|
||||||
|
<ClInclude Include="xdelta3-cfgs.h" />
|
||||||
|
<ClInclude Include="xdelta3-decode.h" />
|
||||||
|
<ClInclude Include="xdelta3-djw.h" />
|
||||||
|
<ClInclude Include="xdelta3-fgk.h" />
|
||||||
|
<ClInclude Include="xdelta3-hash.h" />
|
||||||
|
<ClInclude Include="xdelta3-internal.h" />
|
||||||
|
<ClInclude Include="xdelta3-list.h" />
|
||||||
|
<ClInclude Include="xdelta3-lzma.h" />
|
||||||
|
<ClInclude Include="xdelta3-main.h" />
|
||||||
|
<ClInclude Include="xdelta3-merge.h" />
|
||||||
|
<ClInclude Include="xdelta3-second.h" />
|
||||||
|
<ClInclude Include="xdelta3-test.h" />
|
||||||
|
<ClInclude Include="xdelta3.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{8F9D37B5-B78E-4816-BE61-AEF679DBF3BC}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>xdelta3</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v120</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v120</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v120</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v120</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v120</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|Itanium'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v120</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|Itanium'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<IncludePath>$(WindowsSdkDir)\include;$(VCInstallDir)include;..\xz\include</IncludePath>
|
||||||
|
<LibraryPath>$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64;..\xz\bin_x86-64</LibraryPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|Itanium'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;SECONDARY_LZMA=0;LZMA_API_STATIC;SIZEOF_SIZE_T=4;SIZEOF_UNSIGNED_LONG_LONG=8;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalIncludeDirectories>../xz/include</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;..\..\..\..\src\xz\bin_x86-64\liblzma_static.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;SECONDARY_LZMA=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;LZMA_API_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\..\src\xz\include</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;..\..\..\..\src\xz\bin_i486\liblzma_static.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;SECONDARY_LZMA=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;LZMA_API_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\..\src\xz\include</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);..\..\..\..\src\xz\bin_x86-64\liblzma_static.lib</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|Itanium'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='xdelta3-64|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
7
lib/xdelta3/xdelta3.wxi
Normal file
7
lib/xdelta3/xdelta3.wxi
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<Include>
|
||||||
|
<?define PRODUCT_ID=60131be5-be4d-4975-9108-dd0be735890d ?>
|
||||||
|
<?define PACKAGE_ID=82bf21ca-ee08-4701-ab78-37210dac82ce ?>
|
||||||
|
<?define COMPONENT_ID=85bc3206-05f8-41f8-b500-6ea32e5d6a8f ?>
|
||||||
|
<?define MANUAL_ID=07f387bc-a0c5-4af9-88db-1a84443f1fc5 ?>
|
||||||
|
<?define SOURCE_ID=4e1503a9-3ed1-4e06-b0c0-890462b1a4fd ?>
|
||||||
|
</Include>
|
131
lib/xdelta3/xdelta3.wxs
Normal file
131
lib/xdelta3/xdelta3.wxs
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
<?xml version='1.0'?>
|
||||||
|
<?include $(sys.SOURCEFILEDIR)\xdelta3.wxi ?>
|
||||||
|
|
||||||
|
<Wix xmlns='http://schemas.microsoft.com/wix/2003/01/wi'>
|
||||||
|
<Product Id='$(var.PRODUCT_ID)'
|
||||||
|
Name='Xdelta 3.0u'
|
||||||
|
Language='1033'
|
||||||
|
Codepage='1252'
|
||||||
|
Version='3.0.1.1'
|
||||||
|
Manufacturer='Josh.MacDonald@Gmail.Com'>
|
||||||
|
|
||||||
|
<Package Id='$(var.PACKAGE_ID)'
|
||||||
|
Keywords='Installer'
|
||||||
|
Description='Xdelta 3.0u'
|
||||||
|
Comments='http://xdelta.org'
|
||||||
|
Manufacturer='Josh.MacDonald@Gmail.Com'
|
||||||
|
InstallerVersion='300'
|
||||||
|
Languages='1033'
|
||||||
|
Compressed='yes' />
|
||||||
|
|
||||||
|
<Media Id='1'
|
||||||
|
Cabinet='xdelta30t.cab'
|
||||||
|
EmbedCab='yes' />
|
||||||
|
|
||||||
|
<Directory Id='TARGETDIR' Name='SourceDir'>
|
||||||
|
<Directory Id='ProgramFilesFolder' Name='PFiles'>
|
||||||
|
<Directory Id='Xdelta'
|
||||||
|
Name='Xdelta'>
|
||||||
|
|
||||||
|
<Component Id='Main'
|
||||||
|
Guid='$(var.COMPONENT_ID)'>
|
||||||
|
<File Id='XdeltaEXE'
|
||||||
|
Name='xdelt30t'
|
||||||
|
LongName='xdelta30t.exe'
|
||||||
|
DiskId='1'
|
||||||
|
Source='G:\jmacd\svn\xdelta3\Release\xdelta3.exe'
|
||||||
|
Vital='yes'>
|
||||||
|
</File>
|
||||||
|
</Component>
|
||||||
|
|
||||||
|
<Component Id='Readme'
|
||||||
|
Guid='$(var.MANUAL_ID)'>
|
||||||
|
<File Id='Readme'
|
||||||
|
Name='readme.txt'
|
||||||
|
LongName='readme.txt'
|
||||||
|
DiskId='1'
|
||||||
|
Source='G:\jmacd\svn\xdelta3\readme.txt'
|
||||||
|
Vital='yes'>
|
||||||
|
<Shortcut Id="startupmenuReadme"
|
||||||
|
Directory="ProgramMenuDir"
|
||||||
|
Name="readme.txt"
|
||||||
|
LongName="Xdelta3 readme.txt"
|
||||||
|
/>
|
||||||
|
</File>
|
||||||
|
</Component>
|
||||||
|
|
||||||
|
<Component Id='Copyright'
|
||||||
|
Guid='$(var.MANUAL_ID)'>
|
||||||
|
<File Id='Copyright'
|
||||||
|
Name='COPYING'
|
||||||
|
LongName='COPYING'
|
||||||
|
DiskId='1'
|
||||||
|
Source='G:\jmacd\svn\xdelta3\COPYING'
|
||||||
|
Vital='yes'>
|
||||||
|
<Shortcut Id="startupmenuCopyright"
|
||||||
|
Directory="ProgramMenuDir"
|
||||||
|
Name="COPYING"
|
||||||
|
LongName="GNU Public License"
|
||||||
|
/>
|
||||||
|
</File>
|
||||||
|
</Component>
|
||||||
|
|
||||||
|
<Component Id='Source'
|
||||||
|
Guid='$(var.SOURCE_ID)'>
|
||||||
|
<File Id='Source'
|
||||||
|
Name='xdelt30t.zip'
|
||||||
|
LongName='xdelta3.0u.zip'
|
||||||
|
DiskId='1'
|
||||||
|
Source='G:\jmacd\svn\xdelta3\xdelta3.0u.zip'
|
||||||
|
Vital='yes'>
|
||||||
|
<Shortcut Id="startupmenuSource"
|
||||||
|
Directory="ProgramMenuDir"
|
||||||
|
Name="xdelt30t.zip"
|
||||||
|
LongName="xdelta3.0u.zip"
|
||||||
|
/>
|
||||||
|
</File>
|
||||||
|
</Component>
|
||||||
|
|
||||||
|
</Directory>
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<Directory Id="ProgramMenuFolder" Name="PMenu" LongName="Programs">
|
||||||
|
<Directory Id="ProgramMenuDir"
|
||||||
|
Name="xdelt30t"
|
||||||
|
LongName="Xdelta 3.0u">
|
||||||
|
</Directory>
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<!-- <Merge Id='CRT' -->
|
||||||
|
<!-- Language='0' -->
|
||||||
|
<!-- DiskId='1' -->
|
||||||
|
<!-- src='C:\Program Files\Common Files\Merge Modules\microsoft_vc80_crt_x86.msm' -->
|
||||||
|
<!-- /> -->
|
||||||
|
<!-- <Merge Id='CRT Policy' -->
|
||||||
|
<!-- Language='0' -->
|
||||||
|
<!-- DiskId='1' -->
|
||||||
|
<!-- src='C:\Program Files\Common Files\Merge Modules\policy_8_0_Microsoft_VC80_CRT_x86.msm' -->
|
||||||
|
<!-- /> -->
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<Feature Id='Complete'
|
||||||
|
Level='1'>
|
||||||
|
<ComponentRef Id='Main' />
|
||||||
|
<ComponentRef Id='Readme' />
|
||||||
|
<ComponentRef Id='Copyright' />
|
||||||
|
<ComponentRef Id='Source' />
|
||||||
|
</Feature>
|
||||||
|
|
||||||
|
<!-- <Feature Id='CRT_WinSXS' Title='CRT WinSXS' Level='1'> -->
|
||||||
|
<!-- <MergeRef Id='CRT' /> -->
|
||||||
|
<!-- <MergeRef Id='CRT Policy' /> -->
|
||||||
|
<!-- </Feature> -->
|
||||||
|
|
||||||
|
<InstallExecuteSequence>
|
||||||
|
<RemoveRegistryValues/>
|
||||||
|
<RemoveFiles/>
|
||||||
|
<InstallFiles/>
|
||||||
|
<WriteRegistryValues/>
|
||||||
|
</InstallExecuteSequence>
|
||||||
|
</Product>
|
||||||
|
</Wix>
|
|
@ -1 +1,3 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
void errorAndExit();
|
void errorAndExit();
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
struct arguments {
|
struct arguments {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
//minimum of two integers
|
//minimum of two integers
|
||||||
#define min(a,b) \
|
#define min(a,b) \
|
||||||
({ __typeof__ (a) _a = (a); \
|
({ __typeof__ (a) _a = (a); \
|
||||||
|
|
8
src/xdelta3.c
Normal file
8
src/xdelta3.c
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
//To fix compile errors with xdelta3
|
||||||
|
#define SIZEOF_SIZE_T 4
|
||||||
|
#define static_assert(e,m) /* do nothing */
|
||||||
|
#define XD3_ENCODER 0
|
||||||
|
typedef unsigned int usize_t;
|
||||||
|
typedef unsigned long long xoff_t;
|
||||||
|
|
||||||
|
#include "../lib/xdelta3/xdelta3.h"
|
Loading…
Reference in a new issue