mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-22 23:49:50 +00:00
XDelta patch support (Take 2) (#15915)
* Add xdelta in deps * Include <assert.h> in xdelta3.h - Otherwise the static_assert calls can fail * Build xdelta3 in Makefile.common * Add xdelta support to the softpatching infrastructure - The patching itself isn't fully implemented yet * Adjust how xdelta3.h checks the sizes of some types - Now checks max values instead of relying on autotools * Add some enums that were excluded by the cherry-pick * Remove stray whitespace * Adjust SIZE macros in xdelta3.h - Move them outside the XD3_USE_LARGEFILE64 block - Add more SIZE declarations - Make SIZEOF_UNSIGNED_LONG_LONG contingent on the presence of ULLONG_MAX * Reintegrate xdelta support * Enable support for xdelta's secondary compressors - Necessary for some patches * Fix some format specifiers * Remove unnecessary files from xdelta * Include xdelta3.h with a relative path * Add xdelta3 headers to HEADERS variable * Gate Xdelta support behind HAVE_XDELTA - HAVE_XDELTA is on by default - HAVE_PATCH is still required for HAVE_XDELTA to be meaningful - Support is mostly contingent on the availability of LZMA - Anything modern should be okay - Legacy platforms (e.g. DOS) may need to have Xdelta support disabled - At least until some other solution can be found * Disable HAVE_XDELTA on platforms where the build recently failed - These come from looking at the failed builds on GitHub - These are guesses, and may turn out to be wrong * Fix a potential memory leak - Whoops, looks like I need to call two cleanup functions - xd3_close_stream exists separately from xd3_free_stream * Split the --help printout for --xdelta into its own strlcat call - GCC was complaining about #ifdefs within macro arguments being non-portable * Fix some incorrect printf format specifiers * Modify Xdelta to adhere to C89 - It's mostly using RetroArch's INLINE macro instead of the inline keyword * Slight cleanups * Remove a stray comma that was hindering C89 builds * Add XDelta support to CHANGES.md * Change how the xdelta patch's name is computed - To be in line with other recent refactoring * Fix an incorrect merge - Whoops, this part was from before I figured out how to get the size of a patched file * Explain the song-and-dance behind computing a patched file's size * Define some XDelta3-related constants to 0 on 32-bit platforms * Adjust some Xdelta-related macro definitions - Exclude the encoder, since we're not making patches - Move some #defines to after inclusion of <stdint.h>, to fix undefined behavior - Remove _WIN32_WINNT overrides, since they were for code that we're not using * Fix Xdelta support * Wrap an encoder-only function in `#if XD3_ENCODER`
This commit is contained in:
parent
3e6ada7239
commit
cbf49a0b77
@ -1,4 +1,5 @@
|
||||
# Future
|
||||
- PATCHES: Add support for XDelta-formatted patches.
|
||||
|
||||
# 1.16.0
|
||||
- 3DS: Update __system_initArgv
|
||||
|
@ -251,6 +251,23 @@ OBJ += frontend/frontend_driver.o \
|
||||
ifeq ($(HAVE_PATCH), 1)
|
||||
DEFINES += -DHAVE_PATCH
|
||||
OBJ += tasks/task_patch.o
|
||||
ifeq ($(HAVE_XDELTA), 1)
|
||||
DEFINES += -DHAVE_XDELTA -DSECONDARY_DJW -DSECONDARY_LZMA -DSECONDARY_FGK
|
||||
INCLUDE_DIRS += -I$(DEPS_DIR)/xdelta3 -I$(LIBRETRO_COMM_DIR)
|
||||
LIBS += -llzma
|
||||
OBJ += $(DEPS_DIR)/xdelta3/xdelta3.o
|
||||
HEADERS += xdelta3.h \
|
||||
xdelta3-cfgs.h \
|
||||
xdelta3-fgk.h \
|
||||
xdelta3-hash.h \
|
||||
xdelta3-internal.h \
|
||||
xdelta3-list.h \
|
||||
xdelta3-lzma.h \
|
||||
xdelta3-second.h
|
||||
# These headers are added to the makefile because xdelta3 does weird things
|
||||
# with its #includes, which affects dependency tracking and project analysis
|
||||
# (e.g. for IDEs).
|
||||
endif
|
||||
endif
|
||||
|
||||
OBJ += \
|
||||
|
@ -66,6 +66,7 @@ HAVE_CHD = 0 # disabled due to static libretro-common and libchdr conflicts betw
|
||||
HAVE_STB_VORBIS = 1
|
||||
HAVE_IBXM = 1
|
||||
HAVE_CORE_INFO_CACHE = 1
|
||||
HAVE_XDELTA = 0 # disabled because <lzma.h> isn't available (or we haven't figured out how to install it)
|
||||
|
||||
HAVE_RGUI = 1
|
||||
HAVE_MATERIALUI = 0
|
||||
|
@ -105,6 +105,7 @@ HAVE_OZONE = 0
|
||||
HAVE_ZLIB = 1
|
||||
HAVE_CONFIGFILE = 1
|
||||
HAVE_PATCH = 1
|
||||
HAVE_XDELTA = 0 # Disabled until we figure out how to include <lzma.h>
|
||||
HAVE_CHEATS = 1
|
||||
HAVE_CHEEVOS = 0
|
||||
HAVE_LIBSHAKE = 0
|
||||
|
@ -129,6 +129,7 @@ HAVE_ZLIB := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_CONFIGFILE := 1
|
||||
HAVE_PATCH := 1
|
||||
HAVE_XDELTA := 0 # disabled because <lzma.h> isn't available (or we haven't figured out how to install it)
|
||||
HAVE_CHEATS := 1
|
||||
HAVE_SCREENSHOTS := 1
|
||||
HAVE_REWIND := 1
|
||||
|
@ -54,6 +54,7 @@ else
|
||||
HAVE_MENU = 1
|
||||
HAVE_CONFIGFILE = 1
|
||||
HAVE_PATCH = 1
|
||||
HAVE_PATCH = 0 # disabled because <lzma.h> isn't available (or we haven't figured out how to install it)
|
||||
HAVE_CHEATS = 1
|
||||
HAVE_RGUI = 1
|
||||
HAVE_MATERIALUI = 0
|
||||
|
@ -6,7 +6,7 @@ HAVE_THREADS ?= 1
|
||||
BIG_STACK ?= 0
|
||||
LOAD_WITHOUT_CORE_INFO ?= 0
|
||||
HAVE_STATIC_DUMMY ?= 0
|
||||
|
||||
HAVE_XDELTA ?= 1
|
||||
TARGET = retroarchpsp
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
|
@ -107,6 +107,7 @@ HAVE_OZONE = 0
|
||||
HAVE_ZLIB = 1
|
||||
HAVE_CONFIGFILE = 1
|
||||
HAVE_PATCH = 1
|
||||
HAVE_XDELTA = 0 # disabled because <lzma.h> isn't available (or we haven't figured out how to install it)
|
||||
HAVE_CHEATS = 1
|
||||
HAVE_CHEEVOS = 0
|
||||
HAVE_LIBSHAKE = 0
|
||||
|
@ -107,6 +107,7 @@ HAVE_OZONE = 0
|
||||
HAVE_ZLIB = 1
|
||||
HAVE_CONFIGFILE = 1
|
||||
HAVE_PATCH = 1
|
||||
HAVE_XDELTA = 0 # Disabled until we figure out how to include <lzma.h>
|
||||
HAVE_CHEATS = 1
|
||||
HAVE_CHEEVOS = 0
|
||||
HAVE_LIBSHAKE = 0
|
||||
|
@ -84,6 +84,7 @@ else
|
||||
HAVE_GFX_WIDGETS := 1
|
||||
HAVE_CONFIGFILE := 1
|
||||
HAVE_PATCH := 1
|
||||
HAVE_XDELTA := 1 # disabled because <lzma.h> isn't available (or we haven't figured out how to install it)
|
||||
HAVE_CHEATS := 1
|
||||
HAVE_OVERLAY := 1
|
||||
HAVE_MATERIALUI := 1
|
||||
|
@ -137,6 +137,7 @@ HAVE_ZLIB := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_CONFIGFILE := 1
|
||||
HAVE_PATCH := 1
|
||||
HAVE_XDELTA := 0 # disabled because <lzma.h> isn't available (or we haven't figured out how to install it)
|
||||
HAVE_CHEATS := 1
|
||||
HAVE_SCREENSHOTS := 1
|
||||
HAVE_REWIND := 1
|
||||
|
@ -143,6 +143,7 @@ endif
|
||||
HAVE_RBMP = 1
|
||||
HAVE_CONFIGFILE = 1
|
||||
HAVE_PATCH = 1
|
||||
HAVE_XDELTA = 0 # disabled because <lzma.h> isn't available (or we haven't figured out how to install it)
|
||||
HAVE_REWIND = 1
|
||||
HAVE_CHEATS = 1
|
||||
HAVE_MENU = 1
|
||||
|
@ -1040,7 +1040,7 @@
|
||||
#define DEFAULT_NOTIFICATION_SHOW_CHEATS_APPLIED true
|
||||
|
||||
/* Display a notification when applying an
|
||||
* IPS/BPS/UPS patch file */
|
||||
* IPS/BPS/UPS/Xdelta patch file */
|
||||
#define DEFAULT_NOTIFICATION_SHOW_PATCH_APPLIED true
|
||||
|
||||
/* Display a notification when loading an
|
||||
|
@ -2917,6 +2917,7 @@ void config_set_defaults(void *data)
|
||||
retroarch_ctl(RARCH_CTL_UNSET_UPS_PREF, NULL);
|
||||
retroarch_ctl(RARCH_CTL_UNSET_BPS_PREF, NULL);
|
||||
retroarch_ctl(RARCH_CTL_UNSET_IPS_PREF, NULL);
|
||||
retroarch_ctl(RARCH_CTL_UNSET_XDELTA_PREF, NULL);
|
||||
|
||||
*recording_st->output_dir = '\0';
|
||||
*recording_st->config_dir = '\0';
|
||||
|
176
deps/xdelta3/LICENSE
vendored
Normal file
176
deps/xdelta3/LICENSE
vendored
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
|
37
deps/xdelta3/README.md
vendored
Normal file
37
deps/xdelta3/README.md
vendored
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.
|
171
deps/xdelta3/xdelta3-cfgs.h
vendored
Normal file
171
deps/xdelta3/xdelta3-cfgs.h
vendored
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
|
1222
deps/xdelta3/xdelta3-decode.h
vendored
Normal file
1222
deps/xdelta3/xdelta3-decode.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1838
deps/xdelta3/xdelta3-djw.h
vendored
Normal file
1838
deps/xdelta3/xdelta3-djw.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
862
deps/xdelta3/xdelta3-fgk.h
vendored
Normal file
862
deps/xdelta3/xdelta3-fgk.h
vendored
Normal file
@ -0,0 +1,862 @@
|
||||
/* 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_
|
||||
|
||||
/* To include RetroArch's INLINE macro */
|
||||
#include "retro_inline.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 */
|
||||
/*********************************************************************/
|
||||
|
||||
#if XD3_ENCODER
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
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_ */
|
163
deps/xdelta3/xdelta3-hash.h
vendored
Normal file
163
deps/xdelta3/xdelta3-hash.h
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
/* 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_
|
||||
|
||||
/* To include RetroArch's INLINE macro */
|
||||
#include "retro_inline.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;
|
||||
usize_t i;
|
||||
for (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);
|
||||
int i;
|
||||
|
||||
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 (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_ */
|
387
deps/xdelta3/xdelta3-internal.h
vendored
Normal file
387
deps/xdelta3/xdelta3-internal.h
vendored
Normal file
@ -0,0 +1,387 @@
|
||||
/* 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__
|
||||
|
||||
/* To include RetroArch's INLINE macro */
|
||||
#include "retro_inline.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__ */
|
130
deps/xdelta3/xdelta3-list.h
vendored
Normal file
130
deps/xdelta3/xdelta3-list.h
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
/* 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__
|
||||
|
||||
/* To include RetroArch's INLINE macro */
|
||||
#include "retro_inline.h"
|
||||
|
||||
#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
deps/xdelta3/xdelta3-lzma.h
vendored
Normal file
195
deps/xdelta3/xdelta3-lzma.h
vendored
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_ */
|
321
deps/xdelta3/xdelta3-second.h
vendored
Normal file
321
deps/xdelta3/xdelta3-second.h
vendored
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_ */
|
4813
deps/xdelta3/xdelta3.c
vendored
Normal file
4813
deps/xdelta3/xdelta3.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1502
deps/xdelta3/xdelta3.h
vendored
Normal file
1502
deps/xdelta3/xdelta3.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -226,6 +226,12 @@ Attempts to apply a IPS patch to the current content image. No files are altered
|
||||
If this flag is not specified, RetroArch will look for a .ips file with same basename as content specified.
|
||||
Note that RetroArch cannot perform any error checking if patching was successful due to how IPS works.
|
||||
|
||||
.TP
|
||||
\fB--xdelta PATCH\fR
|
||||
Attempts to apply an Xdelta patch to the current content image. No files are altered.
|
||||
If this flag is not specified, RetroArch will look for a .xdelta file with same basename as content specified.
|
||||
Only available if RetroArch was built with Xdelta support.
|
||||
|
||||
.TP
|
||||
\fB--no-patch\fR
|
||||
Disables all kinds of content patching.
|
||||
|
@ -63,6 +63,7 @@ RETRO_BEGIN_DECLS
|
||||
#define FILE_PATH_UPS_EXTENSION ".ups"
|
||||
#define FILE_PATH_IPS_EXTENSION ".ips"
|
||||
#define FILE_PATH_BPS_EXTENSION ".bps"
|
||||
#define FILE_PATH_XDELTA_EXTENSION ".xdelta"
|
||||
#define FILE_PATH_RDB_EXTENSION ".rdb"
|
||||
#define FILE_PATH_RDB_EXTENSION_NO_DOT "rdb"
|
||||
#define FILE_PATH_ZIP_EXTENSION ".zip"
|
||||
|
@ -6,6 +6,7 @@ HAVE_CORE_INFO_CACHE=yes # Core info cache support
|
||||
HAVE_BLUETOOTH=no # Bluetooth support
|
||||
HAVE_NVDA=yes # NVDA support
|
||||
HAVE_PATCH=yes # Softpatching support (BPS/IPS/UPS)
|
||||
HAVE_XDELTA=yes # Xdelta softpatching support (requires softpatching)
|
||||
HAVE_SAPI=no # SAPI support
|
||||
HAVE_VIDEO_FILTER=yes # Video filter support
|
||||
HAVE_WINRAWINPUT=yes # Windows Raw Input support (XP and higher)
|
||||
|
55
retroarch.c
55
retroarch.c
@ -270,6 +270,7 @@ enum
|
||||
RA_OPT_APPENDCONFIG,
|
||||
RA_OPT_BPS,
|
||||
RA_OPT_IPS,
|
||||
RA_OPT_XDELTA,
|
||||
RA_OPT_NO_PATCH,
|
||||
RA_OPT_RECORDCONFIG,
|
||||
RA_OPT_SUBSYSTEM,
|
||||
@ -4605,6 +4606,11 @@ void retroarch_override_setting_set(
|
||||
case RARCH_OVERRIDE_SETTING_IPS_PREF:
|
||||
#ifdef HAVE_PATCH
|
||||
p_rarch->flags |= RARCH_FLAGS_HAS_SET_IPS_PREF;
|
||||
#endif
|
||||
break;
|
||||
case RARCH_OVERRIDE_SETTING_XDELTA_PREF:
|
||||
#if defined(HAVE_PATCH) && defined(HAVE_XDELTA)
|
||||
p_rarch->flags |= RARCH_FLAGS_HAS_SET_XDELTA_PREF;
|
||||
#endif
|
||||
break;
|
||||
case RARCH_OVERRIDE_SETTING_LOG_TO_FILE:
|
||||
@ -4682,6 +4688,11 @@ void retroarch_override_setting_unset(
|
||||
case RARCH_OVERRIDE_SETTING_IPS_PREF:
|
||||
#ifdef HAVE_PATCH
|
||||
p_rarch->flags &= ~RARCH_FLAGS_HAS_SET_IPS_PREF;
|
||||
#endif
|
||||
break;
|
||||
case RARCH_OVERRIDE_SETTING_XDELTA_PREF:
|
||||
#if defined(HAVE_PATCH) && defined(HAVE_XDELTA)
|
||||
p_rarch->flags &= ~RARCH_FLAGS_HAS_SET_XDELTA_PREF;
|
||||
#endif
|
||||
break;
|
||||
case RARCH_OVERRIDE_SETTING_LOG_TO_FILE:
|
||||
@ -4734,7 +4745,8 @@ static void global_free(struct rarch_state *p_rarch)
|
||||
p_rarch->flags &= ~(
|
||||
RARCH_FLAGS_BPS_PREF
|
||||
| RARCH_FLAGS_IPS_PREF
|
||||
| RARCH_FLAGS_UPS_PREF);
|
||||
| RARCH_FLAGS_UPS_PREF
|
||||
| RARCH_FLAGS_XDELTA_PREF);
|
||||
runloop_st->flags &= ~RUNLOOP_FLAG_PATCH_BLOCKED;
|
||||
|
||||
#endif
|
||||
@ -4759,6 +4771,7 @@ static void global_free(struct rarch_state *p_rarch)
|
||||
*runloop_st->name.ups = '\0';
|
||||
*runloop_st->name.bps = '\0';
|
||||
*runloop_st->name.ips = '\0';
|
||||
*runloop_st->name.xdelta = '\0';
|
||||
*runloop_st->name.savefile = '\0';
|
||||
*runloop_st->name.savestate = '\0';
|
||||
*runloop_st->name.replay = '\0';
|
||||
@ -5445,10 +5458,18 @@ static void retroarch_print_help(const char *arg0)
|
||||
"Specifies path for BPS patch that will be applied to content.\n"
|
||||
" --ips=FILE "
|
||||
"Specifies path for IPS patch that will be applied to content.\n"
|
||||
, sizeof(buf));
|
||||
#ifdef HAVE_XDELTA
|
||||
strlcat(buf,
|
||||
" --xdelta=FILE "
|
||||
"Specifies path for Xdelta patch that will be applied to content.\n"
|
||||
, sizeof(buf));
|
||||
#endif /* HAVE_XDELTA */
|
||||
strlcat(buf,
|
||||
" --no-patch "
|
||||
"Disables all forms of content patching.\n"
|
||||
, sizeof(buf));
|
||||
#endif
|
||||
#endif /* HAVE_PATCH */
|
||||
|
||||
#ifdef HAVE_SCREENSHOTS
|
||||
strlcat(buf,
|
||||
@ -5713,8 +5734,11 @@ static bool retroarch_parse_input_and_config(
|
||||
{ "ups", 1, NULL, 'U' },
|
||||
{ "bps", 1, NULL, RA_OPT_BPS },
|
||||
{ "ips", 1, NULL, RA_OPT_IPS },
|
||||
#ifdef HAVE_XDELTA
|
||||
{ "xdelta", 1, NULL, RA_OPT_XDELTA },
|
||||
#endif /* HAVE_XDELTA */
|
||||
{ "no-patch", 0, NULL, RA_OPT_NO_PATCH },
|
||||
#endif
|
||||
#endif /* HAVE_PATCH */
|
||||
{ "detach", 0, NULL, 'D' },
|
||||
{ "features", 0, NULL, RA_OPT_FEATURES },
|
||||
{ "subsystem", 1, NULL, RA_OPT_SUBSYSTEM },
|
||||
@ -5788,10 +5812,11 @@ static bool retroarch_parse_input_and_config(
|
||||
p_rarch->flags &= ~RARCH_FLAGS_HAS_SET_USERNAME;
|
||||
#ifdef HAVE_PATCH
|
||||
p_rarch->flags &= ~( RARCH_FLAGS_UPS_PREF | RARCH_FLAGS_IPS_PREF
|
||||
| RARCH_FLAGS_BPS_PREF);
|
||||
| RARCH_FLAGS_BPS_PREF | RARCH_FLAGS_XDELTA_PREF);
|
||||
*runloop_st->name.ups = '\0';
|
||||
*runloop_st->name.bps = '\0';
|
||||
*runloop_st->name.ips = '\0';
|
||||
*runloop_st->name.xdelta = '\0';
|
||||
#endif
|
||||
#ifdef HAVE_CONFIGFILE
|
||||
runloop_st->flags &= ~RUNLOOP_FLAG_OVERRIDES_ACTIVE;
|
||||
@ -6195,7 +6220,14 @@ static bool retroarch_parse_input_and_config(
|
||||
retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_IPS_PREF, NULL);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case RA_OPT_XDELTA:
|
||||
#if defined(HAVE_PATCH) && defined(HAVE_XDELTA)
|
||||
strlcpy(runloop_st->name.xdelta, optarg,
|
||||
sizeof(runloop_st->name.xdelta));
|
||||
p_rarch->flags |= RARCH_FLAGS_XDELTA_PREF;
|
||||
retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_XDELTA_PREF, NULL);
|
||||
#endif
|
||||
break;
|
||||
case RA_OPT_NO_PATCH:
|
||||
#ifdef HAVE_PATCH
|
||||
runloop_st->flags |= RUNLOOP_FLAG_PATCH_BLOCKED;
|
||||
@ -6842,7 +6874,12 @@ bool retroarch_ctl(enum rarch_ctl_state state, void *data)
|
||||
case RARCH_CTL_UNSET_IPS_PREF:
|
||||
p_rarch->flags &= ~RARCH_FLAGS_IPS_PREF;
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_XDELTA
|
||||
case RARCH_CTL_UNSET_XDELTA_PREF:
|
||||
p_rarch->flags &= ~RARCH_FLAGS_XDELTA_PREF;
|
||||
break;
|
||||
#endif /* HAVE_XDELTA */
|
||||
#endif /* HAVE_PATCH */
|
||||
case RARCH_CTL_IS_DUMMY_CORE:
|
||||
return runloop_st->current_core_type == CORE_TYPE_DUMMY;
|
||||
case RARCH_CTL_IS_CORE_LOADED:
|
||||
@ -7100,7 +7137,11 @@ bool retroarch_override_setting_is_set(
|
||||
return ((p_rarch->flags & RARCH_FLAGS_HAS_SET_BPS_PREF) > 0);
|
||||
case RARCH_OVERRIDE_SETTING_IPS_PREF:
|
||||
return ((p_rarch->flags & RARCH_FLAGS_HAS_SET_IPS_PREF) > 0);
|
||||
#endif
|
||||
#ifdef HAVE_XDELTA
|
||||
case RARCH_OVERRIDE_SETTING_XDELTA_PREF:
|
||||
return ((p_rarch->flags & RARCH_FLAGS_HAS_SET_XDELTA_PREF) > 0);
|
||||
#endif /* HAVE_XDELTA */
|
||||
#endif /* HAVE_PATCH */
|
||||
case RARCH_OVERRIDE_SETTING_LOG_TO_FILE:
|
||||
return ((p_rarch->flags & RARCH_FLAGS_HAS_SET_LOG_TO_FILE) > 0);
|
||||
case RARCH_OVERRIDE_SETTING_DATABASE_SCAN:
|
||||
|
@ -104,7 +104,9 @@ enum rarch_state_flags
|
||||
RARCH_FLAGS_BPS_PREF = (1 << 11),
|
||||
RARCH_FLAGS_IPS_PREF = (1 << 12),
|
||||
RARCH_FLAGS_BLOCK_CONFIG_READ = (1 << 13),
|
||||
RARCH_FLAGS_CLI_DATABASE_SCAN = (1 << 14)
|
||||
RARCH_FLAGS_CLI_DATABASE_SCAN = (1 << 14),
|
||||
RARCH_FLAGS_HAS_SET_XDELTA_PREF = (1 << 15),
|
||||
RARCH_FLAGS_XDELTA_PREF = (1 << 16)
|
||||
};
|
||||
|
||||
bool retroarch_ctl(enum rarch_ctl_state state, void *data);
|
||||
|
@ -62,6 +62,7 @@ enum rarch_ctl_state
|
||||
RARCH_CTL_UNSET_BPS_PREF,
|
||||
RARCH_CTL_UNSET_UPS_PREF,
|
||||
RARCH_CTL_UNSET_IPS_PREF,
|
||||
RARCH_CTL_UNSET_XDELTA_PREF,
|
||||
|
||||
#ifdef HAVE_CONFIGFILE
|
||||
/* Block config read */
|
||||
@ -122,6 +123,7 @@ enum rarch_override_setting
|
||||
RARCH_OVERRIDE_SETTING_UPS_PREF,
|
||||
RARCH_OVERRIDE_SETTING_BPS_PREF,
|
||||
RARCH_OVERRIDE_SETTING_IPS_PREF,
|
||||
RARCH_OVERRIDE_SETTING_XDELTA_PREF,
|
||||
RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE,
|
||||
RARCH_OVERRIDE_SETTING_LOG_TO_FILE,
|
||||
RARCH_OVERRIDE_SETTING_DATABASE_SCAN,
|
||||
|
10
runloop.c
10
runloop.c
@ -4874,6 +4874,16 @@ void runloop_path_fill_names(void)
|
||||
".ips",
|
||||
sizeof(runloop_st->name.ips) - len);
|
||||
}
|
||||
|
||||
if (string_is_empty(runloop_st->name.xdelta))
|
||||
{
|
||||
size_t len = strlcpy(runloop_st->name.xdelta,
|
||||
runloop_st->runtime_content_path_basename,
|
||||
sizeof(runloop_st->name.xdelta));
|
||||
strlcpy(runloop_st->name.xdelta + len,
|
||||
".xdelta",
|
||||
sizeof(runloop_st->name.xdelta) - len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -294,6 +294,7 @@ struct runloop
|
||||
char ups[8192];
|
||||
char bps[8192];
|
||||
char ips[8192];
|
||||
char xdelta[8192];
|
||||
char label[8192];
|
||||
} name;
|
||||
|
||||
|
@ -123,7 +123,8 @@ enum content_information_flags
|
||||
CONTENT_INFO_FLAG_IS_UPS_PREF = (1 << 5),
|
||||
CONTENT_INFO_FLAG_PATCH_IS_BLOCKED = (1 << 6),
|
||||
CONTENT_INFO_FLAG_BIOS_IS_MISSING = (1 << 7),
|
||||
CONTENT_INFO_FLAG_CHECK_FW_BEFORE_LOADING = (1 << 8)
|
||||
CONTENT_INFO_FLAG_CHECK_FW_BEFORE_LOADING = (1 << 8),
|
||||
CONTENT_INFO_FLAG_IS_XDELTA_PREF = (1 << 9)
|
||||
};
|
||||
|
||||
struct content_information_ctx
|
||||
@ -131,6 +132,7 @@ struct content_information_ctx
|
||||
char *name_ips;
|
||||
char *name_bps;
|
||||
char *name_ups;
|
||||
char *name_xdelta;
|
||||
|
||||
char *valid_extensions;
|
||||
char *directory_cache;
|
||||
@ -726,9 +728,11 @@ static bool content_file_load_into_memory(
|
||||
content_ctx->flags & CONTENT_INFO_FLAG_IS_IPS_PREF,
|
||||
content_ctx->flags & CONTENT_INFO_FLAG_IS_BPS_PREF,
|
||||
content_ctx->flags & CONTENT_INFO_FLAG_IS_UPS_PREF,
|
||||
content_ctx->flags & CONTENT_INFO_FLAG_IS_XDELTA_PREF,
|
||||
content_ctx->name_ips,
|
||||
content_ctx->name_bps,
|
||||
content_ctx->name_ups,
|
||||
content_ctx->name_xdelta,
|
||||
(uint8_t**)&content_data,
|
||||
(void*)&content_size);
|
||||
#endif
|
||||
@ -1941,6 +1945,10 @@ bool task_push_start_dummy_core(content_ctx_info_t *content_info)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_BPS_PREF;
|
||||
if (rarch_flags & RARCH_FLAGS_UPS_PREF)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_UPS_PREF;
|
||||
#ifdef HAVE_XDELTA
|
||||
if (rarch_flags & RARCH_FLAGS_XDELTA_PREF)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_XDELTA_PREF;
|
||||
#endif /* HAVE_XDELTA */
|
||||
if (runloop_st->flags & RUNLOOP_FLAG_PATCH_BLOCKED)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_PATCH_IS_BLOCKED;
|
||||
#endif
|
||||
@ -1951,6 +1959,7 @@ bool task_push_start_dummy_core(content_ctx_info_t *content_info)
|
||||
content_ctx.name_ips = NULL;
|
||||
content_ctx.name_bps = NULL;
|
||||
content_ctx.name_ups = NULL;
|
||||
content_ctx.name_xdelta = NULL;
|
||||
content_ctx.valid_extensions = NULL;
|
||||
|
||||
content_ctx.subsystem.data = NULL;
|
||||
@ -1962,6 +1971,8 @@ bool task_push_start_dummy_core(content_ctx_info_t *content_info)
|
||||
content_ctx.name_bps = strdup(runloop_st->name.bps);
|
||||
if (!string_is_empty(runloop_st->name.ups))
|
||||
content_ctx.name_ups = strdup(runloop_st->name.ups);
|
||||
if (!string_is_empty(runloop_st->name.xdelta))
|
||||
content_ctx.name_xdelta = strdup(runloop_st->name.xdelta);
|
||||
|
||||
if (!string_is_empty(path_dir_system))
|
||||
content_ctx.directory_system = strdup(path_dir_system);
|
||||
@ -1989,6 +2000,8 @@ bool task_push_start_dummy_core(content_ctx_info_t *content_info)
|
||||
free(content_ctx.name_bps);
|
||||
if (content_ctx.name_ups)
|
||||
free(content_ctx.name_ups);
|
||||
if (content_ctx.name_xdelta)
|
||||
free(content_ctx.name_xdelta);
|
||||
if (content_ctx.directory_system)
|
||||
free(content_ctx.directory_system);
|
||||
|
||||
@ -2031,6 +2044,10 @@ bool task_push_load_content_from_playlist_from_menu(
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_BPS_PREF;
|
||||
if (rarch_flags & RARCH_FLAGS_UPS_PREF)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_UPS_PREF;
|
||||
#ifdef HAVE_XDELTA
|
||||
if (rarch_flags & RARCH_FLAGS_XDELTA_PREF)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_XDELTA_PREF;
|
||||
#endif /* HAVE_XDELTA */
|
||||
if (runloop_st->flags & RUNLOOP_FLAG_PATCH_BLOCKED)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_PATCH_IS_BLOCKED;
|
||||
#endif
|
||||
@ -2041,6 +2058,7 @@ bool task_push_load_content_from_playlist_from_menu(
|
||||
content_ctx.name_ips = NULL;
|
||||
content_ctx.name_bps = NULL;
|
||||
content_ctx.name_ups = NULL;
|
||||
content_ctx.name_xdelta = NULL;
|
||||
content_ctx.valid_extensions = NULL;
|
||||
|
||||
content_ctx.subsystem.data = NULL;
|
||||
@ -2052,6 +2070,8 @@ bool task_push_load_content_from_playlist_from_menu(
|
||||
content_ctx.name_bps = strdup(runloop_st->name.bps);
|
||||
if (!string_is_empty(runloop_st->name.ups))
|
||||
content_ctx.name_ups = strdup(runloop_st->name.ups);
|
||||
if (!string_is_empty(runloop_st->name.xdelta))
|
||||
content_ctx.name_xdelta = strdup(runloop_st->name.xdelta);
|
||||
if (label)
|
||||
strlcpy(runloop_st->name.label, label, sizeof(runloop_st->name.label));
|
||||
else
|
||||
@ -2138,6 +2158,8 @@ end:
|
||||
free(content_ctx.name_bps);
|
||||
if (content_ctx.name_ups)
|
||||
free(content_ctx.name_ups);
|
||||
if (content_ctx.name_xdelta)
|
||||
free(content_ctx.name_xdelta);
|
||||
if (content_ctx.directory_system)
|
||||
free(content_ctx.directory_system);
|
||||
|
||||
@ -2171,6 +2193,10 @@ bool task_push_start_current_core(content_ctx_info_t *content_info)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_BPS_PREF;
|
||||
if (rarch_flags & RARCH_FLAGS_UPS_PREF)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_UPS_PREF;
|
||||
#ifdef HAVE_XDELTA
|
||||
if (rarch_flags & RARCH_FLAGS_XDELTA_PREF)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_XDELTA_PREF;
|
||||
#endif
|
||||
if (runloop_st->flags & RUNLOOP_FLAG_PATCH_BLOCKED)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_PATCH_IS_BLOCKED;
|
||||
}
|
||||
@ -2182,6 +2208,7 @@ bool task_push_start_current_core(content_ctx_info_t *content_info)
|
||||
content_ctx.name_ips = NULL;
|
||||
content_ctx.name_bps = NULL;
|
||||
content_ctx.name_ups = NULL;
|
||||
content_ctx.name_xdelta = NULL;
|
||||
content_ctx.valid_extensions = NULL;
|
||||
|
||||
content_ctx.subsystem.data = NULL;
|
||||
@ -2193,6 +2220,8 @@ bool task_push_start_current_core(content_ctx_info_t *content_info)
|
||||
content_ctx.name_bps = strdup(runloop_st->name.bps);
|
||||
if (!string_is_empty(runloop_st->name.ups))
|
||||
content_ctx.name_ups = strdup(runloop_st->name.ups);
|
||||
if (!string_is_empty(runloop_st->name.xdelta))
|
||||
content_ctx.name_xdelta = strdup(runloop_st->name.xdelta);
|
||||
|
||||
if (!string_is_empty(path_dir_system))
|
||||
content_ctx.directory_system = strdup(path_dir_system);
|
||||
@ -2240,6 +2269,8 @@ end:
|
||||
free(content_ctx.name_bps);
|
||||
if (content_ctx.name_ups)
|
||||
free(content_ctx.name_ups);
|
||||
if (content_ctx.name_xdelta)
|
||||
free(content_ctx.name_xdelta);
|
||||
if (content_ctx.directory_system)
|
||||
free(content_ctx.directory_system);
|
||||
|
||||
@ -2405,6 +2436,10 @@ bool task_push_load_content_with_new_core_from_menu(
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_BPS_PREF;
|
||||
if (rarch_flags & RARCH_FLAGS_UPS_PREF)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_UPS_PREF;
|
||||
#ifdef HAVE_XDELTA
|
||||
if (rarch_flags & RARCH_FLAGS_XDELTA_PREF)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_XDELTA_PREF;
|
||||
#endif
|
||||
if (runloop_st->flags & RUNLOOP_FLAG_PATCH_BLOCKED)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_PATCH_IS_BLOCKED;
|
||||
}
|
||||
@ -2416,6 +2451,7 @@ bool task_push_load_content_with_new_core_from_menu(
|
||||
content_ctx.name_ips = NULL;
|
||||
content_ctx.name_bps = NULL;
|
||||
content_ctx.name_ups = NULL;
|
||||
content_ctx.name_xdelta = NULL;
|
||||
content_ctx.valid_extensions = NULL;
|
||||
|
||||
content_ctx.subsystem.data = NULL;
|
||||
@ -2427,6 +2463,8 @@ bool task_push_load_content_with_new_core_from_menu(
|
||||
content_ctx.name_bps = strdup(runloop_st->name.bps);
|
||||
if (!string_is_empty(runloop_st->name.ups))
|
||||
content_ctx.name_ups = strdup(runloop_st->name.ups);
|
||||
if (!string_is_empty(runloop_st->name.xdelta))
|
||||
content_ctx.name_xdelta = strdup(runloop_st->name.xdelta);
|
||||
|
||||
runloop_st->name.label[0] = '\0';
|
||||
|
||||
@ -2475,6 +2513,8 @@ end:
|
||||
free(content_ctx.name_bps);
|
||||
if (content_ctx.name_ups)
|
||||
free(content_ctx.name_ups);
|
||||
if (content_ctx.name_xdelta)
|
||||
free(content_ctx.name_xdelta);
|
||||
if (content_ctx.directory_system)
|
||||
free(content_ctx.directory_system);
|
||||
|
||||
@ -2513,6 +2553,10 @@ static bool task_load_content_internal(
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_BPS_PREF;
|
||||
if (rarch_flags & RARCH_FLAGS_UPS_PREF)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_UPS_PREF;
|
||||
#ifdef HAVE_XDELTA
|
||||
if (rarch_flags & RARCH_FLAGS_XDELTA_PREF)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_XDELTA_PREF;
|
||||
#endif /* HAVE_XDELTA */
|
||||
if (runloop_st->flags & RUNLOOP_FLAG_PATCH_BLOCKED)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_PATCH_IS_BLOCKED;
|
||||
#endif
|
||||
@ -2523,6 +2567,7 @@ static bool task_load_content_internal(
|
||||
content_ctx.name_ips = NULL;
|
||||
content_ctx.name_bps = NULL;
|
||||
content_ctx.name_ups = NULL;
|
||||
content_ctx.name_xdelta = NULL;
|
||||
content_ctx.valid_extensions = NULL;
|
||||
|
||||
content_ctx.subsystem.data = NULL;
|
||||
@ -2555,6 +2600,8 @@ static bool task_load_content_internal(
|
||||
content_ctx.name_bps = strdup(runloop_st->name.bps);
|
||||
if (!string_is_empty(runloop_st->name.ups))
|
||||
content_ctx.name_ups = strdup(runloop_st->name.ups);
|
||||
if (!string_is_empty(runloop_st->name.xdelta))
|
||||
content_ctx.name_xdelta = strdup(runloop_st->name.xdelta);
|
||||
|
||||
if (!string_is_empty(path_dir_system))
|
||||
content_ctx.directory_system = strdup(path_dir_system);
|
||||
@ -2587,6 +2634,8 @@ end:
|
||||
free(content_ctx.name_bps);
|
||||
if (content_ctx.name_ups)
|
||||
free(content_ctx.name_ups);
|
||||
if (content_ctx.name_xdelta)
|
||||
free(content_ctx.name_xdelta);
|
||||
if (content_ctx.directory_system)
|
||||
free(content_ctx.directory_system);
|
||||
if (content_ctx.directory_cache)
|
||||
@ -3018,14 +3067,19 @@ bool content_init(void)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_BPS_PREF;
|
||||
if (rarch_flags & RARCH_FLAGS_UPS_PREF)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_UPS_PREF;
|
||||
#ifdef HAVE_XDELTA
|
||||
if (rarch_flags & RARCH_FLAGS_XDELTA_PREF)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_IS_XDELTA_PREF;
|
||||
#endif /* HAVE_XDELTA */
|
||||
if (runloop_st->flags & RUNLOOP_FLAG_PATCH_BLOCKED)
|
||||
content_ctx.flags |= CONTENT_INFO_FLAG_PATCH_IS_BLOCKED;
|
||||
#endif
|
||||
#endif /* HAVE_PATCH */
|
||||
content_ctx.directory_system = NULL;
|
||||
content_ctx.directory_cache = NULL;
|
||||
content_ctx.name_ips = NULL;
|
||||
content_ctx.name_bps = NULL;
|
||||
content_ctx.name_ups = NULL;
|
||||
content_ctx.name_xdelta = NULL;
|
||||
content_ctx.valid_extensions = NULL;
|
||||
|
||||
content_ctx.subsystem.data = NULL;
|
||||
@ -3037,6 +3091,8 @@ bool content_init(void)
|
||||
content_ctx.name_bps = strdup(runloop_st->name.bps);
|
||||
if (!string_is_empty(runloop_st->name.ups))
|
||||
content_ctx.name_ups = strdup(runloop_st->name.ups);
|
||||
if (!string_is_empty(runloop_st->name.xdelta))
|
||||
content_ctx.name_xdelta = strdup(runloop_st->name.xdelta);
|
||||
|
||||
if (sys_info)
|
||||
{
|
||||
@ -3080,6 +3136,8 @@ bool content_init(void)
|
||||
free(content_ctx.name_bps);
|
||||
if (content_ctx.name_ups)
|
||||
free(content_ctx.name_ups);
|
||||
if (content_ctx.name_xdelta)
|
||||
free(content_ctx.name_xdelta);
|
||||
if (content_ctx.directory_system)
|
||||
free(content_ctx.directory_system);
|
||||
if (content_ctx.directory_cache)
|
||||
|
@ -36,6 +36,10 @@
|
||||
#include "../verbosity.h"
|
||||
#include "../configuration.h"
|
||||
|
||||
#if HAVE_XDELTA
|
||||
#include "../deps/xdelta3/xdelta3.h"
|
||||
#endif
|
||||
|
||||
enum bps_mode
|
||||
{
|
||||
SOURCE_READ = 0,
|
||||
@ -57,7 +61,8 @@ enum patch_error
|
||||
PATCH_TARGET_INVALID,
|
||||
PATCH_SOURCE_CHECKSUM_INVALID,
|
||||
PATCH_TARGET_CHECKSUM_INVALID,
|
||||
PATCH_PATCH_CHECKSUM_INVALID
|
||||
PATCH_PATCH_CHECKSUM_INVALID,
|
||||
PATCH_PATCH_UNSUPPORTED
|
||||
};
|
||||
|
||||
struct bps_data
|
||||
@ -611,6 +616,105 @@ static enum patch_error ips_apply_patch(
|
||||
return PATCH_PATCH_INVALID;
|
||||
}
|
||||
|
||||
static enum patch_error xdelta_apply_patch(
|
||||
const uint8_t *patchdata, uint64_t patchlen,
|
||||
const uint8_t *sourcedata, uint64_t sourcelength,
|
||||
uint8_t **targetdata, uint64_t *targetlength)
|
||||
{
|
||||
#if defined(HAVE_PATCH) && defined(HAVE_XDELTA)
|
||||
int ret;
|
||||
enum patch_error error_patch = PATCH_SUCCESS;
|
||||
xd3_stream stream;
|
||||
xd3_config config;
|
||||
xd3_source source;
|
||||
|
||||
/* Validate the magic number, as given by RFC 3284 section 4.1 */
|
||||
if (patchlen < 8 ||
|
||||
patchdata[0] != 0xD6 ||
|
||||
patchdata[1] != 0xC3 ||
|
||||
patchdata[2] != 0xC4 ||
|
||||
patchdata[3] != 0x00)
|
||||
return PATCH_PATCH_INVALID_HEADER;
|
||||
|
||||
xd3_init_config(&config, XD3_SKIP_EMIT);
|
||||
/* The first pass is just to compute the buffer size,
|
||||
* no need to emit patched data yet */
|
||||
|
||||
if (xd3_config_stream(&stream, &config) != 0)
|
||||
return PATCH_UNKNOWN;
|
||||
|
||||
memset(&source, 0, sizeof(source));
|
||||
source.blksize = sourcelength;
|
||||
source.onblk = sourcelength;
|
||||
source.curblk = sourcedata;
|
||||
source.curblkno = 0;
|
||||
xd3_set_source_and_size(&stream, &source, sourcelength);
|
||||
|
||||
do
|
||||
{ /* Make a first pass over the patch, to compute the target size.
|
||||
* XDelta3 doesn't store the target size in the patch file,
|
||||
* so we have to either compute it ourselves
|
||||
* or keep reallocating a buffer as we go.
|
||||
* I went with the former because it's simpler and fails sooner.
|
||||
*/
|
||||
switch (ret = xd3_decode_input(&stream))
|
||||
{ /* xd3 works like a zlib-styled state machine (stream is the machine) */
|
||||
case XD3_INPUT: /* When starting the first pass, provide the input */
|
||||
xd3_avail_input(&stream, patchdata, patchlen);
|
||||
RARCH_DBG("[xdelta] Provided %lu bytes of input to xd3_stream\n", patchlen);
|
||||
break;
|
||||
case XD3_GOTHEADER:
|
||||
case XD3_WINSTART:
|
||||
*targetlength += stream.winsize;
|
||||
RARCH_DBG("[xdelta] Discovered a window of %lu bytes (target filesize is %lu bytes)\n", stream.winsize, *targetlength);
|
||||
/* xdelta updates the active stream window in the GOTHEADER and WINSTART states */
|
||||
break;
|
||||
case XD3_OUTPUT:
|
||||
xd3_consume_output(&stream); /* Need to call this after every output */
|
||||
break;
|
||||
case XD3_INVALID_INPUT:
|
||||
error_patch = PATCH_PATCH_INVALID;
|
||||
RARCH_ERR("[xdelta] Invalid input in xd3_stream (%s)\n", xd3_errstring(&stream));
|
||||
goto cleanup_stream;
|
||||
case XD3_INTERNAL:
|
||||
error_patch = PATCH_UNKNOWN;
|
||||
RARCH_ERR("[xdelta] Internal error in xd3_stream (%s)\n", xd3_errstring(&stream));
|
||||
goto cleanup_stream;
|
||||
case XD3_WINFINISH:
|
||||
RARCH_DBG("[xdelta] Finished processing window #%d\n", stream.current_window);
|
||||
break;
|
||||
default:
|
||||
RARCH_DBG("[xdelta] xd3_decode_input returned %ld (%s; %s)\n", ret, xd3_strerror(ret), stream.msg);
|
||||
}
|
||||
} while (stream.avail_in);
|
||||
|
||||
*targetdata = malloc(*targetlength);
|
||||
switch (ret = xd3_decode_memory(
|
||||
patchdata, patchlen,
|
||||
sourcedata, sourcelength,
|
||||
*targetdata, targetlength, *targetlength, 0))
|
||||
{
|
||||
case 0: /* Success */
|
||||
break;
|
||||
case ENOSPC:
|
||||
error_patch = PATCH_TARGET_ALLOC_FAILED;
|
||||
free(*targetdata);
|
||||
goto cleanup_stream;
|
||||
default:
|
||||
error_patch = PATCH_UNKNOWN;
|
||||
free(*targetdata);
|
||||
goto cleanup_stream;
|
||||
}
|
||||
|
||||
cleanup_stream:
|
||||
xd3_close_stream(&stream);
|
||||
xd3_free_stream(&stream);
|
||||
return error_patch;
|
||||
#else /* HAVE_PATCH is defined and HAVE_XDELTA is defined */
|
||||
return PATCH_PATCH_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool apply_patch_content(uint8_t **buf,
|
||||
ssize_t *size, const char *patch_desc, const char *patch_path,
|
||||
patch_func_t func, void *patch_data, int64_t patch_size)
|
||||
@ -738,6 +842,34 @@ static bool try_ips_patch(bool allow_ips,
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool try_xdelta_patch(bool allow_xdelta,
|
||||
const char *name_xdelta, uint8_t **buf, ssize_t *size)
|
||||
{
|
||||
#if defined(HAVE_PATCH) && defined(HAVE_XDELTA)
|
||||
if ( allow_xdelta
|
||||
&& !string_is_empty(name_xdelta)
|
||||
&& path_is_valid(name_xdelta)
|
||||
)
|
||||
{
|
||||
int64_t patch_size;
|
||||
bool ret = false;
|
||||
void *patch_data = NULL;
|
||||
|
||||
if (!filestream_read_file(name_xdelta, &patch_data, &patch_size))
|
||||
return false;
|
||||
|
||||
if (patch_size >= 0)
|
||||
ret = apply_patch_content(buf, size, "Xdelta", name_xdelta,
|
||||
xdelta_apply_patch, patch_data, patch_size);
|
||||
|
||||
if (patch_data)
|
||||
free(patch_data);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* patch_content:
|
||||
* @buf : buffer of the content file.
|
||||
@ -750,20 +882,24 @@ bool patch_content(
|
||||
bool is_ips_pref,
|
||||
bool is_bps_pref,
|
||||
bool is_ups_pref,
|
||||
bool is_xdelta_pref,
|
||||
const char *name_ips,
|
||||
const char *name_bps,
|
||||
const char *name_ups,
|
||||
const char *name_xdelta,
|
||||
uint8_t **buf,
|
||||
void *data)
|
||||
{
|
||||
ssize_t *size = (ssize_t*)data;
|
||||
bool allow_ups = !is_bps_pref && !is_ips_pref;
|
||||
bool allow_ips = !is_ups_pref && !is_bps_pref;
|
||||
bool allow_bps = !is_ups_pref && !is_ips_pref;
|
||||
bool allow_ups = !is_bps_pref && !is_ips_pref && !is_xdelta_pref;
|
||||
bool allow_ips = !is_ups_pref && !is_bps_pref && !is_xdelta_pref;
|
||||
bool allow_bps = !is_ups_pref && !is_ips_pref && !is_xdelta_pref;
|
||||
bool allow_xdelta = !is_bps_pref && !is_ups_pref && !is_ips_pref;
|
||||
|
||||
if ( (unsigned)is_ips_pref
|
||||
+ (unsigned)is_bps_pref
|
||||
+ (unsigned)is_ups_pref > 1)
|
||||
+ (unsigned)is_ups_pref
|
||||
+ (unsigned)is_xdelta_pref > 1)
|
||||
{
|
||||
RARCH_WARN("%s\n",
|
||||
msg_hash_to_str(MSG_SEVERAL_PATCHES_ARE_EXPLICITLY_DEFINED));
|
||||
@ -773,16 +909,19 @@ bool patch_content(
|
||||
/* Attempt to apply first (non-indexed) patch */
|
||||
if ( try_ips_patch(allow_ips, name_ips, buf, size)
|
||||
|| try_bps_patch(allow_bps, name_bps, buf, size)
|
||||
|| try_ups_patch(allow_ups, name_ups, buf, size))
|
||||
|| try_ups_patch(allow_ups, name_ups, buf, size)
|
||||
|| try_xdelta_patch(allow_xdelta, name_xdelta, buf, size))
|
||||
{
|
||||
/* A patch has been found. Now attempt to apply
|
||||
* any additional 'indexed' patch files */
|
||||
size_t name_ips_len = strlen(name_ips);
|
||||
size_t name_bps_len = strlen(name_bps);
|
||||
size_t name_ups_len = strlen(name_ups);
|
||||
size_t name_xdelta_len = strlen(name_xdelta);
|
||||
char *name_ips_indexed = (char*)malloc((name_ips_len + 2) * sizeof(char));
|
||||
char *name_bps_indexed = (char*)malloc((name_bps_len + 2) * sizeof(char));
|
||||
char *name_ups_indexed = (char*)malloc((name_ups_len + 2) * sizeof(char));
|
||||
char *name_xdelta_indexed = (char*)malloc((name_xdelta_len + 2) * sizeof(char));
|
||||
/* First patch already applied -> index
|
||||
* for subsequent patches starts at 1 */
|
||||
size_t patch_index = 1;
|
||||
@ -790,12 +929,14 @@ bool patch_content(
|
||||
strlcpy(name_ips_indexed, name_ips, (name_ips_len + 1) * sizeof(char));
|
||||
strlcpy(name_bps_indexed, name_bps, (name_bps_len + 1) * sizeof(char));
|
||||
strlcpy(name_ups_indexed, name_ups, (name_ups_len + 1) * sizeof(char));
|
||||
strlcpy(name_xdelta_indexed, name_xdelta, (name_xdelta_len + 1) * sizeof(char));
|
||||
|
||||
/* Ensure that we NUL terminate *after* the
|
||||
* index character */
|
||||
name_ips_indexed[name_ips_len + 1] = '\0';
|
||||
name_bps_indexed[name_bps_len + 1] = '\0';
|
||||
name_ups_indexed[name_ups_len + 1] = '\0';
|
||||
name_xdelta_indexed[name_xdelta_len + 1] = '\0';
|
||||
|
||||
/* try to patch "*.ipsX" */
|
||||
while (patch_index < 10)
|
||||
@ -815,10 +956,12 @@ bool patch_content(
|
||||
name_ips_indexed[name_ips_len] = index_char;
|
||||
name_bps_indexed[name_bps_len] = index_char;
|
||||
name_ups_indexed[name_ups_len] = index_char;
|
||||
name_xdelta_indexed[name_xdelta_len] = index_char;
|
||||
|
||||
if ( !try_ips_patch(allow_ips, name_ips_indexed, buf, size)
|
||||
&& !try_bps_patch(allow_bps, name_bps_indexed, buf, size)
|
||||
&& !try_ups_patch(allow_ups, name_ups_indexed, buf, size))
|
||||
&& !try_ups_patch(allow_ups, name_ups_indexed, buf, size)
|
||||
&& !try_xdelta_patch(allow_xdelta, name_xdelta_indexed, buf, size))
|
||||
break;
|
||||
|
||||
patch_index++;
|
||||
@ -827,6 +970,7 @@ bool patch_content(
|
||||
free(name_ips_indexed);
|
||||
free(name_bps_indexed);
|
||||
free(name_ups_indexed);
|
||||
free(name_xdelta_indexed);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -240,9 +240,11 @@ bool patch_content(
|
||||
bool is_ips_pref,
|
||||
bool is_bps_pref,
|
||||
bool is_ups_pref,
|
||||
bool is_xdelta_pref,
|
||||
const char *name_ips,
|
||||
const char *name_bps,
|
||||
const char *name_ups,
|
||||
const char *name_xdelta,
|
||||
uint8_t **buf,
|
||||
void *data);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user