mirror of
https://github.com/libretro/RetroArch
synced 2025-02-06 00:39:53 +00:00
cbf49a0b77
* 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`
196 lines
4.3 KiB
C
196 lines
4.3 KiB
C
/* 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_ */
|